7b1a1695f20894534f2554f81f0c8d26db63251a
[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 "HTMLTextFormControlElement.h"
26 #include "HitTestResult.h"
27 #include "RenderText.h"
28 #include "RenderTextControlSingleLine.h"
29 #include "RenderTheme.h"
30 #include "ScrollbarTheme.h"
31 #include "StyleInheritedData.h"
32 #include "StyleProperties.h"
33 #include "TextControlInnerElements.h"
34 #include "VisiblePosition.h"
35 #include <wtf/unicode/CharacterNames.h>
36
37 namespace WebCore {
38
39 RenderTextControl::RenderTextControl(HTMLTextFormControlElement& element, RenderStyle&& style)
40     : RenderBlockFlow(element, WTFMove(style))
41 {
42 }
43
44 RenderTextControl::~RenderTextControl()
45 {
46 }
47
48 HTMLTextFormControlElement& RenderTextControl::textFormControlElement() const
49 {
50     return downcast<HTMLTextFormControlElement>(nodeForNonAnonymous());
51 }
52
53 RefPtr<TextControlInnerTextElement> RenderTextControl::innerTextElement() const
54 {
55     return textFormControlElement().innerTextElement();
56 }
57
58 void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
59 {
60     RenderBlockFlow::styleDidChange(diff, oldStyle);
61     auto innerText = innerTextElement();
62     if (!innerText)
63         return;
64     RenderTextControlInnerBlock* innerTextRenderer = innerText->renderer();
65     if (innerTextRenderer) {
66         // We may have set the width and the height in the old style in layout().
67         // Reset them now to avoid getting a spurious layout hint.
68         innerTextRenderer->mutableStyle().setHeight(Length());
69         innerTextRenderer->mutableStyle().setWidth(Length());
70         innerTextRenderer->setStyle(textFormControlElement().createInnerTextStyle(style()));
71     }
72     textFormControlElement().updatePlaceholderVisibility();
73 }
74
75 int RenderTextControl::textBlockLogicalHeight() const
76 {
77     return logicalHeight() - borderAndPaddingLogicalHeight();
78 }
79
80 int RenderTextControl::textBlockLogicalWidth() const
81 {
82     auto innerText = innerTextElement();
83     ASSERT(innerText);
84
85     LayoutUnit unitWidth = logicalWidth() - borderAndPaddingLogicalWidth();
86     if (innerText->renderer())
87         unitWidth -= innerText->renderBox()->paddingStart() + innerText->renderBox()->paddingEnd();
88
89     return unitWidth;
90 }
91
92 int RenderTextControl::scrollbarThickness() const
93 {
94     // FIXME: We should get the size of the scrollbar from the RenderTheme instead.
95     return ScrollbarTheme::theme().scrollbarThickness();
96 }
97
98 RenderBox::LogicalExtentComputedValues RenderTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const
99 {
100     auto innerText = innerTextElement();
101     ASSERT(innerText);
102     if (RenderBox* innerTextBox = innerText->renderBox()) {
103         LayoutUnit nonContentHeight = innerTextBox->verticalBorderAndPaddingExtent() + innerTextBox->verticalMarginExtent();
104         logicalHeight = computeControlLogicalHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight);
105
106         // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap.
107         if ((isHorizontalWritingMode() && (style().overflowX() == OSCROLL ||  (style().overflowX() == OAUTO && innerText->renderer()->style().overflowWrap() == NormalOverflowWrap)))
108             || (!isHorizontalWritingMode() && (style().overflowY() == OSCROLL ||  (style().overflowY() == OAUTO && innerText->renderer()->style().overflowWrap() == NormalOverflowWrap))))
109             logicalHeight += scrollbarThickness();
110         
111         // FIXME: The logical height of the inner text box should have been added
112         // before calling computeLogicalHeight to avoid this hack.
113         cacheIntrinsicContentLogicalHeightForFlexItem(logicalHeight);
114         
115         logicalHeight += verticalBorderAndPaddingExtent();
116     }
117
118     return RenderBox::computeLogicalHeight(logicalHeight, logicalTop);
119 }
120
121 void RenderTextControl::hitInnerTextElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
122 {
123     auto innerText = innerTextElement();
124     if (!innerText->renderer())
125         return;
126
127     LayoutPoint adjustedLocation = accumulatedOffset + location();
128     LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerText->renderBox()->location()) + toLayoutSize(scrollPosition());
129     result.setInnerNode(innerText.get());
130     result.setInnerNonSharedNode(innerText.get());
131     result.setLocalPoint(localPoint);
132 }
133
134 float RenderTextControl::getAverageCharWidth()
135 {
136     float width;
137     if (style().fontCascade().fastAverageCharWidthIfAvailable(width))
138         return width;
139
140     const UChar ch = '0';
141     const String str = String(&ch, 1);
142     const FontCascade& font = style().fontCascade();
143     TextRun textRun = constructTextRun(str, style(), AllowTrailingExpansion);
144     return font.width(textRun);
145 }
146
147 float RenderTextControl::scaleEmToUnits(int x) const
148 {
149     // This matches the unitsPerEm value for MS Shell Dlg and Courier New from the "head" font table.
150     float unitsPerEm = 2048.0f;
151     return roundf(style().fontCascade().size() * x / unitsPerEm);
152 }
153
154 void RenderTextControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
155 {
156     // Use average character width. Matches IE.
157     maxLogicalWidth = preferredContentLogicalWidth(const_cast<RenderTextControl*>(this)->getAverageCharWidth());
158     if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox())
159         maxLogicalWidth += innerTextRenderBox->paddingStart() + innerTextRenderBox->paddingEnd();
160     if (!style().logicalWidth().isPercentOrCalculated())
161         minLogicalWidth = maxLogicalWidth;
162 }
163
164 void RenderTextControl::computePreferredLogicalWidths()
165 {
166     ASSERT(preferredLogicalWidthsDirty());
167
168     m_minPreferredLogicalWidth = 0;
169     m_maxPreferredLogicalWidth = 0;
170
171     if (style().logicalWidth().isFixed() && style().logicalWidth().value() >= 0)
172         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style().logicalWidth().value());
173     else
174         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
175
176     if (style().logicalMinWidth().isFixed() && style().logicalMinWidth().value() > 0) {
177         m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMinWidth().value()));
178         m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMinWidth().value()));
179     }
180
181     if (style().logicalMaxWidth().isFixed()) {
182         m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMaxWidth().value()));
183         m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style().logicalMaxWidth().value()));
184     }
185
186     LayoutUnit toAdd = borderAndPaddingLogicalWidth();
187
188     m_minPreferredLogicalWidth += toAdd;
189     m_maxPreferredLogicalWidth += toAdd;
190
191     setPreferredLogicalWidthsDirty(false);
192 }
193
194 void RenderTextControl::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
195 {
196     if (!size().isEmpty())
197         rects.append(LayoutRect(additionalOffset, size()));
198 }
199
200 void RenderTextControl::layoutExcludedChildren(bool relayoutChildren)
201 {
202     RenderBlockFlow::layoutExcludedChildren(relayoutChildren);
203
204     HTMLElement* placeholder = textFormControlElement().placeholderElement();
205     RenderElement* placeholderRenderer = placeholder ? placeholder->renderer() : 0;
206     if (!placeholderRenderer)
207         return;
208     placeholderRenderer->setIsExcludedFromNormalLayout(true);
209
210     if (relayoutChildren) {
211         // The markParents arguments should be false because this function is
212         // called from layout() of the parent and the placeholder layout doesn't
213         // affect the parent layout.
214         placeholderRenderer->setChildNeedsLayout(MarkOnlyThis);
215     }
216 }
217
218 #if PLATFORM(IOS)
219 bool RenderTextControl::canScroll() const
220 {
221     auto innerText = innerTextElement();
222     return innerText && innerText->renderer() && innerText->renderer()->hasOverflowClip();
223 }
224
225 int RenderTextControl::innerLineHeight() const
226 {
227     auto innerText = innerTextElement();
228     if (innerText && innerText->renderer())
229         return innerText->renderer()->style().computedLineHeight();
230     return style().computedLineHeight();
231 }
232 #endif
233
234 } // namespace WebCore