REGRESSION(r147602): Search text field doesn't render selection when it has some...
[WebKit-https.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 "CSSFontSelector.h"
28 #include "CSSValueKeywords.h"
29 #include "Chrome.h"
30 #include "Frame.h"
31 #include "FrameSelection.h"
32 #include "FrameView.h"
33 #include "HTMLNames.h"
34 #include "HitTestResult.h"
35 #include "LocalizedStrings.h"
36 #include "Page.h"
37 #include "PlatformKeyboardEvent.h"
38 #include "RenderLayer.h"
39 #include "RenderScrollbar.h"
40 #include "RenderTheme.h"
41 #include "Settings.h"
42 #include "SimpleFontData.h"
43 #include "StyleResolver.h"
44 #include "TextControlInnerElements.h"
45 #include <wtf/StackStats.h>
46
47 using namespace std;
48
49 namespace WebCore {
50
51 using namespace HTMLNames;
52
53 RenderTextControlSingleLine::RenderTextControlSingleLine(Element* element)
54     : RenderTextControl(element)
55     , m_shouldDrawCapsLockIndicator(false)
56     , m_desiredInnerTextLogicalHeight(-1)
57 {
58     ASSERT(element->isHTMLElement());
59     ASSERT(element->toInputElement());
60 }
61
62 RenderTextControlSingleLine::~RenderTextControlSingleLine()
63 {
64 }
65
66 inline HTMLElement* RenderTextControlSingleLine::innerSpinButtonElement() const
67 {
68     return inputElement()->innerSpinButtonElement();
69 }
70
71 RenderStyle* RenderTextControlSingleLine::textBaseStyle() const
72 {
73     HTMLElement* innerBlock = innerBlockElement();
74     return innerBlock ? innerBlock->renderer()->style() : style();
75 }
76
77 void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
78 {
79     RenderTextControl::paint(paintInfo, paintOffset);
80
81     if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
82         LayoutRect contentsRect = contentBoxRect();
83
84         // Center in the block progression direction.
85         if (isHorizontalWritingMode())
86             contentsRect.setY((height() - contentsRect.height()) / 2);
87         else
88             contentsRect.setX((width() - contentsRect.width()) / 2);
89
90         // Convert the rect into the coords used for painting the content
91         contentsRect.moveBy(paintOffset + location());
92         theme()->paintCapsLockIndicator(this, paintInfo, pixelSnappedIntRect(contentsRect));
93     }
94 }
95
96 LayoutUnit RenderTextControlSingleLine::computeLogicalHeightLimit() const
97 {
98     return containerElement() ? contentLogicalHeight() : logicalHeight();
99 }
100
101 void RenderTextControlSingleLine::layout()
102 {
103     StackStats::LayoutCheckPoint layoutCheckPoint;
104
105     // FIXME: We should remove the height-related hacks in layout() and
106     // styleDidChange(). We need them because
107     // - Center the inner elements vertically if the input height is taller than
108     //   the intrinsic height of the inner elements.
109     // - Shrink the inner elment heights if the input height is samller than the
110     //   intrinsic heights of the inner elements.
111
112     // We don't honor paddings and borders for textfields without decorations
113     // and type=search if the text height is taller than the contentHeight()
114     // because of compability.
115
116     RenderBox* innerTextRenderer = innerTextElement()->renderBox();
117     RenderBox* innerBlockRenderer = innerBlockElement() ? innerBlockElement()->renderBox() : 0;
118
119     // To ensure consistency between layouts, we need to reset any conditionally overriden height.
120     if (innerTextRenderer && !innerTextRenderer->style()->logicalHeight().isAuto()) {
121         innerTextRenderer->style()->setLogicalHeight(Length(Auto));
122         innerTextRenderer->setNeedsLayout(true, MarkOnlyThis);
123     }
124     if (innerBlockRenderer && !innerBlockRenderer->style()->logicalHeight().isAuto()) {
125         innerBlockRenderer->style()->setLogicalHeight(Length(Auto));
126         innerBlockRenderer->setNeedsLayout(true, MarkOnlyThis);
127     }
128
129     RenderBlock::layoutBlock(false);
130
131     HTMLElement* container = containerElement();
132     RenderBox* containerRenderer = container ? container->renderBox() : 0;
133
134     // Set the text block height
135     LayoutUnit desiredLogicalHeight = textBlockLogicalHeight();
136     LayoutUnit logicalHeightLimit = computeLogicalHeightLimit();
137     if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) {
138         if (desiredLogicalHeight != innerTextRenderer->logicalHeight())
139             setNeedsLayout(true, MarkOnlyThis);
140
141         m_desiredInnerTextLogicalHeight = desiredLogicalHeight;
142
143         innerTextRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed));
144         innerTextRenderer->setNeedsLayout(true, MarkOnlyThis);
145         if (innerBlockRenderer) {
146             innerBlockRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed));
147             innerBlockRenderer->setNeedsLayout(true, MarkOnlyThis);
148         }
149     }
150     // The container might be taller because of decoration elements.
151     if (containerRenderer) {
152         containerRenderer->layoutIfNeeded();
153         LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight();
154         if (containerLogicalHeight > logicalHeightLimit) {
155             containerRenderer->style()->setLogicalHeight(Length(logicalHeightLimit, Fixed));
156             setNeedsLayout(true, MarkOnlyThis);
157         } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) {
158             containerRenderer->style()->setLogicalHeight(Length(contentLogicalHeight(), Fixed));
159             setNeedsLayout(true, MarkOnlyThis);
160         } else
161             containerRenderer->style()->setLogicalHeight(Length(containerLogicalHeight, Fixed));
162     }
163
164     // If we need another layout pass, we have changed one of children's height so we need to relayout them.
165     if (needsLayout())
166         RenderBlock::layoutBlock(true);
167
168     // Center the child block in the block progression direction (vertical centering for horizontal text fields).
169     if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) {
170         LayoutUnit logicalHeightDiff = innerTextRenderer->logicalHeight() - contentLogicalHeight();
171         innerTextRenderer->setLogicalTop(innerTextRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2)));
172     } else
173         centerContainerIfNeeded(containerRenderer);
174
175     // Ignores the paddings for the inner spin button.
176     if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) {
177         RenderBox* parentBox = innerSpinBox->parentBox();
178         if (containerRenderer && !containerRenderer->style()->isLeftToRightDirection())
179             innerSpinBox->setLogicalLocation(LayoutPoint(-paddingLogicalLeft(), -paddingBefore()));
180         else
181             innerSpinBox->setLogicalLocation(LayoutPoint(parentBox->logicalWidth() - innerSpinBox->logicalWidth() + paddingLogicalRight(), -paddingBefore()));
182         innerSpinBox->setLogicalHeight(logicalHeight() - borderBefore() - borderAfter());
183     }
184
185     HTMLElement* placeholderElement = inputElement()->placeholderElement();
186     if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) {
187         LayoutSize innerTextSize;
188         if (innerTextRenderer)
189             innerTextSize = innerTextRenderer->size();
190         placeholderBox->style()->setWidth(Length(innerTextSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed));
191         placeholderBox->style()->setHeight(Length(innerTextSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed));
192         bool neededLayout = placeholderBox->needsLayout();
193         bool placeholderBoxHadLayout = placeholderBox->everHadLayout();
194         placeholderBox->layoutIfNeeded();
195         LayoutPoint textOffset;
196         if (innerTextRenderer)
197             textOffset = innerTextRenderer->location();
198         if (innerBlockElement() && innerBlockElement()->renderBox())
199             textOffset += toLayoutSize(innerBlockElement()->renderBox()->location());
200         if (containerRenderer)
201             textOffset += toLayoutSize(containerRenderer->location());
202         placeholderBox->setLocation(textOffset);
203
204         if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) {
205             // This assumes a shadow tree without floats. If floats are added, the
206             // logic should be shared with RenderBlock::layoutBlockChild.
207             placeholderBox->repaint();
208         }
209         // The placeholder gets layout last, after the parent text control and its other children,
210         // so in order to get the correct overflow from the placeholder we need to recompute it now.
211         if (neededLayout)
212             computeOverflow(clientLogicalBottom());
213     }
214 }
215
216 bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
217 {
218     if (!RenderTextControl::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction))
219         return false;
220
221     // Say that we hit the inner text element if
222     //  - we hit a node inside the inner text element,
223     //  - we hit the <input> element (e.g. we're over the border or padding), or
224     //  - we hit regions not in any decoration buttons.
225     HTMLElement* container = containerElement();
226     if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node() || (container && container == result.innerNode())) {
227         LayoutPoint pointInParent = locationInContainer.point();
228         if (container && innerBlockElement()) {
229             if (innerBlockElement()->renderBox())
230                 pointInParent -= toLayoutSize(innerBlockElement()->renderBox()->location());
231             if (container->renderBox())
232                 pointInParent -= toLayoutSize(container->renderBox()->location());
233         }
234         hitInnerTextElement(result, pointInParent, accumulatedOffset);
235     }
236     return true;
237 }
238
239 void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
240 {
241     m_desiredInnerTextLogicalHeight = -1;
242     RenderTextControl::styleDidChange(diff, oldStyle);
243
244     // We may have set the width and the height in the old style in layout().
245     // Reset them now to avoid getting a spurious layout hint.
246     HTMLElement* innerBlock = innerBlockElement();
247     if (RenderObject* innerBlockRenderer = innerBlock ? innerBlock->renderer() : 0) {
248         innerBlockRenderer->style()->setHeight(Length());
249         innerBlockRenderer->style()->setWidth(Length());
250     }
251     HTMLElement* container = containerElement();
252     if (RenderObject* containerRenderer = container ? container->renderer() : 0) {
253         containerRenderer->style()->setHeight(Length());
254         containerRenderer->style()->setWidth(Length());
255     }
256     RenderObject* innerTextRenderer = innerTextElement()->renderer();
257     if (innerTextRenderer && diff == StyleDifferenceLayout)
258         innerTextRenderer->setNeedsLayout(true, MarkContainingBlockChain);
259     if (HTMLElement* placeholder = inputElement()->placeholderElement())
260         placeholder->setInlineStyleProperty(CSSPropertyTextOverflow, textShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip);
261     setHasOverflowClip(false);
262 }
263
264 void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
265 {
266     if (!node() || !document())
267         return;
268
269     // Only draw the caps lock indicator if these things are true:
270     // 1) The field is a password field
271     // 2) The frame is active
272     // 3) The element is focused
273     // 4) The caps lock is on
274     bool shouldDrawCapsLockIndicator = false;
275
276     if (Frame* frame = document()->frame())
277         shouldDrawCapsLockIndicator = inputElement()->isPasswordField()
278                                       && frame->selection()->isFocusedAndActive()
279                                       && document()->focusedElement() == node()
280                                       && PlatformKeyboardEvent::currentCapsLockState();
281
282     if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
283         m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
284         repaint();
285     }
286 }
287
288 bool RenderTextControlSingleLine::hasControlClip() const
289 {
290     // Apply control clip for text fields with decorations.
291     return !!containerElement();
292 }
293
294 LayoutRect RenderTextControlSingleLine::controlClipRect(const LayoutPoint& additionalOffset) const
295 {
296     ASSERT(hasControlClip());
297     LayoutRect clipRect = contentBoxRect();
298     if (containerElement()->renderBox())
299         clipRect = unionRect(clipRect, containerElement()->renderBox()->frameRect());
300     clipRect.moveBy(additionalOffset);
301     return clipRect;
302 }
303
304 float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family)
305 {
306     // Since Lucida Grande is the default font, we want this to match the width
307     // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
308     // IE for some encodings (in IE, the default font is encoding specific).
309     // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg.
310     if (family == "Lucida Grande")
311         return scaleEmToUnits(901);
312
313     return RenderTextControl::getAvgCharWidth(family);
314 }
315
316 LayoutUnit RenderTextControlSingleLine::preferredContentLogicalWidth(float charWidth) const
317 {
318     int factor;
319     bool includesDecoration = inputElement()->sizeShouldIncludeDecoration(factor);
320     if (factor <= 0)
321         factor = 20;
322
323     LayoutUnit result = static_cast<LayoutUnit>(ceiledLayoutUnit(charWidth * factor));
324
325     float maxCharWidth = 0.f;
326     const AtomicString& family = style()->font().firstFamily();
327     // Since Lucida Grande is the default font, we want this to match the width
328     // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
329     // IE for some encodings (in IE, the default font is encoding specific).
330     // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg.
331     if (family == "Lucida Grande")
332         maxCharWidth = scaleEmToUnits(4027);
333     else if (hasValidAvgCharWidth(family))
334         maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth());
335
336     // For text inputs, IE adds some extra width.
337     if (maxCharWidth > 0.f)
338         result += maxCharWidth - charWidth;
339
340     if (includesDecoration) {
341         HTMLElement* spinButton = innerSpinButtonElement();
342         if (RenderBox* spinRenderer = spinButton ? spinButton->renderBox() : 0) {
343             result += spinRenderer->borderAndPaddingLogicalWidth();
344             // Since the width of spinRenderer is not calculated yet, spinRenderer->logicalWidth() returns 0.
345             // So computedStyle()->logicalWidth() is used instead.
346             result += spinButton->computedStyle()->logicalWidth().value();
347         }
348     }
349
350     return result;
351 }
352
353 LayoutUnit RenderTextControlSingleLine::computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
354 {
355     return lineHeight + nonContentHeight;
356 }
357
358 void RenderTextControlSingleLine::updateFromElement()
359 {
360     RenderTextControl::updateFromElement();
361 }
362
363 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
364 {
365     RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();   
366     textBlockStyle->inheritFrom(startStyle);
367     adjustInnerTextStyle(startStyle, textBlockStyle.get());
368
369     textBlockStyle->setWhiteSpace(PRE);
370     textBlockStyle->setOverflowWrap(NormalOverflowWrap);
371     textBlockStyle->setOverflowX(OHIDDEN);
372     textBlockStyle->setOverflowY(OHIDDEN);
373     textBlockStyle->setTextOverflow(textShouldBeTruncated() ? TextOverflowEllipsis : TextOverflowClip);
374
375     if (m_desiredInnerTextLogicalHeight >= 0)
376         textBlockStyle->setLogicalHeight(Length(m_desiredInnerTextLogicalHeight, Fixed));
377     // Do not allow line-height to be smaller than our default.
378     if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
379         textBlockStyle->setLineHeight(RenderStyle::initialLineHeight());
380
381     textBlockStyle->setDisplay(BLOCK);
382
383     return textBlockStyle.release();
384 }
385
386 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
387 {
388     RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
389     innerBlockStyle->inheritFrom(startStyle);
390
391     innerBlockStyle->setFlexGrow(1);
392     // min-width: 0; is needed for correct shrinking.
393     // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
394     innerBlockStyle->setMinWidth(Length(0, Fixed));
395     innerBlockStyle->setDisplay(BLOCK);
396     innerBlockStyle->setDirection(LTR);
397
398     // 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.
399     innerBlockStyle->setUserModify(READ_ONLY);
400
401     return innerBlockStyle.release();
402 }
403
404 bool RenderTextControlSingleLine::textShouldBeTruncated() const
405 {
406     return document()->focusedElement() != node()
407         && style()->textOverflow() == TextOverflowEllipsis;
408 }
409
410 void RenderTextControlSingleLine::autoscroll(const IntPoint& position)
411 {
412     RenderBox* renderer = innerTextElement()->renderBox();
413     if (!renderer)
414         return;
415     RenderLayer* layer = renderer->layer();
416     if (layer)
417         layer->autoscroll(position);
418 }
419
420 int RenderTextControlSingleLine::scrollWidth() const
421 {
422     if (innerTextElement())
423         return innerTextElement()->scrollWidth();
424     return RenderBlock::scrollWidth();
425 }
426
427 int RenderTextControlSingleLine::scrollHeight() const
428 {
429     if (innerTextElement())
430         return innerTextElement()->scrollHeight();
431     return RenderBlock::scrollHeight();
432 }
433
434 int RenderTextControlSingleLine::scrollLeft() const
435 {
436     if (innerTextElement())
437         return innerTextElement()->scrollLeft();
438     return RenderBlock::scrollLeft();
439 }
440
441 int RenderTextControlSingleLine::scrollTop() const
442 {
443     if (innerTextElement())
444         return innerTextElement()->scrollTop();
445     return RenderBlock::scrollTop();
446 }
447
448 void RenderTextControlSingleLine::setScrollLeft(int newLeft)
449 {
450     if (innerTextElement())
451         innerTextElement()->setScrollLeft(newLeft);
452 }
453
454 void RenderTextControlSingleLine::setScrollTop(int newTop)
455 {
456     if (innerTextElement())
457         innerTextElement()->setScrollTop(newTop);
458 }
459
460 bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
461 {
462     RenderBox* renderer = innerTextElement()->renderBox();
463     if (!renderer)
464         return false;
465     RenderLayer* layer = renderer->layer();
466     if (layer && layer->scroll(direction, granularity, multiplier))
467         return true;
468     return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
469 }
470
471 bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
472 {
473     RenderLayer* layer = innerTextElement()->renderBox()->layer();
474     if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
475         return true;
476     return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
477 }
478
479 HTMLInputElement* RenderTextControlSingleLine::inputElement() const
480 {
481     return node()->toInputElement();
482 }
483
484 }