OLD | NEW |
| (Empty) |
1 /** | |
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. | |
3 * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmo
bile.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 "core/rendering/RenderTextControl.h" | |
24 | |
25 #include "core/html/HTMLTextFormControlElement.h" | |
26 #include "core/layout/HitTestResult.h" | |
27 #include "core/layout/LayoutTheme.h" | |
28 #include "core/layout/TextRunConstructor.h" | |
29 #include "platform/scroll/ScrollbarTheme.h" | |
30 #include "wtf/unicode/CharacterNames.h" | |
31 | |
32 namespace blink { | |
33 | |
34 RenderTextControl::RenderTextControl(HTMLTextFormControlElement* element) | |
35 : RenderBlockFlow(element) | |
36 { | |
37 ASSERT(element); | |
38 } | |
39 | |
40 RenderTextControl::~RenderTextControl() | |
41 { | |
42 } | |
43 | |
44 HTMLTextFormControlElement* RenderTextControl::textFormControlElement() const | |
45 { | |
46 return toHTMLTextFormControlElement(node()); | |
47 } | |
48 | |
49 HTMLElement* RenderTextControl::innerEditorElement() const | |
50 { | |
51 return textFormControlElement()->innerEditorElement(); | |
52 } | |
53 | |
54 void RenderTextControl::addChild(LayoutObject* newChild, LayoutObject* beforeChi
ld) | |
55 { | |
56 // FIXME: This is a terrible hack to get the caret over the placeholder text
since it'll | |
57 // make us paint the placeholder first. (See https://trac.webkit.org/changes
et/118733) | |
58 Node* node = newChild->node(); | |
59 if (node && node->isElementNode() && toElement(node)->shadowPseudoId() == "-
webkit-input-placeholder") | |
60 RenderBlockFlow::addChild(newChild, firstChild()); | |
61 else | |
62 RenderBlockFlow::addChild(newChild, beforeChild); | |
63 } | |
64 | |
65 void RenderTextControl::styleDidChange(StyleDifference diff, const LayoutStyle*
oldStyle) | |
66 { | |
67 RenderBlockFlow::styleDidChange(diff, oldStyle); | |
68 Element* innerEditor = innerEditorElement(); | |
69 if (!innerEditor) | |
70 return; | |
71 RenderBlock* innerEditorRenderer = toRenderBlock(innerEditor->renderer()); | |
72 if (innerEditorRenderer) { | |
73 // We may have set the width and the height in the old style in layout()
. | |
74 // Reset them now to avoid getting a spurious layout hint. | |
75 innerEditorRenderer->style()->setHeight(Length()); | |
76 innerEditorRenderer->style()->setWidth(Length()); | |
77 innerEditorRenderer->setStyle(createInnerEditorStyle(styleRef())); | |
78 innerEditor->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonFo
rTracing::create(StyleChangeReason::Control)); | |
79 } | |
80 textFormControlElement()->updatePlaceholderVisibility(false); | |
81 } | |
82 | |
83 static inline void updateUserModifyProperty(HTMLTextFormControlElement& node, La
youtStyle& style) | |
84 { | |
85 style.setUserModify(node.isDisabledOrReadOnly() ? READ_ONLY : READ_WRITE_PLA
INTEXT_ONLY); | |
86 } | |
87 | |
88 void RenderTextControl::adjustInnerEditorStyle(LayoutStyle& textBlockStyle) cons
t | |
89 { | |
90 // The inner block, if present, always has its direction set to LTR, | |
91 // so we need to inherit the direction and unicode-bidi style from the eleme
nt. | |
92 textBlockStyle.setDirection(style()->direction()); | |
93 textBlockStyle.setUnicodeBidi(style()->unicodeBidi()); | |
94 | |
95 updateUserModifyProperty(*textFormControlElement(), textBlockStyle); | |
96 } | |
97 | |
98 int RenderTextControl::textBlockLogicalHeight() const | |
99 { | |
100 return logicalHeight() - borderAndPaddingLogicalHeight(); | |
101 } | |
102 | |
103 int RenderTextControl::textBlockLogicalWidth() const | |
104 { | |
105 Element* innerEditor = innerEditorElement(); | |
106 ASSERT(innerEditor); | |
107 | |
108 LayoutUnit unitWidth = logicalWidth() - borderAndPaddingLogicalWidth(); | |
109 if (innerEditor->renderer()) | |
110 unitWidth -= innerEditor->renderBox()->paddingStart() + innerEditor->ren
derBox()->paddingEnd(); | |
111 | |
112 return unitWidth; | |
113 } | |
114 | |
115 void RenderTextControl::updateFromElement() | |
116 { | |
117 Element* innerEditor = innerEditorElement(); | |
118 if (innerEditor && innerEditor->renderer()) | |
119 updateUserModifyProperty(*textFormControlElement(), innerEditor->rendere
r()->mutableStyleRef()); | |
120 } | |
121 | |
122 int RenderTextControl::scrollbarThickness() const | |
123 { | |
124 // FIXME: We should get the size of the scrollbar from the LayoutTheme inste
ad. | |
125 return ScrollbarTheme::theme()->scrollbarThickness(); | |
126 } | |
127 | |
128 void RenderTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUni
t logicalTop, LogicalExtentComputedValues& computedValues) const | |
129 { | |
130 HTMLElement* innerEditor = innerEditorElement(); | |
131 ASSERT(innerEditor); | |
132 if (RenderBox* innerEditorBox = innerEditor->renderBox()) { | |
133 LayoutUnit nonContentHeight = innerEditorBox->borderAndPaddingHeight() +
innerEditorBox->marginHeight(); | |
134 logicalHeight = computeControlLogicalHeight(innerEditorBox->lineHeight(t
rue, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight); | |
135 | |
136 // We are able to have a horizontal scrollbar if the overflow style is s
croll, or if its auto and there's no word wrap. | |
137 if ((isHorizontalWritingMode() && (style()->overflowX() == OSCROLL || (
style()->overflowX() == OAUTO && innerEditor->renderer()->style()->overflowWrap(
) == NormalOverflowWrap))) | |
138 || (!isHorizontalWritingMode() && (style()->overflowY() == OSCROLL |
| (style()->overflowY() == OAUTO && innerEditor->renderer()->style()->overflowW
rap() == NormalOverflowWrap)))) | |
139 logicalHeight += scrollbarThickness(); | |
140 | |
141 // FIXME: The logical height of the inner text box should have been adde
d before calling computeLogicalHeight to | |
142 // avoid this hack. | |
143 setIntrinsicContentLogicalHeight(logicalHeight); | |
144 | |
145 logicalHeight += borderAndPaddingHeight(); | |
146 } | |
147 | |
148 RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues); | |
149 } | |
150 | |
151 void RenderTextControl::hitInnerEditorElement(HitTestResult& result, const Layou
tPoint& pointInContainer, const LayoutPoint& accumulatedOffset) | |
152 { | |
153 HTMLElement* innerEditor = innerEditorElement(); | |
154 if (!innerEditor->renderer()) | |
155 return; | |
156 | |
157 LayoutPoint adjustedLocation = accumulatedOffset + location(); | |
158 LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation +
innerEditor->renderBox()->location()); | |
159 if (hasOverflowClip()) | |
160 localPoint += scrolledContentOffset(); | |
161 result.setInnerNode(innerEditor); | |
162 result.setInnerNonSharedNode(innerEditor); | |
163 result.setLocalPoint(localPoint); | |
164 } | |
165 | |
166 static const char* const fontFamiliesWithInvalidCharWidth[] = { | |
167 "American Typewriter", | |
168 "Arial Hebrew", | |
169 "Chalkboard", | |
170 "Cochin", | |
171 "Corsiva Hebrew", | |
172 "Courier", | |
173 "Euphemia UCAS", | |
174 "Geneva", | |
175 "Gill Sans", | |
176 "Hei", | |
177 "Helvetica", | |
178 "Hoefler Text", | |
179 "InaiMathi", | |
180 "Kai", | |
181 "Lucida Grande", | |
182 "Marker Felt", | |
183 "Monaco", | |
184 "Mshtakan", | |
185 "New Peninim MT", | |
186 "Osaka", | |
187 "Raanana", | |
188 "STHeiti", | |
189 "Symbol", | |
190 "Times", | |
191 "Apple Braille", | |
192 "Apple LiGothic", | |
193 "Apple LiSung", | |
194 "Apple Symbols", | |
195 "AppleGothic", | |
196 "AppleMyungjo", | |
197 "#GungSeo", | |
198 "#HeadLineA", | |
199 "#PCMyungjo", | |
200 "#PilGi", | |
201 }; | |
202 | |
203 // For font families where any of the fonts don't have a valid entry in the OS/2
table | |
204 // for avgCharWidth, fallback to the legacy webkit behavior of getting the avgCh
arWidth | |
205 // from the width of a '0'. This only seems to apply to a fixed number of Mac fo
nts, | |
206 // but, in order to get similar rendering across platforms, we do this check for | |
207 // all platforms. | |
208 bool RenderTextControl::hasValidAvgCharWidth(AtomicString family) | |
209 { | |
210 static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0; | |
211 | |
212 if (family.isEmpty()) | |
213 return false; | |
214 | |
215 if (!fontFamiliesWithInvalidCharWidthMap) { | |
216 fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>; | |
217 | |
218 for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontFamiliesWithInvalidCharWidth
); ++i) | |
219 fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWi
thInvalidCharWidth[i])); | |
220 } | |
221 | |
222 return !fontFamiliesWithInvalidCharWidthMap->contains(family); | |
223 } | |
224 | |
225 float RenderTextControl::getAvgCharWidth(AtomicString family) | |
226 { | |
227 if (hasValidAvgCharWidth(family)) | |
228 return roundf(style()->font().primaryFont()->avgCharWidth()); | |
229 | |
230 const UChar ch = '0'; | |
231 const String str = String(&ch, 1); | |
232 const Font& font = style()->font(); | |
233 TextRun textRun = constructTextRun(this, font, str, styleRef(), TextRun::All
owTrailingExpansion); | |
234 return font.width(textRun); | |
235 } | |
236 | |
237 float RenderTextControl::scaleEmToUnits(int x) const | |
238 { | |
239 // This matches the unitsPerEm value for MS Shell Dlg and Courier New from t
he "head" font table. | |
240 float unitsPerEm = 2048.0f; | |
241 return roundf(style()->font().fontDescription().computedSize() * x / unitsPe
rEm); | |
242 } | |
243 | |
244 void RenderTextControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidt
h, LayoutUnit& maxLogicalWidth) const | |
245 { | |
246 // Use average character width. Matches IE. | |
247 AtomicString family = style()->font().fontDescription().family().family(); | |
248 maxLogicalWidth = preferredContentLogicalWidth(const_cast<RenderTextControl*
>(this)->getAvgCharWidth(family)); | |
249 if (RenderBox* innerEditorRenderBox = innerEditorElement()->renderBox()) | |
250 maxLogicalWidth += innerEditorRenderBox->paddingStart() + innerEditorRen
derBox->paddingEnd(); | |
251 if (!style()->logicalWidth().isPercent()) | |
252 minLogicalWidth = maxLogicalWidth; | |
253 } | |
254 | |
255 void RenderTextControl::computePreferredLogicalWidths() | |
256 { | |
257 ASSERT(preferredLogicalWidthsDirty()); | |
258 | |
259 m_minPreferredLogicalWidth = 0; | |
260 m_maxPreferredLogicalWidth = 0; | |
261 const LayoutStyle& styleToUse = styleRef(); | |
262 | |
263 if (styleToUse.logicalWidth().isFixed() && styleToUse.logicalWidth().value()
>= 0) | |
264 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentB
oxLogicalWidthForBoxSizing(styleToUse.logicalWidth().value()); | |
265 else | |
266 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferred
LogicalWidth); | |
267 | |
268 if (styleToUse.logicalMinWidth().isFixed() && styleToUse.logicalMinWidth().v
alue() > 0) { | |
269 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjust
ContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value())); | |
270 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjust
ContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value())); | |
271 } | |
272 | |
273 if (styleToUse.logicalMaxWidth().isFixed()) { | |
274 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjust
ContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value())); | |
275 m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjust
ContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value())); | |
276 } | |
277 | |
278 LayoutUnit toAdd = borderAndPaddingLogicalWidth(); | |
279 | |
280 m_minPreferredLogicalWidth += toAdd; | |
281 m_maxPreferredLogicalWidth += toAdd; | |
282 | |
283 clearPreferredLogicalWidthsDirty(); | |
284 } | |
285 | |
286 void RenderTextControl::addFocusRingRects(Vector<LayoutRect>& rects, const Layou
tPoint& additionalOffset) const | |
287 { | |
288 if (!size().isEmpty()) | |
289 rects.append(LayoutRect(additionalOffset, size())); | |
290 } | |
291 | |
292 LayoutObject* RenderTextControl::layoutSpecialExcludedChild(bool relayoutChildre
n, SubtreeLayoutScope& layoutScope) | |
293 { | |
294 HTMLElement* placeholder = toHTMLTextFormControlElement(node())->placeholder
Element(); | |
295 LayoutObject* placeholderRenderer = placeholder ? placeholder->renderer() :
0; | |
296 if (!placeholderRenderer) | |
297 return 0; | |
298 if (relayoutChildren) | |
299 layoutScope.setChildNeedsLayout(placeholderRenderer); | |
300 return placeholderRenderer; | |
301 } | |
302 | |
303 } // namespace blink | |
OLD | NEW |