Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / RenderTextControl.cpp
1 /**
2  * Copyright (C) 2006, 2007, 2014 Apple Inc. All rights reserved.
3  *           (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)  
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #include "config.h"
23 #include "RenderTextControl.h"
24
25 #include "CSSPrimitiveValueMappings.h"
26 #include "HTMLTextFormControlElement.h"
27 #include "HitTestResult.h"
28 #include "RenderText.h"
29 #include "RenderTextControlSingleLine.h"
30 #include "RenderTheme.h"
31 #include "ScrollbarTheme.h"
32 #include "StyleInheritedData.h"
33 #include "StyleProperties.h"
34 #include "TextControlInnerElements.h"
35 #include "VisiblePosition.h"
36 #include <wtf/unicode/CharacterNames.h>
37
38 namespace WebCore {
39
40 RenderTextControl::RenderTextControl(HTMLTextFormControlElement& element, Ref<RenderStyle>&& style)
41     : RenderBlockFlow(element, WTFMove(style))
42 {
43 }
44
45 RenderTextControl::~RenderTextControl()
46 {
47 }
48
49 HTMLTextFormControlElement& RenderTextControl::textFormControlElement() const
50 {
51     return downcast<HTMLTextFormControlElement>(nodeForNonAnonymous());
52 }
53
54 TextControlInnerTextElement* RenderTextControl::innerTextElement() const
55 {
56     return textFormControlElement().innerTextElement();
57 }
58
59 void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
60 {
61     RenderBlockFlow::styleDidChange(diff, oldStyle);
62     TextControlInnerTextElement* innerText = innerTextElement();
63     if (!innerText)
64         return;
65     RenderTextControlInnerBlock* innerTextRenderer = innerText->renderer();
66     if (innerTextRenderer) {
67         // We may have set the width and the height in the old style in layout().
68         // Reset them now to avoid getting a spurious layout hint.
69         innerTextRenderer->style().setHeight(Length());
70         innerTextRenderer->style().setWidth(Length());
71         innerTextRenderer->setStyle(createInnerTextStyle(&style()));
72     }
73     textFormControlElement().updatePlaceholderVisibility();
74 }
75
76 void RenderTextControl::adjustInnerTextStyle(const RenderStyle* startStyle, RenderStyle& textBlockStyle) const
77 {
78     // The inner block, if present, always has its direction set to LTR,
79     // so we need to inherit the direction and unicode-bidi style from the element.
80     textBlockStyle.setDirection(style().direction());
81     textBlockStyle.setUnicodeBidi(style().unicodeBidi());
82
83     HTMLTextFormControlElement& control = textFormControlElement();
84     if (HTMLElement* innerText = control.innerTextElement()) {
85         if (const StyleProperties* properties = innerText->presentationAttributeStyle()) {
86             RefPtr<CSSValue> value = properties->getPropertyCSSValue(CSSPropertyWebkitUserModify);
87             if (is<CSSPrimitiveValue>(value.get()))
88                 textBlockStyle.setUserModify(downcast<CSSPrimitiveValue>(*value));
89         }
90     }
91
92     if (control.isDisabledFormControl())
93         textBlockStyle.setColor(theme().disabledTextColor(textBlockStyle.visitedDependentColor(CSSPropertyColor), startStyle->visitedDependentColor(CSSPropertyBackgroundColor)));
94 #if PLATFORM(IOS)
95     if (textBlockStyle.textSecurity() != TSNONE && !textBlockStyle.isLeftToRightDirection()) {
96         // Preserve the alignment but force the direction to LTR so that the last-typed, unmasked character
97         // (which cannot have RTL directionality) will appear to the right of the masked characters. See <rdar://problem/7024375>.
98         
99         switch (textBlockStyle.textAlign()) {
100         case TASTART:
101         case JUSTIFY:
102             textBlockStyle.setTextAlign(RIGHT);
103             break;
104         case TAEND:
105             textBlockStyle.setTextAlign(LEFT);
106             break;
107         case LEFT:
108         case RIGHT:
109         case CENTER:
110         case WEBKIT_LEFT:
111         case WEBKIT_RIGHT:
112         case WEBKIT_CENTER:
113             break;
114         }
115
116         textBlockStyle.setDirection(LTR);
117     }
118 #endif
119 }
120
121 int RenderTextControl::textBlockLogicalHeight() const
122 {
123     return logicalHeight() - borderAndPaddingLogicalHeight();
124 }
125
126 int RenderTextControl::textBlockLogicalWidth() const
127 {
128     TextControlInnerTextElement* innerText = innerTextElement();
129     ASSERT(innerText);
130
131     LayoutUnit unitWidth = logicalWidth() - borderAndPaddingLogicalWidth();
132     if (innerText->renderer())
133         unitWidth -= innerText->renderBox()->paddingStart() + innerText->renderBox()->paddingEnd();
134
135     return unitWidth;
136 }
137
138 int RenderTextControl::scrollbarThickness() const
139 {
140     // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
141     return ScrollbarTheme::theme().scrollbarThickness();
142 }
143
144 void RenderTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
145 {
146     TextControlInnerTextElement* innerText = innerTextElement();
147     ASSERT(innerText);
148     if (RenderBox* innerTextBox = innerText->renderBox()) {
149         LayoutUnit nonContentHeight = innerTextBox->verticalBorderAndPaddingExtent() + innerTextBox->verticalMarginExtent();
150         logicalHeight = computeControlLogicalHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + verticalBorderAndPaddingExtent();
151
152         // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
153         if ((isHorizontalWritingMode() && (style().overflowX() == OSCROLL ||  (style().overflowX() == OAUTO && innerText->renderer()->style().overflowWrap() == NormalOverflowWrap)))
154             || (!isHorizontalWritingMode() && (style().overflowY() == OSCROLL ||  (style().overflowY() == OAUTO && innerText->renderer()->style().overflowWrap() == NormalOverflowWrap))))
155             logicalHeight += scrollbarThickness();
156     }
157
158     RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
159 }
160
161 void RenderTextControl::hitInnerTextElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
162 {
163     TextControlInnerTextElement* innerText = innerTextElement();
164     if (!innerText->renderer())
165         return;
166
167     LayoutPoint adjustedLocation = accumulatedOffset + location();
168     LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerText->renderBox()->location()) + scrolledContentOffset();
169     result.setInnerNode(innerText);
170     result.setInnerNonSharedNode(innerText);
171     result.setLocalPoint(localPoint);
172 }
173
174 float RenderTextControl::getAverageCharWidth()
175 {
176     float width;
177     if (style().fontCascade().fastAverageCharWidthIfAvailable(width))
178         return width;
179
180     const UChar ch = '0';
181     const String str = String(&ch, 1);
182     const FontCascade& font = style().fontCascade();
183     TextRun textRun = constructTextRun(this, font, str, style(), AllowTrailingExpansion);
184     textRun.disableRoundingHacks();
185     return font.width(textRun);
186 }
187
188 float RenderTextControl::scaleEmToUnits(int x) const
189 {
190     // This matches the unitsPerEm value for MS Shell Dlg and Courier New from the "head" font table.
191     float unitsPerEm = 2048.0f;
192     return roundf(style().fontCascade().size() * x / unitsPerEm);
193 }
194
195 void RenderTextControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
196 {
197     // Use average character width. Matches IE.
198     maxLogicalWidth = preferredContentLogicalWidth(const_cast<RenderTextControl*>(this)->getAverageCharWidth());
199     if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox())
200         maxLogicalWidth += innerTextRenderBox->paddingStart() + innerTextRenderBox->paddingEnd();
201     if (!style().logicalWidth().isPercentOrCalculated())
202         minLogicalWidth = maxLogicalWidth;
203 }
204
205 void RenderTextControl::computePreferredLogicalWidths()
206 {
207     ASSERT(preferredLogicalWidthsDirty());
208
209     m_minPreferredLogicalWidth = 0;
210     m_maxPreferredLogicalWidth = 0;
211
212     if (style().logicalWidth().isFixed() && style().logicalWidth().value() >= 0)
213         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style().logicalWidth().value());
214     else
215         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
216
217     if (style().logicalMinWidth().isFixed() && style().logicalMinWidth().value() > 0) {
218         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMinWidth().value()));
219         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMinWidth().value()));
220     }
221
222     if (style().logicalMaxWidth().isFixed()) {
223         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMaxWidth().value()));
224         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMaxWidth().value()));
225     }
226
227     LayoutUnit toAdd = borderAndPaddingLogicalWidth();
228
229     m_minPreferredLogicalWidth += toAdd;
230     m_maxPreferredLogicalWidth += toAdd;
231
232     setPreferredLogicalWidthsDirty(false);
233 }
234
235 void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
236 {
237     if (!size().isEmpty())
238         rects.append(snappedIntRect(additionalOffset, size()));
239 }
240
241 RenderObject* RenderTextControl::layoutSpecialExcludedChild(bool relayoutChildren)
242 {
243     HTMLElement* placeholder = textFormControlElement().placeholderElement();
244     RenderElement* placeholderRenderer = placeholder ? placeholder->renderer() : 0;
245     if (!placeholderRenderer)
246         return 0;
247     if (relayoutChildren) {
248         // The markParents arguments should be false because this function is
249         // called from layout() of the parent and the placeholder layout doesn't
250         // affect the parent layout.
251         placeholderRenderer->setChildNeedsLayout(MarkOnlyThis);
252     }
253     return placeholderRenderer;
254 }
255
256 #if PLATFORM(IOS)
257 bool RenderTextControl::canScroll() const
258 {
259     Element* innerText = innerTextElement();
260     return innerText && innerText->renderer() && innerText->renderer()->hasOverflowClip();
261 }
262
263 int RenderTextControl::innerLineHeight() const
264 {
265     Element* innerText = innerTextElement();
266     if (innerText && innerText->renderer())
267         return innerText->renderer()->style().computedLineHeight();
268     return style().computedLineHeight();
269 }
270 #endif
271
272 } // namespace WebCore