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