OSDN Git Service

am 891974e8: (-s ours) am 19d88459: am f18b71fe: Merge "Fix for bug 4144936: [Proxy...
[android-x86/external-webkit.git] / 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 "Chrome.h"
28 #include "CSSStyleSelector.h"
29 #include "Event.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "HTMLInputElement.h"
34 #include "HTMLNames.h"
35 #include "HitTestResult.h"
36 #include "InputElement.h"
37 #include "LocalizedStrings.h"
38 #include "MouseEvent.h"
39 #include "PlatformKeyboardEvent.h"
40 #include "RenderLayer.h"
41 #include "RenderScrollbar.h"
42 #include "RenderTheme.h"
43 #include "SelectionController.h"
44 #include "Settings.h"
45 #include "SimpleFontData.h"
46 #include "TextControlInnerElements.h"
47
48 using namespace std;
49
50 namespace WebCore {
51
52 using namespace HTMLNames;
53
54 RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node, bool placeholderVisible)
55     : RenderTextControl(node, placeholderVisible)
56     , m_searchPopupIsVisible(false)
57     , m_shouldDrawCapsLockIndicator(false)
58     , m_searchEventTimer(this, &RenderTextControlSingleLine::searchEventTimerFired)
59     , m_searchPopup(0)
60 {
61 }
62
63 RenderTextControlSingleLine::~RenderTextControlSingleLine()
64 {
65     if (m_searchPopup) {
66         m_searchPopup->popupMenu()->disconnectClient();
67         m_searchPopup = 0;
68     }
69  
70     if (m_innerBlock) {
71         m_innerBlock->detach();
72         m_innerBlock = 0;
73     }
74
75     if (m_innerSpinButton)
76         m_innerSpinButton->detach();
77     if (m_outerSpinButton)
78         m_outerSpinButton->detach();
79 #if ENABLE(INPUT_SPEECH)
80     if (m_speechButton)
81         m_speechButton->detach();
82 #endif
83 }
84
85 RenderStyle* RenderTextControlSingleLine::textBaseStyle() const
86 {
87     return m_innerBlock ? m_innerBlock->renderer()->style() : style();
88 }
89
90 void RenderTextControlSingleLine::addSearchResult()
91 {
92     ASSERT(node()->isHTMLElement());
93     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
94     if (input->maxResults() <= 0)
95         return;
96
97     String value = input->value();
98     if (value.isEmpty())
99         return;
100
101     Settings* settings = document()->settings();
102     if (!settings || settings->privateBrowsingEnabled())
103         return;
104
105     int size = static_cast<int>(m_recentSearches.size());
106     for (int i = size - 1; i >= 0; --i) {
107         if (m_recentSearches[i] == value)
108             m_recentSearches.remove(i);
109     }
110
111     m_recentSearches.insert(0, value);
112     while (static_cast<int>(m_recentSearches.size()) > input->maxResults())
113         m_recentSearches.removeLast();
114
115     const AtomicString& name = autosaveName();
116     if (!m_searchPopup)
117         m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
118
119     m_searchPopup->saveRecentSearches(name, m_recentSearches);
120 }
121
122 void RenderTextControlSingleLine::stopSearchEventTimer()
123 {
124     ASSERT(node()->isHTMLElement());
125     m_searchEventTimer.stop();
126 }
127
128 void RenderTextControlSingleLine::showPopup()
129 {
130     ASSERT(node()->isHTMLElement());
131     if (m_searchPopupIsVisible)
132         return;
133
134     if (!m_searchPopup)
135         m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
136
137     if (!m_searchPopup->enabled())
138         return;
139
140     m_searchPopupIsVisible = true;
141
142     const AtomicString& name = autosaveName();
143     m_searchPopup->loadRecentSearches(name, m_recentSearches);
144
145     // Trim the recent searches list if the maximum size has changed since we last saved.
146     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
147     if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) {
148         do {
149             m_recentSearches.removeLast();
150         } while (static_cast<int>(m_recentSearches.size()) > input->maxResults());
151
152         m_searchPopup->saveRecentSearches(name, m_recentSearches);
153     }
154
155     m_searchPopup->popupMenu()->show(absoluteBoundingBoxRect(true), document()->view(), -1);
156 }
157
158 void RenderTextControlSingleLine::hidePopup()
159 {
160     ASSERT(node()->isHTMLElement());
161     if (m_searchPopup)
162         m_searchPopup->popupMenu()->hide();
163 }
164
165 void RenderTextControlSingleLine::subtreeHasChanged()
166 {
167     bool wasChanged = wasChangedSinceLastChangeEvent();
168     RenderTextControl::subtreeHasChanged();
169
170     InputElement* input = inputElement();
171     // We don't need to call sanitizeUserInputValue() function here because
172     // InputElement::handleBeforeTextInsertedEvent() has already called
173     // sanitizeUserInputValue().
174     // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
175     String value = text();
176     if (input->isAcceptableValue(value))
177         input->setValueFromRenderer(input->sanitizeValue(value));
178     if (node()->isHTMLElement()) {
179         // Recalc for :invalid and hasUnacceptableValue() change.
180         static_cast<HTMLInputElement*>(input)->setNeedsStyleRecalc();
181     }
182
183     if (m_cancelButton)
184         updateCancelButtonVisibility();
185
186     // If the incremental attribute is set, then dispatch the search event
187     if (input->searchEventsShouldBeDispatched())
188         startSearchEventTimer();
189
190     if (!wasChanged && node()->focused()) {
191         if (Frame* frame = this->frame())
192             frame->editor()->textFieldDidBeginEditing(static_cast<Element*>(node()));
193     }
194
195     if (node()->focused()) {
196         if (Frame* frame = document()->frame())
197             frame->editor()->textDidChangeInTextField(static_cast<Element*>(node()));
198     }
199 }
200
201 void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty)
202 {
203     RenderTextControl::paint(paintInfo, tx, ty);
204
205     if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
206         IntRect contentsRect = contentBoxRect();
207
208         // Center vertically like the text.
209         contentsRect.setY((height() - contentsRect.height()) / 2);
210
211         // Convert the rect into the coords used for painting the content
212         contentsRect.move(tx + x(), ty + y());
213         theme()->paintCapsLockIndicator(this, paintInfo, contentsRect);
214     }
215 }
216
217 void RenderTextControlSingleLine::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
218 {
219     paintBoxDecorationsWithSize(paintInfo, tx, ty, width() - decorationWidthRight(), height());
220 }
221
222 void RenderTextControlSingleLine::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
223 {
224     int w = width() - decorationWidthRight();
225     if (w && height())
226         rects.append(IntRect(tx, ty, w, height()));
227 }
228
229 void RenderTextControlSingleLine::layout()
230 {
231     int oldHeight = height();
232     computeLogicalHeight();
233
234     int oldWidth = width();
235     computeLogicalWidth();
236
237     bool relayoutChildren = oldHeight != height() || oldWidth != width();
238
239 #ifdef ANDROID_LAYOUT
240     checkAndSetRelayoutChildren(&relayoutChildren);
241 #endif
242
243     RenderBox* innerTextRenderer = innerTextElement()->renderBox();
244     RenderBox* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderBox() : 0;
245
246     // Set the text block height
247     int desiredHeight = textBlockHeight();
248     int currentHeight = innerTextRenderer->height();
249
250     if (currentHeight > height()) {
251         if (desiredHeight != currentHeight)
252             relayoutChildren = true;
253         innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed));
254         if (m_innerBlock)
255             innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed));
256     }
257
258     // Set the text block width
259     int desiredWidth = textBlockWidth();
260     if (desiredWidth != innerTextRenderer->width())
261         relayoutChildren = true;
262     innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed));
263
264     if (m_innerBlock) {
265         int innerBlockWidth = width() - borderAndPaddingWidth();
266         if (innerBlockWidth != innerBlockRenderer->width())
267             relayoutChildren = true;
268         innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed));
269     }
270
271     RenderBlock::layoutBlock(relayoutChildren);
272
273     // Center the child block vertically
274     RenderBox* childBlock = innerBlockRenderer ? innerBlockRenderer : innerTextRenderer;
275     currentHeight = childBlock->height();
276     if (currentHeight < height())
277         childBlock->setY((height() - currentHeight) / 2);
278
279     // Ignores the paddings for the inner spin button.
280     if (RenderBox* spinBox = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) {
281         spinBox->setLocation(spinBox->x() + paddingRight(), borderTop());
282         spinBox->setHeight(height() - borderTop() - borderBottom());
283     }
284
285 #if ENABLE(INPUT_SPEECH)
286     if (RenderBox* button = m_speechButton ? m_speechButton->renderBox() : 0) {
287         if (m_innerBlock) {
288             // This is mostly the case where this is a search field. The speech button is a sibling
289             // of the inner block and laid out at the far right.
290             int x = width() - borderAndPaddingWidth() - button->width() - button->borderAndPaddingWidth();
291             int y = (height() - button->height()) / 2;
292             button->setLocation(x, y);
293         } else {
294             // For non-search fields which are simpler and we let the defaut layout handle things
295             // except for small tweaking below.
296             button->setLocation(button->x() + paddingRight(), (height() - button->height()) / 2);
297         }
298     }
299 #endif
300
301     // Center the spin button vertically, and move it to the right by
302     // padding + border of the text fields.
303     if (RenderBox* spinBox = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) {
304         int diff = height() - spinBox->height();
305         // If the diff is odd, the top area over the spin button takes the
306         // remaining one pixel. It's good for Mac NSStepper because it has
307         // shadow at the bottom.
308         int y = (diff / 2) + (diff % 2);
309         int x = width() - borderRight() - paddingRight() - spinBox->width();
310         spinBox->setLocation(x, y);
311     }
312 }
313
314 bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction)
315 {
316     // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point
317     // was on the control but not on the inner element (see Radar 4617841).
318
319     // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block,
320     // and act as if we've hit the close block if we're to the right of the inner text block.
321
322     if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction))
323         return false;
324
325     // If we hit a node inside the inner text element, say that we hit that element,
326     // and if we hit our node (e.g. we're over the border or padding), also say that we hit the
327     // inner text element so that it gains focus.
328     if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node())
329         hitInnerTextElement(result, xPos, yPos, tx, ty);
330
331     // If we found a spin button, we're done.
332     if (m_innerSpinButton && result.innerNode() == m_innerSpinButton)
333         return true;
334     if (m_outerSpinButton && result.innerNode() == m_outerSpinButton)
335         return true;
336 #if ENABLE(INPUT_SPEECH)
337     if (m_speechButton && result.innerNode() == m_speechButton)
338         return true;
339 #endif
340     // If we're not a search field, or we already found the speech, results or cancel buttons, we're done.
341     if (!m_innerBlock || result.innerNode() == m_resultsButton || result.innerNode() == m_cancelButton)
342         return true;
343
344     Node* innerNode = 0;
345     RenderBox* innerBlockRenderer = m_innerBlock->renderBox();
346     RenderBox* innerTextRenderer = innerTextElement()->renderBox();
347
348     IntPoint localPoint = result.localPoint();
349     localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y());
350
351     int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x();
352     if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft)
353         innerNode = m_resultsButton.get();
354
355     if (!innerNode) {
356         int textRight = textLeft + innerTextRenderer->width();
357         if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight)
358             innerNode = m_cancelButton.get();
359     }
360
361     if (innerNode) {
362         result.setInnerNode(innerNode);
363         localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y());
364     }
365
366     result.setLocalPoint(localPoint);
367     return true;
368 }
369
370 void RenderTextControlSingleLine::forwardEvent(Event* event)
371 {
372     RenderBox* innerTextRenderer = innerTextElement()->renderBox();
373
374     if (event->type() == eventNames().blurEvent) {
375         if (innerTextRenderer) {
376             if (RenderLayer* innerLayer = innerTextRenderer->layer())
377                 innerLayer->scrollToOffset(!style()->isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0);
378         }
379
380         capsLockStateMayHaveChanged();
381     } else if (event->type() == eventNames().focusEvent)
382         capsLockStateMayHaveChanged();
383
384     if (!event->isMouseEvent()) {
385         RenderTextControl::forwardEvent(event);
386         return;
387     }
388
389 #if ENABLE(INPUT_SPEECH)
390     if (RenderBox* speechBox = m_speechButton ? m_speechButton->renderBox() : 0) {
391         FloatPoint pointInTextControlCoords = absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true);
392         if (speechBox->frameRect().contains(roundedIntPoint(pointInTextControlCoords))) {
393             m_speechButton->defaultEventHandler(event);
394             return;
395         }
396     }
397 #endif
398
399     FloatPoint localPoint = innerTextRenderer->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true);
400     int textRight = innerTextRenderer->borderBoxRect().right();
401
402     if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x())
403         m_resultsButton->defaultEventHandler(event);
404     else if (m_cancelButton && localPoint.x() > textRight)
405         m_cancelButton->defaultEventHandler(event);
406     else if (m_innerSpinButton && localPoint.x() > textRight && m_innerSpinButton->renderBox() && localPoint.x() < textRight + m_innerSpinButton->renderBox()->width())
407         m_innerSpinButton->defaultEventHandler(event);
408     else if (m_outerSpinButton && localPoint.x() > textRight)
409         m_outerSpinButton->defaultEventHandler(event);
410     else
411         RenderTextControl::forwardEvent(event);
412 }
413
414 void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
415 {
416     RenderTextControl::styleDidChange(diff, oldStyle);
417
418     if (RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0) {
419         // We may have set the width and the height in the old style in layout().
420         // Reset them now to avoid getting a spurious layout hint.
421         innerBlockRenderer->style()->setHeight(Length());
422         innerBlockRenderer->style()->setWidth(Length());
423         innerBlockRenderer->setStyle(createInnerBlockStyle(style()));
424     }
425
426     if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0)
427         resultsRenderer->setStyle(createResultsButtonStyle(style()));
428
429     if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
430         cancelRenderer->setStyle(createCancelButtonStyle(style()));
431
432     if (RenderObject* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderer() : 0)
433         spinRenderer->setStyle(createOuterSpinButtonStyle());
434
435 #if ENABLE(INPUT_SPEECH)
436     if (RenderObject* speechRenderer = m_speechButton ? m_speechButton->renderer() : 0)
437         speechRenderer->setStyle(createSpeechButtonStyle());
438 #endif
439
440     setHasOverflowClip(false);
441 }
442
443 void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
444 {
445     if (!node() || !document())
446         return;
447
448     // Only draw the caps lock indicator if these things are true:
449     // 1) The field is a password field
450     // 2) The frame is active
451     // 3) The element is focused
452     // 4) The caps lock is on
453     bool shouldDrawCapsLockIndicator = false;
454
455     if (Frame* frame = document()->frame())
456         shouldDrawCapsLockIndicator = inputElement()->isPasswordField()
457                                       && frame->selection()->isFocusedAndActive()
458                                       && document()->focusedNode() == node()
459                                       && PlatformKeyboardEvent::currentCapsLockState();
460
461     if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
462         m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
463         repaint();
464     }
465 }
466
467 bool RenderTextControlSingleLine::hasControlClip() const
468 {
469     bool clip = m_cancelButton;
470     return clip;
471 }
472
473 IntRect RenderTextControlSingleLine::controlClipRect(int tx, int ty) const
474 {
475     // This should only get called for search & speech inputs.
476     ASSERT(hasControlClip());
477
478     IntRect clipRect = IntRect(m_innerBlock->renderBox()->frameRect());
479     clipRect.move(tx, ty);
480     return clipRect;
481 }
482
483 int RenderTextControlSingleLine::textBlockWidth() const
484 {
485     int width = RenderTextControl::textBlockWidth();
486
487     if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) {
488         resultsRenderer->computeLogicalWidth();
489         width -= resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->marginRight();
490     }
491
492     if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) {
493         cancelRenderer->computeLogicalWidth();
494         width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight();
495     }
496
497     if (RenderBox* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) {
498         spinRenderer->computeLogicalWidth();
499         width -= spinRenderer->width() + spinRenderer->marginLeft() + spinRenderer->marginRight();
500     }
501
502 #if ENABLE(INPUT_SPEECH)
503     if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) {
504         speechRenderer->computeLogicalWidth();
505         width -= speechRenderer->width() + speechRenderer->marginLeft() + speechRenderer->marginRight();
506     }
507 #endif
508
509     return width - decorationWidthRight();
510 }
511
512 int RenderTextControlSingleLine::decorationWidthRight() const
513 {
514     int width = 0;
515     if (RenderBox* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) {
516         spinRenderer->computeLogicalWidth();
517         width += spinRenderer->width() + spinRenderer->marginLeft() + spinRenderer->marginRight();
518     }
519     if (width > 0)
520         width += paddingRight() + borderRight();
521     return width;
522 }
523     
524 float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family)
525 {
526     // Since Lucida Grande is the default font, we want this to match the width
527     // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
528     // IE for some encodings (in IE, the default font is encoding specific).
529     // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg.
530     if (family == AtomicString("Lucida Grande"))
531         return scaleEmToUnits(901);
532
533     return RenderTextControl::getAvgCharWidth(family);
534 }
535     
536 int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const
537 {
538     int factor = inputElement()->size();
539     if (factor <= 0)
540         factor = 20;
541
542     int result = static_cast<int>(ceilf(charWidth * factor));
543
544     float maxCharWidth = 0.f;
545     AtomicString family = style()->font().family().family();
546     // Since Lucida Grande is the default font, we want this to match the width
547     // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
548     // IE for some encodings (in IE, the default font is encoding specific).
549     // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg.
550     if (family == AtomicString("Lucida Grande"))
551         maxCharWidth = scaleEmToUnits(4027);
552     else if (hasValidAvgCharWidth(family))
553         maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth());
554
555     // For text inputs, IE adds some extra width.
556     if (maxCharWidth > 0.f)
557         result += maxCharWidth - charWidth;
558
559     if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0)
560         result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() +
561                   resultsRenderer->paddingLeft() + resultsRenderer->paddingRight();
562
563     if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0)
564         result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() +
565                   cancelRenderer->paddingLeft() + cancelRenderer->paddingRight();
566
567     if (RenderBox* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0)
568         result += spinRenderer->minPreferredLogicalWidth();
569
570 #if ENABLE(INPUT_SPEECH)
571     if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) {
572         result += speechRenderer->borderLeft() + speechRenderer->borderRight() +
573                   speechRenderer->paddingLeft() + speechRenderer->paddingRight();
574     }
575 #endif
576     return result;
577 }
578
579 int RenderTextControlSingleLine::preferredDecorationWidthRight() const
580 {
581     int width = 0;
582     if (RenderBox* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) {
583         spinRenderer->computeLogicalWidth();
584         width += spinRenderer->minPreferredLogicalWidth() + spinRenderer->marginLeft() + spinRenderer->marginRight();
585     }
586     if (width > 0)
587         width += paddingRight() + borderRight();
588     return width;
589 }
590
591 void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight)
592 {
593     if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) {
594         resultsRenderer->computeLogicalHeight();
595         setHeight(max(height(),
596                   resultsRenderer->borderTop() + resultsRenderer->borderBottom() +
597                   resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() +
598                   resultsRenderer->marginTop() + resultsRenderer->marginBottom()));
599         lineHeight = max(lineHeight, resultsRenderer->height());
600     }
601     if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) {
602         cancelRenderer->computeLogicalHeight();
603         setHeight(max(height(),
604                   cancelRenderer->borderTop() + cancelRenderer->borderBottom() +
605                   cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() +
606                   cancelRenderer->marginTop() + cancelRenderer->marginBottom()));
607         lineHeight = max(lineHeight, cancelRenderer->height());
608     }
609
610     setHeight(height() + lineHeight);
611 }
612
613 void RenderTextControlSingleLine::createSubtreeIfNeeded()
614 {
615     bool createSubtree = inputElement()->isSearchField();
616     if (!createSubtree) {
617         RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get());
618 #if ENABLE(INPUT_SPEECH)
619         if (inputElement()->isSpeechEnabled() && !m_speechButton) {
620             // Create the speech button element.
621             m_speechButton = InputFieldSpeechButtonElement::create(static_cast<HTMLElement*>(node()));
622             m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena());
623         }
624 #endif
625         bool hasSpinButton = inputElement()->hasSpinButton();
626         if (hasSpinButton && !m_innerSpinButton) {
627             m_innerSpinButton = SpinButtonElement::create(static_cast<HTMLElement*>(node()));
628             m_innerSpinButton->attachInnerElement(node(), createInnerSpinButtonStyle(), renderArena());
629         }
630         if (hasSpinButton && !m_outerSpinButton) {
631             m_outerSpinButton = SpinButtonElement::create(static_cast<HTMLElement*>(node()));
632             m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena());
633         }
634         return;
635     }
636
637     if (!m_innerBlock) {
638         // Create the inner block element
639         m_innerBlock = TextControlInnerElement::create(static_cast<HTMLElement*>(node()));
640         m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena());
641     }
642 #if ENABLE(INPUT_SPEECH)
643     if (inputElement()->isSpeechEnabled() && !m_speechButton) {
644         // Create the speech button element.
645         m_speechButton = InputFieldSpeechButtonElement::create(static_cast<HTMLElement*>(node()));
646         m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena());
647     }
648 #endif
649     if (inputElement()->hasSpinButton() && !m_outerSpinButton) {
650         m_outerSpinButton = SpinButtonElement::create(static_cast<HTMLElement*>(node()));
651         m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena());
652     }
653
654     if (inputElement()->isSearchField()) {
655         if (!m_resultsButton) {
656             // Create the search results button element.
657             m_resultsButton = SearchFieldResultsButtonElement::create(document());
658             m_resultsButton->attachInnerElement(m_innerBlock.get(), createResultsButtonStyle(m_innerBlock->renderer()->style()), renderArena());
659         }
660     }
661
662     // Create innerText element before adding the other buttons.
663     RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get());
664
665     if (inputElement()->isSearchField()) {
666         if (!m_cancelButton) {
667             // Create the cancel button element.
668             m_cancelButton = SearchFieldCancelButtonElement::create(document());
669             m_cancelButton->attachInnerElement(m_innerBlock.get(), createCancelButtonStyle(m_innerBlock->renderer()->style()), renderArena());
670         }
671     }
672 }
673
674 void RenderTextControlSingleLine::updateFromElement()
675 {
676     createSubtreeIfNeeded();
677     RenderTextControl::updateFromElement();
678
679     if (m_cancelButton)
680         updateCancelButtonVisibility();
681
682     if (!inputElement()->suggestedValue().isNull())
683         setInnerTextValue(inputElement()->suggestedValue());
684     else {
685         if (node()->hasTagName(inputTag)) {
686             // For HTMLInputElement, update the renderer value if the formControlValueMatchesRenderer()
687             // flag is false. It protects an unacceptable renderer value from
688             // being overwritten with the DOM value.
689             if (!static_cast<HTMLInputElement*>(node())->formControlValueMatchesRenderer())
690                 setInnerTextValue(inputElement()->value());
691         }
692     }
693
694     if (m_searchPopupIsVisible)
695         m_searchPopup->popupMenu()->updateFromElement();
696 }
697
698 void RenderTextControlSingleLine::cacheSelection(int start, int end)
699 {
700     inputElement()->cacheSelection(start, end);
701 }
702
703 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
704 {
705     RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();   
706     textBlockStyle->inheritFrom(startStyle);
707     adjustInnerTextStyle(startStyle, textBlockStyle.get());
708
709     textBlockStyle->setWhiteSpace(PRE);
710     textBlockStyle->setWordWrap(NormalWordWrap);
711     textBlockStyle->setOverflowX(OHIDDEN);
712     textBlockStyle->setOverflowY(OHIDDEN);
713
714     // Do not allow line-height to be smaller than our default.
715     if (textBlockStyle->font().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
716         textBlockStyle->setLineHeight(Length(-100.0f, Percent));
717
718     WebCore::EDisplay display = (m_innerBlock || inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK);
719 #if ENABLE(INPUT_SPEECH)
720     if (inputElement()->isSpeechEnabled())
721       display = INLINE_BLOCK;
722 #endif
723     textBlockStyle->setDisplay(display);
724
725     // We're adding one extra pixel of padding to match WinIE.
726     textBlockStyle->setPaddingLeft(Length(1, Fixed));
727     textBlockStyle->setPaddingRight(Length(1, Fixed));
728
729     return textBlockStyle.release();
730 }
731
732 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
733 {
734     ASSERT(node()->isHTMLElement());
735
736     RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
737     innerBlockStyle->inheritFrom(startStyle);
738
739     innerBlockStyle->setDisplay(inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK);
740     innerBlockStyle->setDirection(LTR);
741
742     // 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.
743     innerBlockStyle->setUserModify(READ_ONLY);
744
745     return innerBlockStyle.release();
746 }
747
748 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(const RenderStyle* startStyle) const
749 {
750     ASSERT(node()->isHTMLElement());
751     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
752
753     RefPtr<RenderStyle> resultsBlockStyle;
754     if (input->maxResults() < 0)
755         resultsBlockStyle = getCachedPseudoStyle(SEARCH_DECORATION);
756     else if (!input->maxResults())
757         resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_DECORATION);
758     else
759         resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_BUTTON);
760
761     if (!resultsBlockStyle)
762         resultsBlockStyle = RenderStyle::create();
763
764     if (startStyle)
765         resultsBlockStyle->inheritFrom(startStyle);
766
767     return resultsBlockStyle.release();
768 }
769
770 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(const RenderStyle* startStyle) const
771 {
772     ASSERT(node()->isHTMLElement());
773     RefPtr<RenderStyle> cancelBlockStyle;
774     
775     if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(SEARCH_CANCEL_BUTTON))
776         // We may be sharing style with another search field, but we must not share the cancel button style.
777         cancelBlockStyle = RenderStyle::clone(pseudoStyle.get());
778     else
779         cancelBlockStyle = RenderStyle::create();
780
781     if (startStyle)
782         cancelBlockStyle->inheritFrom(startStyle);
783
784     cancelBlockStyle->setVisibility(visibilityForCancelButton());
785     return cancelBlockStyle.release();
786 }
787
788 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerSpinButtonStyle() const
789 {
790     ASSERT(node()->isHTMLElement());
791     RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INNER_SPIN_BUTTON);
792     if (!buttonStyle)
793         buttonStyle = RenderStyle::create();
794     buttonStyle->inheritFrom(style());
795     return buttonStyle.release();
796 }
797
798 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createOuterSpinButtonStyle() const
799 {
800     ASSERT(node()->isHTMLElement());
801     RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(OUTER_SPIN_BUTTON);
802     if (!buttonStyle)
803         buttonStyle = RenderStyle::create();
804     buttonStyle->inheritFrom(style());
805     return buttonStyle.release();
806 }
807
808 #if ENABLE(INPUT_SPEECH)
809 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createSpeechButtonStyle() const
810 {
811     ASSERT(node()->isHTMLElement());
812     RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INPUT_SPEECH_BUTTON);
813     if (!buttonStyle)
814         buttonStyle = RenderStyle::create();
815     buttonStyle->inheritFrom(style());
816     return buttonStyle.release();
817 }
818 #endif
819
820 void RenderTextControlSingleLine::updateCancelButtonVisibility() const
821 {
822     if (!m_cancelButton->renderer())
823         return;
824
825     const RenderStyle* curStyle = m_cancelButton->renderer()->style();
826     EVisibility buttonVisibility = visibilityForCancelButton();
827     if (curStyle->visibility() == buttonVisibility)
828         return;
829
830     RefPtr<RenderStyle> cancelButtonStyle = RenderStyle::clone(curStyle);
831     cancelButtonStyle->setVisibility(buttonVisibility);
832     m_cancelButton->renderer()->setStyle(cancelButtonStyle);
833 }
834
835 EVisibility RenderTextControlSingleLine::visibilityForCancelButton() const
836 {
837     ASSERT(node()->isHTMLElement());
838     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
839     return input->value().isEmpty() ? HIDDEN : VISIBLE;
840 }
841
842 const AtomicString& RenderTextControlSingleLine::autosaveName() const
843 {
844     return static_cast<Element*>(node())->getAttribute(autosaveAttr);
845 }
846
847 void RenderTextControlSingleLine::startSearchEventTimer()
848 {
849     ASSERT(node()->isHTMLElement());
850     unsigned length = text().length();
851
852     // If there's no text, fire the event right away.
853     if (!length) {
854         stopSearchEventTimer();
855         static_cast<HTMLInputElement*>(node())->onSearch();
856         return;
857     }
858
859     // After typing the first key, we wait 0.5 seconds.
860     // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on.
861     m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length));
862 }
863
864 void RenderTextControlSingleLine::searchEventTimerFired(Timer<RenderTextControlSingleLine>*)
865 {
866     ASSERT(node()->isHTMLElement());
867     static_cast<HTMLInputElement*>(node())->onSearch();
868 }
869
870 // PopupMenuClient methods
871 void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents)
872 {
873     ASSERT(node()->isHTMLElement());
874     ASSERT(static_cast<int>(listIndex) < listSize());
875     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
876     if (static_cast<int>(listIndex) == (listSize() - 1)) {
877         if (fireEvents) {
878             m_recentSearches.clear();
879             const AtomicString& name = autosaveName();
880             if (!name.isEmpty()) {
881                 if (!m_searchPopup)
882                     m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
883                 m_searchPopup->saveRecentSearches(name, m_recentSearches);
884             }
885         }
886     } else {
887         input->setValue(itemText(listIndex));
888         if (fireEvents)
889             input->onSearch();
890         input->select();
891     }
892 }
893
894 String RenderTextControlSingleLine::itemText(unsigned listIndex) const
895 {
896     int size = listSize();
897     if (size == 1) {
898         ASSERT(!listIndex);
899         return searchMenuNoRecentSearchesText();
900     }
901     if (!listIndex)
902         return searchMenuRecentSearchesText();
903     if (itemIsSeparator(listIndex))
904         return String();
905     if (static_cast<int>(listIndex) == (size - 1))
906         return searchMenuClearRecentSearchesText();
907     return m_recentSearches[listIndex - 1];
908 }
909
910 String RenderTextControlSingleLine::itemLabel(unsigned) const
911 {
912     return String();
913 }
914
915 String RenderTextControlSingleLine::itemIcon(unsigned) const
916 {
917     return String();
918 }
919
920 bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const
921 {
922      if (!listIndex || itemIsSeparator(listIndex))
923         return false;
924     return true;
925 }
926
927 PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const
928 {
929     return menuStyle();
930 }
931
932 PopupMenuStyle RenderTextControlSingleLine::menuStyle() const
933 {
934     return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, style()->display() == NONE, style()->textIndent(), style()->direction());
935 }
936
937 int RenderTextControlSingleLine::clientInsetLeft() const
938 {
939     // Inset the menu by the radius of the cap on the left so that
940     // it only runs along the straight part of the bezel.
941     return height() / 2;
942 }
943
944 int RenderTextControlSingleLine::clientInsetRight() const
945 {
946     // Inset the menu by the radius of the cap on the right so that
947     // it only runs along the straight part of the bezel (unless it needs
948     // to be wider).
949     return height() / 2;
950 }
951
952 int RenderTextControlSingleLine::clientPaddingLeft() const
953 {
954     int padding = paddingLeft();
955
956     if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0)
957         padding += resultsRenderer->width();
958
959     return padding;
960 }
961
962 int RenderTextControlSingleLine::clientPaddingRight() const
963 {
964     int padding = paddingRight();
965
966     if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0)
967         padding += cancelRenderer->width();
968
969     return padding;
970 }
971
972 int RenderTextControlSingleLine::listSize() const
973 {
974     // If there are no recent searches, then our menu will have 1 "No recent searches" item.
975     if (!m_recentSearches.size())
976         return 1;
977     // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item.
978     return m_recentSearches.size() + 3;
979 }
980
981 int RenderTextControlSingleLine::selectedIndex() const
982 {
983     return -1;
984 }
985
986 void RenderTextControlSingleLine::popupDidHide()
987 {
988     m_searchPopupIsVisible = false;
989 }
990
991 bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const
992 {
993     // The separator will be the second to last item in our list.
994     return static_cast<int>(listIndex) == (listSize() - 2);
995 }
996
997 bool RenderTextControlSingleLine::itemIsLabel(unsigned listIndex) const
998 {
999     return listIndex == 0;
1000 }
1001
1002 bool RenderTextControlSingleLine::itemIsSelected(unsigned) const
1003 {
1004     return false;
1005 }
1006
1007 void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex)
1008 {
1009     ASSERT(node()->isHTMLElement());
1010     static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex));
1011 }
1012
1013 FontSelector* RenderTextControlSingleLine::fontSelector() const
1014 {
1015     return document()->styleSelector()->fontSelector();
1016 }
1017
1018 HostWindow* RenderTextControlSingleLine::hostWindow() const
1019 {
1020     return document()->view()->hostWindow();
1021 }
1022
1023 void RenderTextControlSingleLine::autoscroll()
1024 {
1025     RenderLayer* layer = innerTextElement()->renderBox()->layer();
1026     if (layer)
1027         layer->autoscroll();
1028 }
1029
1030 int RenderTextControlSingleLine::scrollWidth() const
1031 {
1032     if (innerTextElement())
1033         return innerTextElement()->scrollWidth();
1034     return RenderBlock::scrollWidth();
1035 }
1036
1037 int RenderTextControlSingleLine::scrollHeight() const
1038 {
1039     if (innerTextElement())
1040         return innerTextElement()->scrollHeight();
1041     return RenderBlock::scrollHeight();
1042 }
1043
1044 int RenderTextControlSingleLine::scrollLeft() const
1045 {
1046     if (innerTextElement())
1047         return innerTextElement()->scrollLeft();
1048     return RenderBlock::scrollLeft();
1049 }
1050
1051 int RenderTextControlSingleLine::scrollTop() const
1052 {
1053     if (innerTextElement())
1054         return innerTextElement()->scrollTop();
1055     return RenderBlock::scrollTop();
1056 }
1057
1058 void RenderTextControlSingleLine::setScrollLeft(int newLeft)
1059 {
1060     if (innerTextElement())
1061         innerTextElement()->setScrollLeft(newLeft);
1062 }
1063
1064 void RenderTextControlSingleLine::setScrollTop(int newTop)
1065 {
1066     if (innerTextElement())
1067         innerTextElement()->setScrollTop(newTop);
1068 }
1069
1070 bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
1071 {
1072     RenderLayer* layer = innerTextElement()->renderBox()->layer();
1073     if (layer && layer->scroll(direction, granularity, multiplier))
1074         return true;
1075     return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
1076 }
1077
1078 bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
1079 {
1080     RenderLayer* layer = innerTextElement()->renderBox()->layer();
1081     if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
1082         return true;
1083     return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
1084 }
1085
1086 PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
1087 {
1088     RefPtr<Scrollbar> widget;
1089     bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
1090     if (hasCustomScrollbarStyle)
1091         widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, this);
1092     else
1093         widget = Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize);
1094     return widget.release();
1095 }
1096
1097 InputElement* RenderTextControlSingleLine::inputElement() const
1098 {
1099     return toInputElement(static_cast<Element*>(node()));
1100 }
1101
1102 int RenderTextControlSingleLine::textBlockInsetLeft() const
1103 {
1104     int inset = borderLeft() + clientPaddingLeft();
1105     if (HTMLElement* innerText = innerTextElement()) {
1106         if (RenderBox* innerTextRenderer = innerText->renderBox())
1107             inset += innerTextRenderer->paddingLeft();
1108     }
1109     return inset;
1110 }
1111     
1112 int RenderTextControlSingleLine::textBlockInsetRight() const
1113 {
1114     int inset = borderRight() + clientPaddingRight();
1115     if (HTMLElement* innerText = innerTextElement()) {
1116         if (RenderBox* innerTextRenderer = innerText->renderBox())
1117             inset += innerTextRenderer->paddingRight();
1118     }
1119     return inset;
1120 }
1121
1122 int RenderTextControlSingleLine::textBlockInsetTop() const
1123 {
1124     RenderBox* innerRenderer = 0;
1125     if (m_innerBlock)
1126         innerRenderer = m_innerBlock->renderBox();
1127     else if (HTMLElement* innerText = innerTextElement())
1128         innerRenderer = innerText->renderBox();
1129     
1130     if (innerRenderer)
1131         return innerRenderer->y();
1132     
1133     return borderTop() + paddingTop();
1134 }    
1135
1136 }