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