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