OSDN Git Service

Merge changes Ide388898,Ic49f367c,I1158a808,Iacb6ca5d,I2100dd3a,I5c1abe54,Ib0ef9902...
[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 #if ENABLE(INPUT_SPEECH)
675 void RenderTextControlSingleLine::speechAttributeChanged()
676 {
677     // The inner text element of this renderer has different styles depending on whether the
678     // speech button is visible or not. So when the speech attribute changes, we reset the
679     // whole thing and recreate to get the right styles and layout.
680     if (m_speechButton)
681         m_speechButton->detach();
682     setChildrenInline(true);
683     RenderStyle* parentStyle = m_innerBlock ? m_innerBlock->renderer()->style() : style();
684     setStyle(createInnerTextStyle(parentStyle));
685     updateFromElement();
686 }
687 #endif
688
689 void RenderTextControlSingleLine::updateFromElement()
690 {
691     createSubtreeIfNeeded();
692     RenderTextControl::updateFromElement();
693
694     if (m_cancelButton)
695         updateCancelButtonVisibility();
696
697     if (!inputElement()->suggestedValue().isNull())
698         setInnerTextValue(inputElement()->suggestedValue());
699     else {
700         if (node()->hasTagName(inputTag)) {
701             // For HTMLInputElement, update the renderer value if the formControlValueMatchesRenderer()
702             // flag is false. It protects an unacceptable renderer value from
703             // being overwritten with the DOM value.
704             if (!static_cast<HTMLInputElement*>(node())->formControlValueMatchesRenderer())
705                 setInnerTextValue(inputElement()->value());
706         }
707     }
708
709     if (m_searchPopupIsVisible)
710         m_searchPopup->popupMenu()->updateFromElement();
711 }
712
713 void RenderTextControlSingleLine::cacheSelection(int start, int end)
714 {
715     inputElement()->cacheSelection(start, end);
716 }
717
718 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
719 {
720     RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();   
721     textBlockStyle->inheritFrom(startStyle);
722     adjustInnerTextStyle(startStyle, textBlockStyle.get());
723
724     textBlockStyle->setWhiteSpace(PRE);
725     textBlockStyle->setWordWrap(NormalWordWrap);
726     textBlockStyle->setOverflowX(OHIDDEN);
727     textBlockStyle->setOverflowY(OHIDDEN);
728
729     // Do not allow line-height to be smaller than our default.
730     if (textBlockStyle->font().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
731         textBlockStyle->setLineHeight(Length(-100.0f, Percent));
732
733     WebCore::EDisplay display = (m_innerBlock || inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK);
734 #if ENABLE(INPUT_SPEECH)
735     if (inputElement()->isSpeechEnabled())
736       display = INLINE_BLOCK;
737 #endif
738     textBlockStyle->setDisplay(display);
739
740     // We're adding one extra pixel of padding to match WinIE.
741     textBlockStyle->setPaddingLeft(Length(1, Fixed));
742     textBlockStyle->setPaddingRight(Length(1, Fixed));
743
744     return textBlockStyle.release();
745 }
746
747 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
748 {
749     ASSERT(node()->isHTMLElement());
750
751     RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
752     innerBlockStyle->inheritFrom(startStyle);
753
754     innerBlockStyle->setDisplay(inputElement()->hasSpinButton() ? INLINE_BLOCK : BLOCK);
755     innerBlockStyle->setDirection(LTR);
756
757     // 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.
758     innerBlockStyle->setUserModify(READ_ONLY);
759
760     return innerBlockStyle.release();
761 }
762
763 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(const RenderStyle* startStyle) const
764 {
765     ASSERT(node()->isHTMLElement());
766     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
767
768     RefPtr<RenderStyle> resultsBlockStyle;
769     if (input->maxResults() < 0)
770         resultsBlockStyle = getCachedPseudoStyle(SEARCH_DECORATION);
771     else if (!input->maxResults())
772         resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_DECORATION);
773     else
774         resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_BUTTON);
775
776     if (!resultsBlockStyle)
777         resultsBlockStyle = RenderStyle::create();
778
779     if (startStyle)
780         resultsBlockStyle->inheritFrom(startStyle);
781
782     return resultsBlockStyle.release();
783 }
784
785 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(const RenderStyle* startStyle) const
786 {
787     ASSERT(node()->isHTMLElement());
788     RefPtr<RenderStyle> cancelBlockStyle;
789     
790     if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(SEARCH_CANCEL_BUTTON))
791         // We may be sharing style with another search field, but we must not share the cancel button style.
792         cancelBlockStyle = RenderStyle::clone(pseudoStyle.get());
793     else
794         cancelBlockStyle = RenderStyle::create();
795
796     if (startStyle)
797         cancelBlockStyle->inheritFrom(startStyle);
798
799     cancelBlockStyle->setVisibility(visibilityForCancelButton());
800     return cancelBlockStyle.release();
801 }
802
803 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerSpinButtonStyle() const
804 {
805     ASSERT(node()->isHTMLElement());
806     RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INNER_SPIN_BUTTON);
807     if (!buttonStyle)
808         buttonStyle = RenderStyle::create();
809     buttonStyle->inheritFrom(style());
810     return buttonStyle.release();
811 }
812
813 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createOuterSpinButtonStyle() const
814 {
815     ASSERT(node()->isHTMLElement());
816     RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(OUTER_SPIN_BUTTON);
817     if (!buttonStyle)
818         buttonStyle = RenderStyle::create();
819     buttonStyle->inheritFrom(style());
820     return buttonStyle.release();
821 }
822
823 #if ENABLE(INPUT_SPEECH)
824 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createSpeechButtonStyle() const
825 {
826     ASSERT(node()->isHTMLElement());
827     RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INPUT_SPEECH_BUTTON);
828     if (!buttonStyle)
829         buttonStyle = RenderStyle::create();
830     buttonStyle->inheritFrom(style());
831     return buttonStyle.release();
832 }
833 #endif
834
835 void RenderTextControlSingleLine::updateCancelButtonVisibility() const
836 {
837     if (!m_cancelButton->renderer())
838         return;
839
840     const RenderStyle* curStyle = m_cancelButton->renderer()->style();
841     EVisibility buttonVisibility = visibilityForCancelButton();
842     if (curStyle->visibility() == buttonVisibility)
843         return;
844
845     RefPtr<RenderStyle> cancelButtonStyle = RenderStyle::clone(curStyle);
846     cancelButtonStyle->setVisibility(buttonVisibility);
847     m_cancelButton->renderer()->setStyle(cancelButtonStyle);
848 }
849
850 EVisibility RenderTextControlSingleLine::visibilityForCancelButton() const
851 {
852     ASSERT(node()->isHTMLElement());
853     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
854     return input->value().isEmpty() ? HIDDEN : VISIBLE;
855 }
856
857 const AtomicString& RenderTextControlSingleLine::autosaveName() const
858 {
859     return static_cast<Element*>(node())->getAttribute(autosaveAttr);
860 }
861
862 void RenderTextControlSingleLine::startSearchEventTimer()
863 {
864     ASSERT(node()->isHTMLElement());
865     unsigned length = text().length();
866
867     // If there's no text, fire the event right away.
868     if (!length) {
869         stopSearchEventTimer();
870         static_cast<HTMLInputElement*>(node())->onSearch();
871         return;
872     }
873
874     // After typing the first key, we wait 0.5 seconds.
875     // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on.
876     m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length));
877 }
878
879 void RenderTextControlSingleLine::searchEventTimerFired(Timer<RenderTextControlSingleLine>*)
880 {
881     ASSERT(node()->isHTMLElement());
882     static_cast<HTMLInputElement*>(node())->onSearch();
883 }
884
885 // PopupMenuClient methods
886 void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents)
887 {
888     ASSERT(node()->isHTMLElement());
889     ASSERT(static_cast<int>(listIndex) < listSize());
890     HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
891     if (static_cast<int>(listIndex) == (listSize() - 1)) {
892         if (fireEvents) {
893             m_recentSearches.clear();
894             const AtomicString& name = autosaveName();
895             if (!name.isEmpty()) {
896                 if (!m_searchPopup)
897                     m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
898                 m_searchPopup->saveRecentSearches(name, m_recentSearches);
899             }
900         }
901     } else {
902         input->setValue(itemText(listIndex));
903         if (fireEvents)
904             input->onSearch();
905         input->select();
906     }
907 }
908
909 String RenderTextControlSingleLine::itemText(unsigned listIndex) const
910 {
911     int size = listSize();
912     if (size == 1) {
913         ASSERT(!listIndex);
914         return searchMenuNoRecentSearchesText();
915     }
916     if (!listIndex)
917         return searchMenuRecentSearchesText();
918     if (itemIsSeparator(listIndex))
919         return String();
920     if (static_cast<int>(listIndex) == (size - 1))
921         return searchMenuClearRecentSearchesText();
922     return m_recentSearches[listIndex - 1];
923 }
924
925 String RenderTextControlSingleLine::itemLabel(unsigned) const
926 {
927     return String();
928 }
929
930 String RenderTextControlSingleLine::itemIcon(unsigned) const
931 {
932     return String();
933 }
934
935 bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const
936 {
937      if (!listIndex || itemIsSeparator(listIndex))
938         return false;
939     return true;
940 }
941
942 PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const
943 {
944     return menuStyle();
945 }
946
947 PopupMenuStyle RenderTextControlSingleLine::menuStyle() const
948 {
949     return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, style()->display() == NONE, style()->textIndent(), style()->direction());
950 }
951
952 int RenderTextControlSingleLine::clientInsetLeft() const
953 {
954     // Inset the menu by the radius of the cap on the left so that
955     // it only runs along the straight part of the bezel.
956     return height() / 2;
957 }
958
959 int RenderTextControlSingleLine::clientInsetRight() const
960 {
961     // Inset the menu by the radius of the cap on the right so that
962     // it only runs along the straight part of the bezel (unless it needs
963     // to be wider).
964     return height() / 2;
965 }
966
967 int RenderTextControlSingleLine::clientPaddingLeft() const
968 {
969     int padding = paddingLeft();
970
971     if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0)
972         padding += resultsRenderer->width();
973
974     return padding;
975 }
976
977 int RenderTextControlSingleLine::clientPaddingRight() const
978 {
979     int padding = paddingRight();
980
981     if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0)
982         padding += cancelRenderer->width();
983
984     return padding;
985 }
986
987 int RenderTextControlSingleLine::listSize() const
988 {
989     // If there are no recent searches, then our menu will have 1 "No recent searches" item.
990     if (!m_recentSearches.size())
991         return 1;
992     // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item.
993     return m_recentSearches.size() + 3;
994 }
995
996 int RenderTextControlSingleLine::selectedIndex() const
997 {
998     return -1;
999 }
1000
1001 void RenderTextControlSingleLine::popupDidHide()
1002 {
1003     m_searchPopupIsVisible = false;
1004 }
1005
1006 bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const
1007 {
1008     // The separator will be the second to last item in our list.
1009     return static_cast<int>(listIndex) == (listSize() - 2);
1010 }
1011
1012 bool RenderTextControlSingleLine::itemIsLabel(unsigned listIndex) const
1013 {
1014     return listIndex == 0;
1015 }
1016
1017 bool RenderTextControlSingleLine::itemIsSelected(unsigned) const
1018 {
1019     return false;
1020 }
1021
1022 void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex)
1023 {
1024     ASSERT(node()->isHTMLElement());
1025     static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex));
1026 }
1027
1028 FontSelector* RenderTextControlSingleLine::fontSelector() const
1029 {
1030     return document()->styleSelector()->fontSelector();
1031 }
1032
1033 HostWindow* RenderTextControlSingleLine::hostWindow() const
1034 {
1035     return document()->view()->hostWindow();
1036 }
1037
1038 void RenderTextControlSingleLine::autoscroll()
1039 {
1040     RenderLayer* layer = innerTextElement()->renderBox()->layer();
1041     if (layer)
1042         layer->autoscroll();
1043 }
1044
1045 int RenderTextControlSingleLine::scrollWidth() const
1046 {
1047     if (innerTextElement())
1048         return innerTextElement()->scrollWidth();
1049     return RenderBlock::scrollWidth();
1050 }
1051
1052 int RenderTextControlSingleLine::scrollHeight() const
1053 {
1054     if (innerTextElement())
1055         return innerTextElement()->scrollHeight();
1056     return RenderBlock::scrollHeight();
1057 }
1058
1059 int RenderTextControlSingleLine::scrollLeft() const
1060 {
1061     if (innerTextElement())
1062         return innerTextElement()->scrollLeft();
1063     return RenderBlock::scrollLeft();
1064 }
1065
1066 int RenderTextControlSingleLine::scrollTop() const
1067 {
1068     if (innerTextElement())
1069         return innerTextElement()->scrollTop();
1070     return RenderBlock::scrollTop();
1071 }
1072
1073 void RenderTextControlSingleLine::setScrollLeft(int newLeft)
1074 {
1075     if (innerTextElement())
1076         innerTextElement()->setScrollLeft(newLeft);
1077 }
1078
1079 void RenderTextControlSingleLine::setScrollTop(int newTop)
1080 {
1081     if (innerTextElement())
1082         innerTextElement()->setScrollTop(newTop);
1083 }
1084
1085 bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
1086 {
1087     RenderLayer* layer = innerTextElement()->renderBox()->layer();
1088     if (layer && layer->scroll(direction, granularity, multiplier))
1089         return true;
1090     return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
1091 }
1092
1093 bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
1094 {
1095     RenderLayer* layer = innerTextElement()->renderBox()->layer();
1096     if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
1097         return true;
1098     return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
1099 }
1100
1101 PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
1102 {
1103     RefPtr<Scrollbar> widget;
1104     bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
1105     if (hasCustomScrollbarStyle)
1106         widget = RenderScrollbar::createCustomScrollbar(client, orientation, this);
1107     else
1108         widget = Scrollbar::createNativeScrollbar(client, orientation, controlSize);
1109     return widget.release();
1110 }
1111
1112 InputElement* RenderTextControlSingleLine::inputElement() const
1113 {
1114     return toInputElement(static_cast<Element*>(node()));
1115 }
1116
1117 int RenderTextControlSingleLine::textBlockInsetLeft() const
1118 {
1119     int inset = borderLeft() + clientPaddingLeft();
1120     if (HTMLElement* innerText = innerTextElement()) {
1121         if (RenderBox* innerTextRenderer = innerText->renderBox())
1122             inset += innerTextRenderer->paddingLeft();
1123     }
1124     return inset;
1125 }
1126     
1127 int RenderTextControlSingleLine::textBlockInsetRight() const
1128 {
1129     int inset = borderRight() + clientPaddingRight();
1130     if (HTMLElement* innerText = innerTextElement()) {
1131         if (RenderBox* innerTextRenderer = innerText->renderBox())
1132             inset += innerTextRenderer->paddingRight();
1133     }
1134     return inset;
1135 }
1136
1137 int RenderTextControlSingleLine::textBlockInsetTop() const
1138 {
1139     RenderBox* innerRenderer = 0;
1140     if (m_innerBlock)
1141         innerRenderer = m_innerBlock->renderBox();
1142     else if (HTMLElement* innerText = innerTextElement())
1143         innerRenderer = innerText->renderBox();
1144     
1145     if (innerRenderer)
1146         return innerRenderer->y();
1147     
1148     return borderTop() + paddingTop();
1149 }    
1150
1151 }