initial import
[vuplus_webkit] / Source / WebCore / rendering / RenderTextControlSingleLine.cpp
1 /**
2  * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
3  *           (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 
4  * Copyright (C) 2010 Google Inc. All rights reserved.
5  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "RenderTextControlSingleLine.h"
26
27 #include "CSSFontSelector.h"
28 #include "CSSStyleSelector.h"
29 #include "Chrome.h"
30 #include "Frame.h"
31 #include "FrameSelection.h"
32 #include "FrameView.h"
33 #include "HTMLInputElement.h"
34 #include "HTMLNames.h"
35 #include "HitTestResult.h"
36 #include "LocalizedStrings.h"
37 #include "Page.h"
38 #include "PlatformKeyboardEvent.h"
39 #include "RenderLayer.h"
40 #include "RenderScrollbar.h"
41 #include "RenderTheme.h"
42 #include "SearchPopupMenu.h"
43 #include "Settings.h"
44 #include "SimpleFontData.h"
45 #include "TextControlInnerElements.h"
46
47 using namespace std;
48
49 namespace WebCore {
50
51 using namespace HTMLNames;
52
53 VisiblePosition RenderTextControlInnerBlock::positionForPoint(const LayoutPoint& point)
54 {
55     LayoutPoint contentsPoint(point);
56
57     // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that
58     // into account here.
59     if (m_multiLine) {
60         RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer());
61         if (renderer->hasOverflowClip())
62             contentsPoint += renderer->layer()->scrolledContentOffset();
63     }
64
65     return RenderBlock::positionForPoint(contentsPoint);
66 }
67
68 // ----------------------------
69
70 RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node)
71     : RenderTextControl(node)
72     , m_searchPopupIsVisible(false)
73     , m_shouldDrawCapsLockIndicator(false)
74     , m_desiredInnerTextHeight(-1)
75     , m_searchPopup(0)
76 {
77     ASSERT(node->isHTMLElement());
78     ASSERT(node->toInputElement());
79 }
80
81 RenderTextControlSingleLine::~RenderTextControlSingleLine()
82 {
83     if (m_searchPopup) {
84         m_searchPopup->popupMenu()->disconnectClient();
85         m_searchPopup = 0;
86     }
87 }
88
89 inline HTMLElement* RenderTextControlSingleLine::containerElement() const
90 {
91     return inputElement()->containerElement();
92 }
93
94 inline HTMLElement* RenderTextControlSingleLine::innerBlockElement() const
95 {
96     return inputElement()->innerBlockElement();
97 }
98
99 inline HTMLElement* RenderTextControlSingleLine::innerSpinButtonElement() const
100 {
101     return inputElement()->innerSpinButtonElement();
102 }
103
104 inline HTMLElement* RenderTextControlSingleLine::resultsButtonElement() const
105 {
106     return inputElement()->resultsButtonElement();
107 }
108
109 inline HTMLElement* RenderTextControlSingleLine::cancelButtonElement() const
110 {
111     return inputElement()->cancelButtonElement();
112 }
113
114 RenderStyle* RenderTextControlSingleLine::textBaseStyle() const
115 {
116     HTMLElement* innerBlock = innerBlockElement();
117     return innerBlock ? innerBlock->renderer()->style() : style();
118 }
119
120 void RenderTextControlSingleLine::addSearchResult()
121 {
122     HTMLInputElement* input = inputElement();
123     if (input->maxResults() <= 0)
124         return;
125
126     String value = input->value();
127     if (value.isEmpty())
128         return;
129
130     Settings* settings = document()->settings();
131     if (!settings || settings->privateBrowsingEnabled())
132         return;
133
134     int size = static_cast<int>(m_recentSearches.size());
135     for (int i = size - 1; i >= 0; --i) {
136         if (m_recentSearches[i] == value)
137             m_recentSearches.remove(i);
138     }
139
140     m_recentSearches.insert(0, value);
141     while (static_cast<int>(m_recentSearches.size()) > input->maxResults())
142         m_recentSearches.removeLast();
143
144     const AtomicString& name = autosaveName();
145     if (!m_searchPopup)
146         m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
147
148     m_searchPopup->saveRecentSearches(name, m_recentSearches);
149 }
150
151 void RenderTextControlSingleLine::showPopup()
152 {
153     if (m_searchPopupIsVisible)
154         return;
155
156     if (!m_searchPopup)
157         m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
158
159     if (!m_searchPopup->enabled())
160         return;
161
162     m_searchPopupIsVisible = true;
163
164     const AtomicString& name = autosaveName();
165     m_searchPopup->loadRecentSearches(name, m_recentSearches);
166
167     // Trim the recent searches list if the maximum size has changed since we last saved.
168     HTMLInputElement* input = inputElement();
169     if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) {
170         do {
171             m_recentSearches.removeLast();
172         } while (static_cast<int>(m_recentSearches.size()) > input->maxResults());
173
174         m_searchPopup->saveRecentSearches(name, m_recentSearches);
175     }
176
177     m_searchPopup->popupMenu()->show(absoluteBoundingBoxRect(true), document()->view(), -1);
178 }
179
180 void RenderTextControlSingleLine::hidePopup()
181 {
182     if (m_searchPopup)
183         m_searchPopup->popupMenu()->hide();
184 }
185
186 void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
187 {
188     RenderTextControl::paint(paintInfo, paintOffset);
189
190     if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
191         LayoutRect contentsRect = contentBoxRect();
192
193         // Center vertically like the text.
194         contentsRect.setY((height() - contentsRect.height()) / 2);
195
196         // Convert the rect into the coords used for painting the content
197         contentsRect.moveBy(paintOffset + location());
198         theme()->paintCapsLockIndicator(this, paintInfo, contentsRect);
199     }
200 }
201
202 void RenderTextControlSingleLine::layout()
203 {
204     // FIXME: We should remove the height-related hacks in layout() and
205     // styleDidChange(). We need them because
206     // - Center the inner elements vertically if the input height is taller than
207     //   the intrinsic height of the inner elements.
208     // - Shrink the inner elment heights if the input height is samller than the
209     //   intrinsic heights of the inner elements.
210
211     // We don't honor paddings and borders for textfields without decorations
212     // and type=search if the text height is taller than the contentHeight()
213     // because of compability.
214
215     LayoutUnit oldHeight = height();
216     computeLogicalHeight();
217
218     LayoutUnit oldWidth = width();
219     computeLogicalWidth();
220
221     bool relayoutChildren = oldHeight != height() || oldWidth != width();
222
223     RenderBox* innerTextRenderer = innerTextElement()->renderBox();
224     ASSERT(innerTextRenderer);
225     RenderBox* innerBlockRenderer = innerBlockElement() ? innerBlockElement()->renderBox() : 0;
226     HTMLElement* container = containerElement();
227     RenderBox* containerRenderer = container ? container->renderBox() : 0;
228
229     // Set the text block height
230     LayoutUnit desiredHeight = textBlockHeight();
231     LayoutUnit currentHeight = innerTextRenderer->height();
232
233     LayoutUnit heightLimit = (inputElement()->isSearchField() || !container) ? height() : contentHeight();
234     if (currentHeight > heightLimit) {
235         if (desiredHeight != currentHeight)
236             relayoutChildren = true;
237         innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed));
238         m_desiredInnerTextHeight = desiredHeight;
239         if (innerBlockRenderer)
240             innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed));
241     }
242     // The container might be taller because of decoration elements.
243     if (containerRenderer) {
244         containerRenderer->layoutIfNeeded();
245         LayoutUnit containerHeight = containerRenderer->height();
246         if (containerHeight > heightLimit) {
247             containerRenderer->style()->setHeight(Length(heightLimit, Fixed));
248             relayoutChildren = true;
249         } else if (containerRenderer->height() < contentHeight()) {
250             containerRenderer->style()->setHeight(Length(contentHeight(), Fixed));
251             relayoutChildren = true;
252         }
253     }
254
255     RenderBlock::layoutBlock(relayoutChildren);
256
257     // Center the child block vertically
258     currentHeight = innerTextRenderer->height();
259     if (!container && currentHeight != contentHeight()) {
260         LayoutUnit heightDiff = currentHeight - contentHeight();
261         innerTextRenderer->setY(innerTextRenderer->y() - (heightDiff / 2 + layoutMod(heightDiff, 2)));
262     } else if (inputElement()->isSearchField() && containerRenderer && containerRenderer->height() > contentHeight()) {
263         // A quirk for find-in-page box on Safari Windows.
264         // http://webkit.org/b/63157
265         LayoutUnit heightDiff = containerRenderer->height() - contentHeight();
266         containerRenderer->setY(containerRenderer->y() - (heightDiff / 2 + layoutMod(heightDiff, 2)));
267     }
268
269     // Ignores the paddings for the inner spin button.
270     if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) {
271         RenderBox* parentBox = innerSpinBox->parentBox();
272         if (containerRenderer && !containerRenderer->style()->isLeftToRightDirection())
273             innerSpinBox->setLocation(LayoutPoint(-paddingLeft(), -paddingTop()));
274         else
275             innerSpinBox->setLocation(LayoutPoint(parentBox->width() - innerSpinBox->width() + paddingRight(), -paddingTop()));
276         innerSpinBox->setHeight(height() - borderTop() - borderBottom());
277     }
278
279     HTMLElement* placeholderElement = inputElement()->placeholderElement();
280     if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) {
281         placeholderBox->style()->setWidth(Length(innerTextRenderer->width() - placeholderBox->borderAndPaddingWidth(), Fixed));
282         placeholderBox->style()->setHeight(Length(innerTextRenderer->height() - placeholderBox->borderAndPaddingHeight(), Fixed));
283         placeholderBox->layoutIfNeeded();
284         LayoutPoint textOffset = innerTextRenderer->location();
285         if (innerBlockElement() && innerBlockElement()->renderBox())
286             textOffset += toLayoutSize(innerBlockElement()->renderBox()->location());
287         if (containerRenderer)
288             textOffset += toLayoutSize(containerRenderer->location());
289         placeholderBox->setLocation(textOffset);
290     }
291 }
292
293 bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
294 {
295     if (!RenderTextControl::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, hitTestAction))
296         return false;
297
298     // Say that we hit the inner text element if
299     //  - we hit a node inside the inner text element,
300     //  - we hit the <input> element (e.g. we're over the border or padding), or
301     //  - we hit regions not in any decoration buttons.
302     HTMLElement* container = containerElement();
303     if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node() || (container && container == result.innerNode())) {
304         LayoutPoint pointInParent = pointInContainer;
305         if (container && innerBlockElement()) {
306             if (innerBlockElement()->renderBox())
307                 pointInParent -= toLayoutSize(innerBlockElement()->renderBox()->location());
308             if (container->renderBox())
309                 pointInParent -= toLayoutSize(container->renderBox()->location());
310         }
311         hitInnerTextElement(result, pointInParent, accumulatedOffset);
312     }
313     return true;
314 }
315
316 void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
317 {
318     m_desiredInnerTextHeight = -1;
319     RenderTextControl::styleDidChange(diff, oldStyle);
320
321     // We may have set the width and the height in the old style in layout().
322     // Reset them now to avoid getting a spurious layout hint.
323     HTMLElement* innerBlock = innerBlockElement();
324     if (RenderObject* innerBlockRenderer = innerBlock ? innerBlock->renderer() : 0) {
325         innerBlockRenderer->style()->setHeight(Length());
326         innerBlockRenderer->style()->setWidth(Length());
327     }
328     HTMLElement* container = containerElement();
329     if (RenderObject* containerRenderer = container ? container->renderer() : 0) {
330         containerRenderer->style()->setHeight(Length());
331         containerRenderer->style()->setWidth(Length());
332     }
333     setHasOverflowClip(false);
334 }
335
336 void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
337 {
338     if (!node() || !document())
339         return;
340
341     // Only draw the caps lock indicator if these things are true:
342     // 1) The field is a password field
343     // 2) The frame is active
344     // 3) The element is focused
345     // 4) The caps lock is on
346     bool shouldDrawCapsLockIndicator = false;
347
348     if (Frame* frame = document()->frame())
349         shouldDrawCapsLockIndicator = inputElement()->isPasswordField()
350                                       && frame->selection()->isFocusedAndActive()
351                                       && document()->focusedNode() == node()
352                                       && PlatformKeyboardEvent::currentCapsLockState();
353
354     if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
355         m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
356         repaint();
357     }
358 }
359
360 #if ENABLE(INPUT_SPEECH)
361 HTMLElement* RenderTextControlSingleLine::speechButtonElement() const
362 {
363     return inputElement()->speechButtonElement();
364 }
365 #endif
366
367 bool RenderTextControlSingleLine::hasControlClip() const
368 {
369     // Apply control clip for text fields with decorations.
370     return !!containerElement();
371 }
372
373 LayoutRect RenderTextControlSingleLine::controlClipRect(const LayoutPoint& additionalOffset) const
374 {
375     ASSERT(hasControlClip());
376     LayoutRect clipRect = LayoutRect(containerElement()->renderBox()->frameRect());
377     clipRect.moveBy(additionalOffset);
378     return clipRect;
379 }
380
381 float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family)
382 {
383     // Since Lucida Grande is the default font, we want this to match the width
384     // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
385     // IE for some encodings (in IE, the default font is encoding specific).
386     // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg.
387     if (family == AtomicString("Lucida Grande"))
388         return scaleEmToUnits(901);
389
390     return RenderTextControl::getAvgCharWidth(family);
391 }
392
393 LayoutUnit RenderTextControlSingleLine::preferredContentWidth(float charWidth) const
394 {
395     int factor;
396     bool includesDecoration = inputElement()->sizeShouldIncludeDecoration(factor);
397     if (factor <= 0)
398         factor = 20;
399
400     LayoutUnit result = static_cast<LayoutUnit>(ceiledLayoutUnit(charWidth * factor));
401
402     float maxCharWidth = 0.f;
403     AtomicString family = style()->font().family().family();
404     // Since Lucida Grande is the default font, we want this to match the width
405     // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
406     // IE for some encodings (in IE, the default font is encoding specific).
407     // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg.
408     if (family == AtomicString("Lucida Grande"))
409         maxCharWidth = scaleEmToUnits(4027);
410     else if (hasValidAvgCharWidth(family))
411         maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth());
412
413     // For text inputs, IE adds some extra width.
414     if (maxCharWidth > 0.f)
415         result += maxCharWidth - charWidth;
416
417     HTMLElement* resultsButton = resultsButtonElement();
418     if (RenderBox* resultsRenderer = resultsButton ? resultsButton->renderBox() : 0)
419         result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() +
420                   resultsRenderer->paddingLeft() + resultsRenderer->paddingRight();
421
422     HTMLElement* cancelButton = cancelButtonElement();
423     if (RenderBox* cancelRenderer = cancelButton ? cancelButton->renderBox() : 0)
424         result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() +
425                   cancelRenderer->paddingLeft() + cancelRenderer->paddingRight();
426
427     if (includesDecoration) {
428         HTMLElement* spinButton = innerSpinButtonElement();
429         if (RenderBox* spinRenderer = spinButton ? spinButton->renderBox() : 0) {
430             result += spinRenderer->borderLeft() + spinRenderer->borderRight() +
431                   spinRenderer->paddingLeft() + spinRenderer->paddingRight();
432             // Since the width of spinRenderer is not calculated yet, spinRenderer->width() returns 0.
433             // So computedStyle()->width() is used instead.
434             result += spinButton->computedStyle()->width().value();
435         }
436     }
437
438 #if ENABLE(INPUT_SPEECH)
439     HTMLElement* speechButton = speechButtonElement();
440     if (RenderBox* speechRenderer = speechButton ? speechButton->renderBox() : 0) {
441         result += speechRenderer->borderLeft() + speechRenderer->borderRight() +
442                   speechRenderer->paddingLeft() + speechRenderer->paddingRight();
443     }
444 #endif
445     return result;
446 }
447
448 void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(LayoutUnit lineHeight)
449 {
450     HTMLElement* resultsButton = resultsButtonElement();
451     if (RenderBox* resultsRenderer = resultsButton ? resultsButton->renderBox() : 0) {
452         resultsRenderer->computeLogicalHeight();
453         setHeight(max(height(),
454                   resultsRenderer->borderTop() + resultsRenderer->borderBottom() +
455                   resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() +
456                   resultsRenderer->marginTop() + resultsRenderer->marginBottom()));
457         lineHeight = max(lineHeight, resultsRenderer->height());
458     }
459     HTMLElement* cancelButton = cancelButtonElement();
460     if (RenderBox* cancelRenderer = cancelButton ? cancelButton->renderBox() : 0) {
461         cancelRenderer->computeLogicalHeight();
462         setHeight(max(height(),
463                   cancelRenderer->borderTop() + cancelRenderer->borderBottom() +
464                   cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() +
465                   cancelRenderer->marginTop() + cancelRenderer->marginBottom()));
466         lineHeight = max(lineHeight, cancelRenderer->height());
467     }
468
469     setHeight(height() + lineHeight);
470 }
471
472 void RenderTextControlSingleLine::updateFromElement()
473 {
474     RenderTextControl::updateFromElement();
475
476     if (cancelButtonElement())
477         updateCancelButtonVisibility();
478
479     if (m_searchPopupIsVisible)
480         m_searchPopup->popupMenu()->updateFromElement();
481 }
482
483 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
484 {
485     RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();   
486     textBlockStyle->inheritFrom(startStyle);
487     adjustInnerTextStyle(startStyle, textBlockStyle.get());
488
489     textBlockStyle->setWhiteSpace(PRE);
490     textBlockStyle->setWordWrap(NormalWordWrap);
491     textBlockStyle->setOverflowX(OHIDDEN);
492     textBlockStyle->setOverflowY(OHIDDEN);
493
494     if (m_desiredInnerTextHeight >= 0)
495         textBlockStyle->setHeight(Length(m_desiredInnerTextHeight, Fixed));
496     // Do not allow line-height to be smaller than our default.
497     if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
498         textBlockStyle->setLineHeight(Length(-100.0f, Percent));
499
500     textBlockStyle->setDisplay(BLOCK);
501
502     // We're adding one extra pixel of padding to match WinIE.
503     textBlockStyle->setPaddingLeft(Length(1, Fixed));
504     textBlockStyle->setPaddingRight(Length(1, Fixed));
505
506     return textBlockStyle.release();
507 }
508
509 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
510 {
511     RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
512     innerBlockStyle->inheritFrom(startStyle);
513
514     innerBlockStyle->setBoxFlex(1);
515     innerBlockStyle->setDisplay(BLOCK);
516     innerBlockStyle->setDirection(LTR);
517
518     // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable.
519     innerBlockStyle->setUserModify(READ_ONLY);
520
521     return innerBlockStyle.release();
522 }
523
524 void RenderTextControlSingleLine::updateCancelButtonVisibility() const
525 {
526     RenderObject* cancelButtonRenderer = cancelButtonElement()->renderer();
527     if (!cancelButtonRenderer)
528         return;
529
530     const RenderStyle* curStyle = cancelButtonRenderer->style();
531     EVisibility buttonVisibility = visibilityForCancelButton();
532     if (curStyle->visibility() == buttonVisibility)
533         return;
534
535     RefPtr<RenderStyle> cancelButtonStyle = RenderStyle::clone(curStyle);
536     cancelButtonStyle->setVisibility(buttonVisibility);
537     cancelButtonRenderer->setStyle(cancelButtonStyle);
538 }
539
540 EVisibility RenderTextControlSingleLine::visibilityForCancelButton() const
541 {
542     return (style()->visibility() == HIDDEN || inputElement()->value().isEmpty()) ? HIDDEN : VISIBLE;
543 }
544
545 const AtomicString& RenderTextControlSingleLine::autosaveName() const
546 {
547     return static_cast<Element*>(node())->getAttribute(autosaveAttr);
548 }
549
550 // PopupMenuClient methods
551 void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents)
552 {
553     ASSERT(static_cast<int>(listIndex) < listSize());
554     HTMLInputElement* input = inputElement();
555     if (static_cast<int>(listIndex) == (listSize() - 1)) {
556         if (fireEvents) {
557             m_recentSearches.clear();
558             const AtomicString& name = autosaveName();
559             if (!name.isEmpty()) {
560                 if (!m_searchPopup)
561                     m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
562                 m_searchPopup->saveRecentSearches(name, m_recentSearches);
563             }
564         }
565     } else {
566         input->setValue(itemText(listIndex));
567         if (fireEvents)
568             input->onSearch();
569         input->select();
570     }
571 }
572
573 String RenderTextControlSingleLine::itemText(unsigned listIndex) const
574 {
575     int size = listSize();
576     if (size == 1) {
577         ASSERT(!listIndex);
578         return searchMenuNoRecentSearchesText();
579     }
580     if (!listIndex)
581         return searchMenuRecentSearchesText();
582     if (itemIsSeparator(listIndex))
583         return String();
584     if (static_cast<int>(listIndex) == (size - 1))
585         return searchMenuClearRecentSearchesText();
586     return m_recentSearches[listIndex - 1];
587 }
588
589 String RenderTextControlSingleLine::itemLabel(unsigned) const
590 {
591     return String();
592 }
593
594 String RenderTextControlSingleLine::itemIcon(unsigned) const
595 {
596     return String();
597 }
598
599 bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const
600 {
601      if (!listIndex || itemIsSeparator(listIndex))
602         return false;
603     return true;
604 }
605
606 PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const
607 {
608     return menuStyle();
609 }
610
611 PopupMenuStyle RenderTextControlSingleLine::menuStyle() const
612 {
613     return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, style()->display() == NONE, style()->textIndent(), style()->direction(), style()->unicodeBidi() == Override);
614 }
615
616 int RenderTextControlSingleLine::clientInsetLeft() const
617 {
618     // Inset the menu by the radius of the cap on the left so that
619     // it only runs along the straight part of the bezel.
620     return height() / 2;
621 }
622
623 int RenderTextControlSingleLine::clientInsetRight() const
624 {
625     // Inset the menu by the radius of the cap on the right so that
626     // it only runs along the straight part of the bezel (unless it needs
627     // to be wider).
628     return height() / 2;
629 }
630
631 int RenderTextControlSingleLine::clientPaddingLeft() const
632 {
633     int padding = paddingLeft();
634
635     HTMLElement* resultsButton = resultsButtonElement();
636     if (RenderBox* resultsRenderer = resultsButton ? resultsButton->renderBox() : 0)
637         padding += resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->paddingLeft() + resultsRenderer->marginRight() + resultsRenderer->paddingRight();
638
639     return padding;
640 }
641
642 int RenderTextControlSingleLine::clientPaddingRight() const
643 {
644     int padding = paddingRight();
645
646     HTMLElement* cancelButton = cancelButtonElement();
647     if (RenderBox* cancelRenderer = cancelButton ? cancelButton->renderBox() : 0)
648         padding += cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->paddingLeft() + cancelRenderer->marginRight() + cancelRenderer->paddingRight();
649
650     return padding;
651 }
652
653 int RenderTextControlSingleLine::listSize() const
654 {
655     // If there are no recent searches, then our menu will have 1 "No recent searches" item.
656     if (!m_recentSearches.size())
657         return 1;
658     // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item.
659     return m_recentSearches.size() + 3;
660 }
661
662 int RenderTextControlSingleLine::selectedIndex() const
663 {
664     return -1;
665 }
666
667 void RenderTextControlSingleLine::popupDidHide()
668 {
669     m_searchPopupIsVisible = false;
670 }
671
672 bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const
673 {
674     // The separator will be the second to last item in our list.
675     return static_cast<int>(listIndex) == (listSize() - 2);
676 }
677
678 bool RenderTextControlSingleLine::itemIsLabel(unsigned listIndex) const
679 {
680     return listIndex == 0;
681 }
682
683 bool RenderTextControlSingleLine::itemIsSelected(unsigned) const
684 {
685     return false;
686 }
687
688 void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex)
689 {
690     inputElement()->setValue(itemText(listIndex));
691 }
692
693 FontSelector* RenderTextControlSingleLine::fontSelector() const
694 {
695     return document()->styleSelector()->fontSelector();
696 }
697
698 HostWindow* RenderTextControlSingleLine::hostWindow() const
699 {
700     return document()->view()->hostWindow();
701 }
702
703 void RenderTextControlSingleLine::autoscroll()
704 {
705     RenderLayer* layer = innerTextElement()->renderBox()->layer();
706     if (layer)
707         layer->autoscroll();
708 }
709
710 LayoutUnit RenderTextControlSingleLine::scrollWidth() const
711 {
712     if (innerTextElement())
713         return innerTextElement()->scrollWidth();
714     return RenderBlock::scrollWidth();
715 }
716
717 LayoutUnit RenderTextControlSingleLine::scrollHeight() const
718 {
719     if (innerTextElement())
720         return innerTextElement()->scrollHeight();
721     return RenderBlock::scrollHeight();
722 }
723
724 LayoutUnit RenderTextControlSingleLine::scrollLeft() const
725 {
726     if (innerTextElement())
727         return innerTextElement()->scrollLeft();
728     return RenderBlock::scrollLeft();
729 }
730
731 LayoutUnit RenderTextControlSingleLine::scrollTop() const
732 {
733     if (innerTextElement())
734         return innerTextElement()->scrollTop();
735     return RenderBlock::scrollTop();
736 }
737
738 void RenderTextControlSingleLine::setScrollLeft(LayoutUnit newLeft)
739 {
740     if (innerTextElement())
741         innerTextElement()->setScrollLeft(newLeft);
742 }
743
744 void RenderTextControlSingleLine::setScrollTop(LayoutUnit newTop)
745 {
746     if (innerTextElement())
747         innerTextElement()->setScrollTop(newTop);
748 }
749
750 bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
751 {
752     RenderLayer* layer = innerTextElement()->renderBox()->layer();
753     if (layer && layer->scroll(direction, granularity, multiplier))
754         return true;
755     return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
756 }
757
758 bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
759 {
760     RenderLayer* layer = innerTextElement()->renderBox()->layer();
761     if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
762         return true;
763     return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
764 }
765
766 PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
767 {
768     RefPtr<Scrollbar> widget;
769     bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
770     if (hasCustomScrollbarStyle)
771         widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, this);
772     else
773         widget = Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize);
774     return widget.release();
775 }
776
777 HTMLInputElement* RenderTextControlSingleLine::inputElement() const
778 {
779     return node()->toInputElement();
780 }
781
782 }