1 /**
2 * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
3 * (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
4 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24 #include "config.h"
25 #include "RenderTextControlSingleLine.h"
26
27 #include "Chrome.h"
28 #include "CSSStyleSelector.h"
29 #include "Event.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "HTMLInputElement.h"
34 #include "HTMLNames.h"
35 #include "HitTestResult.h"
36 #include "InputElement.h"
37 #include "LocalizedStrings.h"
38 #include "MouseEvent.h"
39 #include "PlatformKeyboardEvent.h"
40 #include "RenderLayer.h"
41 #include "RenderScrollbar.h"
42 #include "RenderTheme.h"
43 #include "SelectionController.h"
44 #include "Settings.h"
45 #include "SimpleFontData.h"
46 #include "TextControlInnerElements.h"
47
48 using namespace std;
49
50 namespace WebCore {
51
52 using namespace HTMLNames;
53
positionForPoint(const IntPoint & point)54 VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point)
55 {
56 IntPoint contentsPoint(point);
57
58 // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that
59 // into account here.
60 if (m_multiLine) {
61 RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer());
62 if (renderer->hasOverflowClip())
63 contentsPoint += renderer->layer()->scrolledContentOffset();
64 }
65
66 return RenderBlock::positionForPoint(contentsPoint);
67 }
68
69 // ----------------------------
70
RenderTextControlSingleLine(Node * node,bool placeholderVisible)71 RenderTextControlSingleLine::RenderTextControlSingleLine(Node* node, bool placeholderVisible)
72 : RenderTextControl(node, placeholderVisible)
73 , m_searchPopupIsVisible(false)
74 , m_shouldDrawCapsLockIndicator(false)
75 , m_searchEventTimer(this, &RenderTextControlSingleLine::searchEventTimerFired)
76 , m_searchPopup(0)
77 {
78 }
79
~RenderTextControlSingleLine()80 RenderTextControlSingleLine::~RenderTextControlSingleLine()
81 {
82 if (m_searchPopup) {
83 m_searchPopup->popupMenu()->disconnectClient();
84 m_searchPopup = 0;
85 }
86
87 if (m_innerBlock) {
88 m_innerBlock->detach();
89 m_innerBlock = 0;
90 }
91
92 if (m_innerSpinButton)
93 m_innerSpinButton->detach();
94 if (m_outerSpinButton)
95 m_outerSpinButton->detach();
96 #if ENABLE(INPUT_SPEECH)
97 if (m_speechButton)
98 m_speechButton->detach();
99 #endif
100 }
101
textBaseStyle() const102 RenderStyle* RenderTextControlSingleLine::textBaseStyle() const
103 {
104 return m_innerBlock ? m_innerBlock->renderer()->style() : style();
105 }
106
addSearchResult()107 void RenderTextControlSingleLine::addSearchResult()
108 {
109 ASSERT(node()->isHTMLElement());
110 HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
111 if (input->maxResults() <= 0)
112 return;
113
114 String value = input->value();
115 if (value.isEmpty())
116 return;
117
118 Settings* settings = document()->settings();
119 if (!settings || settings->privateBrowsingEnabled())
120 return;
121
122 int size = static_cast<int>(m_recentSearches.size());
123 for (int i = size - 1; i >= 0; --i) {
124 if (m_recentSearches[i] == value)
125 m_recentSearches.remove(i);
126 }
127
128 m_recentSearches.insert(0, value);
129 while (static_cast<int>(m_recentSearches.size()) > input->maxResults())
130 m_recentSearches.removeLast();
131
132 const AtomicString& name = autosaveName();
133 if (!m_searchPopup)
134 m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
135
136 m_searchPopup->saveRecentSearches(name, m_recentSearches);
137 }
138
stopSearchEventTimer()139 void RenderTextControlSingleLine::stopSearchEventTimer()
140 {
141 ASSERT(node()->isHTMLElement());
142 m_searchEventTimer.stop();
143 }
144
showPopup()145 void RenderTextControlSingleLine::showPopup()
146 {
147 ASSERT(node()->isHTMLElement());
148 if (m_searchPopupIsVisible)
149 return;
150
151 if (!m_searchPopup)
152 m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
153
154 if (!m_searchPopup->enabled())
155 return;
156
157 m_searchPopupIsVisible = true;
158
159 const AtomicString& name = autosaveName();
160 m_searchPopup->loadRecentSearches(name, m_recentSearches);
161
162 // Trim the recent searches list if the maximum size has changed since we last saved.
163 HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
164 if (static_cast<int>(m_recentSearches.size()) > input->maxResults()) {
165 do {
166 m_recentSearches.removeLast();
167 } while (static_cast<int>(m_recentSearches.size()) > input->maxResults());
168
169 m_searchPopup->saveRecentSearches(name, m_recentSearches);
170 }
171
172 m_searchPopup->popupMenu()->show(absoluteBoundingBoxRect(true), document()->view(), -1);
173 }
174
hidePopup()175 void RenderTextControlSingleLine::hidePopup()
176 {
177 ASSERT(node()->isHTMLElement());
178 if (m_searchPopup)
179 m_searchPopup->popupMenu()->hide();
180 }
181
subtreeHasChanged()182 void RenderTextControlSingleLine::subtreeHasChanged()
183 {
184 RenderTextControl::subtreeHasChanged();
185
186 ASSERT(node()->isElementNode());
187 Element* element = static_cast<Element*>(node());
188 bool wasChanged = element->wasChangedSinceLastFormControlChangeEvent();
189 element->setChangedSinceLastFormControlChangeEvent(true);
190
191 InputElement* input = inputElement();
192 // We don't need to call sanitizeUserInputValue() function here because
193 // InputElement::handleBeforeTextInsertedEvent() has already called
194 // sanitizeUserInputValue().
195 // sanitizeValue() is needed because IME input doesn't dispatch BeforeTextInsertedEvent.
196 String value = text();
197 if (input->isAcceptableValue(value))
198 input->setValueFromRenderer(input->sanitizeValue(input->convertFromVisibleValue(value)));
199 if (node()->isHTMLElement()) {
200 // Recalc for :invalid and hasUnacceptableValue() change.
201 static_cast<HTMLInputElement*>(input)->setNeedsStyleRecalc();
202 }
203
204 if (m_cancelButton)
205 updateCancelButtonVisibility();
206
207 // If the incremental attribute is set, then dispatch the search event
208 if (input->searchEventsShouldBeDispatched())
209 startSearchEventTimer();
210
211 if (!wasChanged && node()->focused()) {
212 if (Frame* frame = this->frame())
213 frame->editor()->textFieldDidBeginEditing(static_cast<Element*>(node()));
214 }
215
216 if (node()->focused()) {
217 if (Frame* frame = document()->frame())
218 frame->editor()->textDidChangeInTextField(static_cast<Element*>(node()));
219 }
220 }
221
paint(PaintInfo & paintInfo,int tx,int ty)222 void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, int tx, int ty)
223 {
224 RenderTextControl::paint(paintInfo, tx, ty);
225
226 if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
227 IntRect contentsRect = contentBoxRect();
228
229 // Center vertically like the text.
230 contentsRect.setY((height() - contentsRect.height()) / 2);
231
232 // Convert the rect into the coords used for painting the content
233 contentsRect.move(tx + x(), ty + y());
234 theme()->paintCapsLockIndicator(this, paintInfo, contentsRect);
235 }
236 }
237
paintBoxDecorations(PaintInfo & paintInfo,int tx,int ty)238 void RenderTextControlSingleLine::paintBoxDecorations(PaintInfo& paintInfo, int tx, int ty)
239 {
240 paintBoxDecorationsWithSize(paintInfo, tx, ty, width() - decorationWidthRight(), height());
241 }
242
addFocusRingRects(Vector<IntRect> & rects,int tx,int ty)243 void RenderTextControlSingleLine::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
244 {
245 int w = width() - decorationWidthRight();
246 if (w && height())
247 rects.append(IntRect(tx, ty, w, height()));
248 }
249
layout()250 void RenderTextControlSingleLine::layout()
251 {
252 int oldHeight = height();
253 computeLogicalHeight();
254
255 int oldWidth = width();
256 computeLogicalWidth();
257
258 bool relayoutChildren = oldHeight != height() || oldWidth != width();
259
260 RenderBox* innerTextRenderer = innerTextElement()->renderBox();
261 RenderBox* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderBox() : 0;
262
263 // Set the text block height
264 int desiredHeight = textBlockHeight();
265 int currentHeight = innerTextRenderer->height();
266
267 if (currentHeight > height()) {
268 if (desiredHeight != currentHeight)
269 relayoutChildren = true;
270 innerTextRenderer->style()->setHeight(Length(desiredHeight, Fixed));
271 if (m_innerBlock)
272 innerBlockRenderer->style()->setHeight(Length(desiredHeight, Fixed));
273 }
274
275 // Set the text block width
276 int desiredWidth = textBlockWidth();
277 if (desiredWidth != innerTextRenderer->width())
278 relayoutChildren = true;
279 innerTextRenderer->style()->setWidth(Length(desiredWidth, Fixed));
280
281 if (m_innerBlock) {
282 int innerBlockWidth = width() - borderAndPaddingWidth();
283 if (innerBlockWidth != innerBlockRenderer->width())
284 relayoutChildren = true;
285 innerBlockRenderer->style()->setWidth(Length(innerBlockWidth, Fixed));
286 }
287
288 RenderBlock::layoutBlock(relayoutChildren);
289
290 // Center the child block vertically
291 RenderBox* childBlock = innerBlockRenderer ? innerBlockRenderer : innerTextRenderer;
292 currentHeight = childBlock->height();
293 if (currentHeight < height())
294 childBlock->setY((height() - currentHeight) / 2);
295
296 // Ignores the paddings for the inner spin button.
297 if (RenderBox* spinBox = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) {
298 spinBox->setLocation(spinBox->x() + paddingRight(), borderTop());
299 spinBox->setHeight(height() - borderTop() - borderBottom());
300 }
301
302 #if ENABLE(INPUT_SPEECH)
303 if (RenderBox* button = m_speechButton ? m_speechButton->renderBox() : 0) {
304 if (m_innerBlock) {
305 // This is mostly the case where this is a search field. The speech button is a sibling
306 // of the inner block and laid out at the far right.
307 int x = width() - borderAndPaddingWidth() - button->width() - button->borderAndPaddingWidth();
308 int y = (height() - button->height()) / 2;
309 button->setLocation(x, y);
310 } else {
311 int x = width() - borderRight() - paddingRight() - button->width();
312 if (m_outerSpinButton && m_outerSpinButton->renderBox())
313 x -= m_outerSpinButton->renderBox()->width();
314
315 RenderBox* spinBox = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0;
316 if (style()->isLeftToRightDirection())
317 x -= spinBox ? spinBox->width() : 0;
318 else
319 innerTextRenderer->setX(paddingLeft() + borderLeft() + (spinBox ? spinBox->width() : 0));
320 int y = (height() - button->height()) / 2;
321 button->setLocation(x, y);
322 }
323 }
324 #endif
325
326 // Center the spin button vertically, and move it to the right by
327 // padding + border of the text fields.
328 if (RenderBox* spinBox = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) {
329 int diff = height() - spinBox->height();
330 // If the diff is odd, the top area over the spin button takes the
331 // remaining one pixel. It's good for Mac NSStepper because it has
332 // shadow at the bottom.
333 int y = (diff / 2) + (diff % 2);
334 int x = width() - borderRight() - paddingRight() - spinBox->width();
335 spinBox->setLocation(x, y);
336 }
337 }
338
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int xPos,int yPos,int tx,int ty,HitTestAction hitTestAction)339 bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction)
340 {
341 // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point
342 // was on the control but not on the inner element (see Radar 4617841).
343
344 // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block,
345 // and act as if we've hit the close block if we're to the right of the inner text block.
346
347 if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction))
348 return false;
349
350 // If we hit a node inside the inner text element, say that we hit that element,
351 // and if we hit our node (e.g. we're over the border or padding), also say that we hit the
352 // inner text element so that it gains focus.
353 if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node())
354 hitInnerTextElement(result, xPos, yPos, tx, ty);
355
356 // If we found a spin button, we're done.
357 if (m_innerSpinButton && result.innerNode() == m_innerSpinButton)
358 return true;
359 if (m_outerSpinButton && result.innerNode() == m_outerSpinButton)
360 return true;
361 #if ENABLE(INPUT_SPEECH)
362 if (m_speechButton && result.innerNode() == m_speechButton)
363 return true;
364 #endif
365 // If we're not a search field, or we already found the speech, results or cancel buttons, we're done.
366 if (!m_innerBlock || result.innerNode() == m_resultsButton || result.innerNode() == m_cancelButton)
367 return true;
368
369 Node* innerNode = 0;
370 RenderBox* innerBlockRenderer = m_innerBlock->renderBox();
371 RenderBox* innerTextRenderer = innerTextElement()->renderBox();
372
373 IntPoint localPoint = result.localPoint();
374 localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y());
375
376 int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x();
377 if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft)
378 innerNode = m_resultsButton.get();
379
380 #if ENABLE(INPUT_SPEECH)
381 if (!innerNode && m_speechButton && m_speechButton->renderer()) {
382 int buttonLeft = tx + x() + innerBlockRenderer->x() + innerBlockRenderer->width() - m_speechButton->renderBox()->width();
383 if (xPos >= buttonLeft)
384 innerNode = m_speechButton.get();
385 }
386 #endif
387
388 if (!innerNode) {
389 int textRight = textLeft + innerTextRenderer->width();
390 if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight)
391 innerNode = m_cancelButton.get();
392 }
393
394 if (innerNode) {
395 result.setInnerNode(innerNode);
396 localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y());
397 }
398
399 result.setLocalPoint(localPoint);
400 return true;
401 }
402
forwardEvent(Event * event)403 void RenderTextControlSingleLine::forwardEvent(Event* event)
404 {
405 RenderBox* innerTextRenderer = innerTextElement()->renderBox();
406
407 if (event->type() == eventNames().blurEvent) {
408 if (innerTextRenderer) {
409 if (RenderLayer* innerLayer = innerTextRenderer->layer())
410 innerLayer->scrollToOffset(!style()->isLeftToRightDirection() ? innerLayer->scrollWidth() : 0, 0);
411 }
412
413 capsLockStateMayHaveChanged();
414 } else if (event->type() == eventNames().focusEvent)
415 capsLockStateMayHaveChanged();
416
417 if (!event->isMouseEvent()) {
418 RenderTextControl::forwardEvent(event);
419 return;
420 }
421
422 #if ENABLE(INPUT_SPEECH)
423 if (RenderBox* speechBox = m_speechButton ? m_speechButton->renderBox() : 0) {
424 RenderBox* parent = innerTextRenderer ? innerTextRenderer : this;
425 FloatPoint pointInTextControlCoords = parent->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true);
426 if (speechBox->frameRect().contains(roundedIntPoint(pointInTextControlCoords))) {
427 m_speechButton->defaultEventHandler(event);
428 return;
429 }
430 }
431 #endif
432
433 FloatPoint localPoint = innerTextRenderer->absoluteToLocal(static_cast<MouseEvent*>(event)->absoluteLocation(), false, true);
434 int textRight = innerTextRenderer->borderBoxRect().maxX();
435
436 if (m_resultsButton && localPoint.x() < innerTextRenderer->borderBoxRect().x())
437 m_resultsButton->defaultEventHandler(event);
438 else if (m_cancelButton && localPoint.x() > textRight)
439 m_cancelButton->defaultEventHandler(event);
440 else
441 RenderTextControl::forwardEvent(event);
442 }
443
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)444 void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
445 {
446 RenderTextControl::styleDidChange(diff, oldStyle);
447
448 if (RenderObject* innerBlockRenderer = m_innerBlock ? m_innerBlock->renderer() : 0) {
449 // We may have set the width and the height in the old style in layout().
450 // Reset them now to avoid getting a spurious layout hint.
451 innerBlockRenderer->style()->setHeight(Length());
452 innerBlockRenderer->style()->setWidth(Length());
453 innerBlockRenderer->setStyle(createInnerBlockStyle(style()));
454 }
455
456 if (RenderObject* resultsRenderer = m_resultsButton ? m_resultsButton->renderer() : 0)
457 resultsRenderer->setStyle(createResultsButtonStyle(style()));
458
459 if (RenderObject* cancelRenderer = m_cancelButton ? m_cancelButton->renderer() : 0)
460 cancelRenderer->setStyle(createCancelButtonStyle(style()));
461
462 if (RenderObject* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderer() : 0)
463 spinRenderer->setStyle(createOuterSpinButtonStyle());
464
465 if (RenderObject* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderer() : 0)
466 spinRenderer->setStyle(createInnerSpinButtonStyle());
467
468 #if ENABLE(INPUT_SPEECH)
469 if (RenderObject* speechRenderer = m_speechButton ? m_speechButton->renderer() : 0)
470 speechRenderer->setStyle(createSpeechButtonStyle());
471 #endif
472
473 setHasOverflowClip(false);
474 }
475
capsLockStateMayHaveChanged()476 void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
477 {
478 if (!node() || !document())
479 return;
480
481 // Only draw the caps lock indicator if these things are true:
482 // 1) The field is a password field
483 // 2) The frame is active
484 // 3) The element is focused
485 // 4) The caps lock is on
486 bool shouldDrawCapsLockIndicator = false;
487
488 if (Frame* frame = document()->frame())
489 shouldDrawCapsLockIndicator = inputElement()->isPasswordField()
490 && frame->selection()->isFocusedAndActive()
491 && document()->focusedNode() == node()
492 && PlatformKeyboardEvent::currentCapsLockState();
493
494 if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
495 m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
496 repaint();
497 }
498 }
499
hasControlClip() const500 bool RenderTextControlSingleLine::hasControlClip() const
501 {
502 bool clip = m_cancelButton;
503 return clip;
504 }
505
controlClipRect(int tx,int ty) const506 IntRect RenderTextControlSingleLine::controlClipRect(int tx, int ty) const
507 {
508 // This should only get called for search & speech inputs.
509 ASSERT(hasControlClip());
510
511 IntRect clipRect = IntRect(m_innerBlock->renderBox()->frameRect());
512 clipRect.move(tx, ty);
513 return clipRect;
514 }
515
textBlockWidth() const516 int RenderTextControlSingleLine::textBlockWidth() const
517 {
518 int width = RenderTextControl::textBlockWidth();
519
520 if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) {
521 resultsRenderer->computeLogicalWidth();
522 width -= resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->marginRight();
523 }
524
525 if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) {
526 cancelRenderer->computeLogicalWidth();
527 width -= cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->marginRight();
528 }
529
530 if (RenderBox* spinRenderer = m_innerSpinButton ? m_innerSpinButton->renderBox() : 0) {
531 spinRenderer->computeLogicalWidth();
532 width -= spinRenderer->width() + spinRenderer->marginLeft() + spinRenderer->marginRight();
533 }
534
535 #if ENABLE(INPUT_SPEECH)
536 if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) {
537 speechRenderer->computeLogicalWidth();
538 width -= speechRenderer->width() + speechRenderer->marginLeft() + speechRenderer->marginRight();
539 }
540 #endif
541
542 return width - decorationWidthRight();
543 }
544
decorationWidthRight() const545 int RenderTextControlSingleLine::decorationWidthRight() const
546 {
547 int width = 0;
548 if (RenderBox* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) {
549 spinRenderer->computeLogicalWidth();
550 width += spinRenderer->width() + spinRenderer->marginLeft() + spinRenderer->marginRight();
551 }
552 if (width > 0)
553 width += paddingRight() + borderRight();
554 return width;
555 }
556
getAvgCharWidth(AtomicString family)557 float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family)
558 {
559 // Since Lucida Grande is the default font, we want this to match the width
560 // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
561 // IE for some encodings (in IE, the default font is encoding specific).
562 // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg.
563 if (family == AtomicString("Lucida Grande"))
564 return scaleEmToUnits(901);
565
566 return RenderTextControl::getAvgCharWidth(family);
567 }
568
preferredContentWidth(float charWidth) const569 int RenderTextControlSingleLine::preferredContentWidth(float charWidth) const
570 {
571 int factor = inputElement()->size();
572 if (factor <= 0)
573 factor = 20;
574
575 int result = static_cast<int>(ceilf(charWidth * factor));
576
577 float maxCharWidth = 0.f;
578 AtomicString family = style()->font().family().family();
579 // Since Lucida Grande is the default font, we want this to match the width
580 // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
581 // IE for some encodings (in IE, the default font is encoding specific).
582 // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg.
583 if (family == AtomicString("Lucida Grande"))
584 maxCharWidth = scaleEmToUnits(4027);
585 else if (hasValidAvgCharWidth(family))
586 maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth());
587
588 // For text inputs, IE adds some extra width.
589 if (maxCharWidth > 0.f)
590 result += maxCharWidth - charWidth;
591
592 if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0)
593 result += resultsRenderer->borderLeft() + resultsRenderer->borderRight() +
594 resultsRenderer->paddingLeft() + resultsRenderer->paddingRight();
595
596 if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0)
597 result += cancelRenderer->borderLeft() + cancelRenderer->borderRight() +
598 cancelRenderer->paddingLeft() + cancelRenderer->paddingRight();
599
600 #if ENABLE(INPUT_SPEECH)
601 if (RenderBox* speechRenderer = m_speechButton ? m_speechButton->renderBox() : 0) {
602 result += speechRenderer->borderLeft() + speechRenderer->borderRight() +
603 speechRenderer->paddingLeft() + speechRenderer->paddingRight();
604 }
605 #endif
606 return result;
607 }
608
preferredDecorationWidthRight() const609 int RenderTextControlSingleLine::preferredDecorationWidthRight() const
610 {
611 int width = 0;
612 if (RenderBox* spinRenderer = m_outerSpinButton ? m_outerSpinButton->renderBox() : 0) {
613 spinRenderer->computeLogicalWidth();
614 width += spinRenderer->minPreferredLogicalWidth() + spinRenderer->marginLeft() + spinRenderer->marginRight();
615 }
616 if (width > 0)
617 width += paddingRight() + borderRight();
618 return width;
619 }
620
adjustControlHeightBasedOnLineHeight(int lineHeight)621 void RenderTextControlSingleLine::adjustControlHeightBasedOnLineHeight(int lineHeight)
622 {
623 if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0) {
624 resultsRenderer->computeLogicalHeight();
625 setHeight(max(height(),
626 resultsRenderer->borderTop() + resultsRenderer->borderBottom() +
627 resultsRenderer->paddingTop() + resultsRenderer->paddingBottom() +
628 resultsRenderer->marginTop() + resultsRenderer->marginBottom()));
629 lineHeight = max(lineHeight, resultsRenderer->height());
630 }
631 if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0) {
632 cancelRenderer->computeLogicalHeight();
633 setHeight(max(height(),
634 cancelRenderer->borderTop() + cancelRenderer->borderBottom() +
635 cancelRenderer->paddingTop() + cancelRenderer->paddingBottom() +
636 cancelRenderer->marginTop() + cancelRenderer->marginBottom()));
637 lineHeight = max(lineHeight, cancelRenderer->height());
638 }
639
640 setHeight(height() + lineHeight);
641 }
642
createSubtreeIfNeeded()643 void RenderTextControlSingleLine::createSubtreeIfNeeded()
644 {
645 if (inputElement()->isSearchField()) {
646 if (!m_innerBlock) {
647 // Create the inner block element
648 m_innerBlock = TextControlInnerElement::create(toHTMLElement(node()));
649 m_innerBlock->attachInnerElement(node(), createInnerBlockStyle(style()), renderArena());
650 }
651
652 #if ENABLE(INPUT_SPEECH)
653 if (inputElement()->isSpeechEnabled() && !m_speechButton) {
654 // Create the speech button element.
655 m_speechButton = InputFieldSpeechButtonElement::create(toHTMLElement(node()));
656 m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena());
657 }
658 #endif
659
660 if (!m_resultsButton) {
661 // Create the search results button element.
662 m_resultsButton = SearchFieldResultsButtonElement::create(document());
663 m_resultsButton->attachInnerElement(m_innerBlock.get(), createResultsButtonStyle(m_innerBlock->renderer()->style()), renderArena());
664 }
665
666 // Create innerText element before adding the other buttons.
667 RenderTextControl::createSubtreeIfNeeded(m_innerBlock.get());
668
669 if (!m_cancelButton) {
670 // Create the cancel button element.
671 m_cancelButton = SearchFieldCancelButtonElement::create(document());
672 m_cancelButton->attachInnerElement(m_innerBlock.get(), createCancelButtonStyle(m_innerBlock->renderer()->style()), renderArena());
673 }
674 } else {
675 RenderTextControl::createSubtreeIfNeeded(0);
676
677 #if ENABLE(INPUT_SPEECH)
678 if (inputElement()->isSpeechEnabled() && !m_speechButton) {
679 // Create the speech button element.
680 m_speechButton = InputFieldSpeechButtonElement::create(toHTMLElement(node()));
681 m_speechButton->attachInnerElement(node(), createSpeechButtonStyle(), renderArena());
682 }
683 #endif
684
685 bool hasSpinButton = theme()->shouldHaveSpinButton(inputElement());
686
687 if (hasSpinButton && !m_innerSpinButton) {
688 m_innerSpinButton = SpinButtonElement::create(toHTMLElement(node()));
689 m_innerSpinButton->attachInnerElement(node(), createInnerSpinButtonStyle(), renderArena());
690 }
691 if (hasSpinButton && !m_outerSpinButton) {
692 m_outerSpinButton = SpinButtonElement::create(toHTMLElement(node()));
693 m_outerSpinButton->attachInnerElement(node(), createOuterSpinButtonStyle(), renderArena());
694 }
695 }
696 }
697
updateFromElement()698 void RenderTextControlSingleLine::updateFromElement()
699 {
700 createSubtreeIfNeeded();
701 RenderTextControl::updateFromElement();
702
703 if (m_cancelButton)
704 updateCancelButtonVisibility();
705
706 if (!inputElement()->suggestedValue().isNull())
707 setInnerTextValue(inputElement()->suggestedValue());
708 else {
709 if (node()->hasTagName(inputTag)) {
710 // For HTMLInputElement, update the renderer value if the formControlValueMatchesRenderer()
711 // flag is false. It protects an unacceptable renderer value from
712 // being overwritten with the DOM value.
713 if (!static_cast<HTMLInputElement*>(node())->formControlValueMatchesRenderer())
714 setInnerTextValue(inputElement()->visibleValue());
715 }
716 }
717
718 if (m_searchPopupIsVisible)
719 m_searchPopup->popupMenu()->updateFromElement();
720 }
721
cacheSelection(int start,int end)722 void RenderTextControlSingleLine::cacheSelection(int start, int end)
723 {
724 inputElement()->cacheSelection(start, end);
725 }
726
createInnerTextStyle(const RenderStyle * startStyle) const727 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
728 {
729 RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();
730 textBlockStyle->inheritFrom(startStyle);
731 adjustInnerTextStyle(startStyle, textBlockStyle.get());
732
733 textBlockStyle->setWhiteSpace(PRE);
734 textBlockStyle->setWordWrap(NormalWordWrap);
735 textBlockStyle->setOverflowX(OHIDDEN);
736 textBlockStyle->setOverflowY(OHIDDEN);
737
738 // Do not allow line-height to be smaller than our default.
739 if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
740 textBlockStyle->setLineHeight(Length(-100.0f, Percent));
741
742 WebCore::EDisplay display = (m_innerBlock || theme()->shouldHaveSpinButton(inputElement()) ? INLINE_BLOCK : BLOCK);
743 #if ENABLE(INPUT_SPEECH)
744 if (inputElement()->isSpeechEnabled())
745 display = INLINE_BLOCK;
746 #endif
747 textBlockStyle->setDisplay(display);
748
749 // We're adding one extra pixel of padding to match WinIE.
750 textBlockStyle->setPaddingLeft(Length(1, Fixed));
751 textBlockStyle->setPaddingRight(Length(1, Fixed));
752
753 return textBlockStyle.release();
754 }
755
createInnerBlockStyle(const RenderStyle * startStyle) const756 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
757 {
758 ASSERT(node()->isHTMLElement());
759
760 RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
761 innerBlockStyle->inheritFrom(startStyle);
762
763 innerBlockStyle->setDisplay(BLOCK);
764 innerBlockStyle->setDirection(LTR);
765
766 // We don't want the shadow dom to be editable, so we set this block to read-only in case the input itself is editable.
767 innerBlockStyle->setUserModify(READ_ONLY);
768
769 return innerBlockStyle.release();
770 }
771
createResultsButtonStyle(const RenderStyle * startStyle) const772 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createResultsButtonStyle(const RenderStyle* startStyle) const
773 {
774 ASSERT(node()->isHTMLElement());
775 HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
776
777 RefPtr<RenderStyle> resultsBlockStyle;
778 if (input->maxResults() < 0)
779 resultsBlockStyle = getCachedPseudoStyle(SEARCH_DECORATION);
780 else if (!input->maxResults())
781 resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_DECORATION);
782 else
783 resultsBlockStyle = getCachedPseudoStyle(SEARCH_RESULTS_BUTTON);
784
785 if (!resultsBlockStyle)
786 resultsBlockStyle = RenderStyle::create();
787
788 if (startStyle)
789 resultsBlockStyle->inheritFrom(startStyle);
790
791 return resultsBlockStyle.release();
792 }
793
createCancelButtonStyle(const RenderStyle * startStyle) const794 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createCancelButtonStyle(const RenderStyle* startStyle) const
795 {
796 ASSERT(node()->isHTMLElement());
797 RefPtr<RenderStyle> cancelBlockStyle;
798
799 if (RefPtr<RenderStyle> pseudoStyle = getCachedPseudoStyle(SEARCH_CANCEL_BUTTON))
800 // We may be sharing style with another search field, but we must not share the cancel button style.
801 cancelBlockStyle = RenderStyle::clone(pseudoStyle.get());
802 else
803 cancelBlockStyle = RenderStyle::create();
804
805 if (startStyle)
806 cancelBlockStyle->inheritFrom(startStyle);
807
808 cancelBlockStyle->setVisibility(visibilityForCancelButton());
809 return cancelBlockStyle.release();
810 }
811
createInnerSpinButtonStyle() const812 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerSpinButtonStyle() const
813 {
814 ASSERT(node()->isHTMLElement());
815 RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INNER_SPIN_BUTTON);
816 if (!buttonStyle)
817 buttonStyle = RenderStyle::create();
818 buttonStyle->inheritFrom(style());
819 return buttonStyle.release();
820 }
821
createOuterSpinButtonStyle() const822 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createOuterSpinButtonStyle() const
823 {
824 ASSERT(node()->isHTMLElement());
825 RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(OUTER_SPIN_BUTTON);
826 if (!buttonStyle)
827 buttonStyle = RenderStyle::create();
828 buttonStyle->inheritFrom(style());
829 return buttonStyle.release();
830 }
831
832 #if ENABLE(INPUT_SPEECH)
createSpeechButtonStyle() const833 PassRefPtr<RenderStyle> RenderTextControlSingleLine::createSpeechButtonStyle() const
834 {
835 ASSERT(node()->isHTMLElement());
836 RefPtr<RenderStyle> buttonStyle = getCachedPseudoStyle(INPUT_SPEECH_BUTTON);
837 if (!buttonStyle)
838 buttonStyle = RenderStyle::create();
839 buttonStyle->inheritFrom(style());
840 return buttonStyle.release();
841 }
842 #endif
843
updateCancelButtonVisibility() const844 void RenderTextControlSingleLine::updateCancelButtonVisibility() const
845 {
846 if (!m_cancelButton->renderer())
847 return;
848
849 const RenderStyle* curStyle = m_cancelButton->renderer()->style();
850 EVisibility buttonVisibility = visibilityForCancelButton();
851 if (curStyle->visibility() == buttonVisibility)
852 return;
853
854 RefPtr<RenderStyle> cancelButtonStyle = RenderStyle::clone(curStyle);
855 cancelButtonStyle->setVisibility(buttonVisibility);
856 m_cancelButton->renderer()->setStyle(cancelButtonStyle);
857 }
858
visibilityForCancelButton() const859 EVisibility RenderTextControlSingleLine::visibilityForCancelButton() const
860 {
861 ASSERT(node()->isHTMLElement());
862 HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
863 return input->value().isEmpty() ? HIDDEN : VISIBLE;
864 }
865
autosaveName() const866 const AtomicString& RenderTextControlSingleLine::autosaveName() const
867 {
868 return static_cast<Element*>(node())->getAttribute(autosaveAttr);
869 }
870
startSearchEventTimer()871 void RenderTextControlSingleLine::startSearchEventTimer()
872 {
873 ASSERT(node()->isHTMLElement());
874 unsigned length = text().length();
875
876 // If there's no text, fire the event right away.
877 if (!length) {
878 stopSearchEventTimer();
879 static_cast<HTMLInputElement*>(node())->onSearch();
880 return;
881 }
882
883 // After typing the first key, we wait 0.5 seconds.
884 // After the second key, 0.4 seconds, then 0.3, then 0.2 from then on.
885 m_searchEventTimer.startOneShot(max(0.2, 0.6 - 0.1 * length));
886 }
887
searchEventTimerFired(Timer<RenderTextControlSingleLine> *)888 void RenderTextControlSingleLine::searchEventTimerFired(Timer<RenderTextControlSingleLine>*)
889 {
890 ASSERT(node()->isHTMLElement());
891 static_cast<HTMLInputElement*>(node())->onSearch();
892 }
893
894 // PopupMenuClient methods
valueChanged(unsigned listIndex,bool fireEvents)895 void RenderTextControlSingleLine::valueChanged(unsigned listIndex, bool fireEvents)
896 {
897 ASSERT(node()->isHTMLElement());
898 ASSERT(static_cast<int>(listIndex) < listSize());
899 HTMLInputElement* input = static_cast<HTMLInputElement*>(node());
900 if (static_cast<int>(listIndex) == (listSize() - 1)) {
901 if (fireEvents) {
902 m_recentSearches.clear();
903 const AtomicString& name = autosaveName();
904 if (!name.isEmpty()) {
905 if (!m_searchPopup)
906 m_searchPopup = document()->page()->chrome()->createSearchPopupMenu(this);
907 m_searchPopup->saveRecentSearches(name, m_recentSearches);
908 }
909 }
910 } else {
911 input->setValue(itemText(listIndex));
912 if (fireEvents)
913 input->onSearch();
914 input->select();
915 }
916 }
917
itemText(unsigned listIndex) const918 String RenderTextControlSingleLine::itemText(unsigned listIndex) const
919 {
920 int size = listSize();
921 if (size == 1) {
922 ASSERT(!listIndex);
923 return searchMenuNoRecentSearchesText();
924 }
925 if (!listIndex)
926 return searchMenuRecentSearchesText();
927 if (itemIsSeparator(listIndex))
928 return String();
929 if (static_cast<int>(listIndex) == (size - 1))
930 return searchMenuClearRecentSearchesText();
931 return m_recentSearches[listIndex - 1];
932 }
933
itemLabel(unsigned) const934 String RenderTextControlSingleLine::itemLabel(unsigned) const
935 {
936 return String();
937 }
938
itemIcon(unsigned) const939 String RenderTextControlSingleLine::itemIcon(unsigned) const
940 {
941 return String();
942 }
943
itemIsEnabled(unsigned listIndex) const944 bool RenderTextControlSingleLine::itemIsEnabled(unsigned listIndex) const
945 {
946 if (!listIndex || itemIsSeparator(listIndex))
947 return false;
948 return true;
949 }
950
itemStyle(unsigned) const951 PopupMenuStyle RenderTextControlSingleLine::itemStyle(unsigned) const
952 {
953 return menuStyle();
954 }
955
menuStyle() const956 PopupMenuStyle RenderTextControlSingleLine::menuStyle() const
957 {
958 return PopupMenuStyle(style()->visitedDependentColor(CSSPropertyColor), style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->font(), style()->visibility() == VISIBLE, style()->display() == NONE, style()->textIndent(), style()->direction(), style()->unicodeBidi() == Override);
959 }
960
clientInsetLeft() const961 int RenderTextControlSingleLine::clientInsetLeft() const
962 {
963 // Inset the menu by the radius of the cap on the left so that
964 // it only runs along the straight part of the bezel.
965 return height() / 2;
966 }
967
clientInsetRight() const968 int RenderTextControlSingleLine::clientInsetRight() const
969 {
970 // Inset the menu by the radius of the cap on the right so that
971 // it only runs along the straight part of the bezel (unless it needs
972 // to be wider).
973 return height() / 2;
974 }
975
clientPaddingLeft() const976 int RenderTextControlSingleLine::clientPaddingLeft() const
977 {
978 int padding = paddingLeft();
979
980 if (RenderBox* resultsRenderer = m_resultsButton ? m_resultsButton->renderBox() : 0)
981 padding += resultsRenderer->width() + resultsRenderer->marginLeft() + resultsRenderer->paddingLeft() + resultsRenderer->marginRight() + resultsRenderer->paddingRight();
982
983 return padding;
984 }
985
clientPaddingRight() const986 int RenderTextControlSingleLine::clientPaddingRight() const
987 {
988 int padding = paddingRight();
989
990 if (RenderBox* cancelRenderer = m_cancelButton ? m_cancelButton->renderBox() : 0)
991 padding += cancelRenderer->width() + cancelRenderer->marginLeft() + cancelRenderer->paddingLeft() + cancelRenderer->marginRight() + cancelRenderer->paddingRight();
992
993 return padding;
994 }
995
listSize() const996 int RenderTextControlSingleLine::listSize() const
997 {
998 // If there are no recent searches, then our menu will have 1 "No recent searches" item.
999 if (!m_recentSearches.size())
1000 return 1;
1001 // Otherwise, leave room in the menu for a header, a separator, and the "Clear recent searches" item.
1002 return m_recentSearches.size() + 3;
1003 }
1004
selectedIndex() const1005 int RenderTextControlSingleLine::selectedIndex() const
1006 {
1007 return -1;
1008 }
1009
popupDidHide()1010 void RenderTextControlSingleLine::popupDidHide()
1011 {
1012 m_searchPopupIsVisible = false;
1013 }
1014
itemIsSeparator(unsigned listIndex) const1015 bool RenderTextControlSingleLine::itemIsSeparator(unsigned listIndex) const
1016 {
1017 // The separator will be the second to last item in our list.
1018 return static_cast<int>(listIndex) == (listSize() - 2);
1019 }
1020
itemIsLabel(unsigned listIndex) const1021 bool RenderTextControlSingleLine::itemIsLabel(unsigned listIndex) const
1022 {
1023 return listIndex == 0;
1024 }
1025
itemIsSelected(unsigned) const1026 bool RenderTextControlSingleLine::itemIsSelected(unsigned) const
1027 {
1028 return false;
1029 }
1030
setTextFromItem(unsigned listIndex)1031 void RenderTextControlSingleLine::setTextFromItem(unsigned listIndex)
1032 {
1033 ASSERT(node()->isHTMLElement());
1034 static_cast<HTMLInputElement*>(node())->setValue(itemText(listIndex));
1035 }
1036
fontSelector() const1037 FontSelector* RenderTextControlSingleLine::fontSelector() const
1038 {
1039 return document()->styleSelector()->fontSelector();
1040 }
1041
hostWindow() const1042 HostWindow* RenderTextControlSingleLine::hostWindow() const
1043 {
1044 return document()->view()->hostWindow();
1045 }
1046
autoscroll()1047 void RenderTextControlSingleLine::autoscroll()
1048 {
1049 RenderLayer* layer = innerTextElement()->renderBox()->layer();
1050 if (layer)
1051 layer->autoscroll();
1052 }
1053
scrollWidth() const1054 int RenderTextControlSingleLine::scrollWidth() const
1055 {
1056 if (innerTextElement())
1057 return innerTextElement()->scrollWidth();
1058 return RenderBlock::scrollWidth();
1059 }
1060
scrollHeight() const1061 int RenderTextControlSingleLine::scrollHeight() const
1062 {
1063 if (innerTextElement())
1064 return innerTextElement()->scrollHeight();
1065 return RenderBlock::scrollHeight();
1066 }
1067
scrollLeft() const1068 int RenderTextControlSingleLine::scrollLeft() const
1069 {
1070 if (innerTextElement())
1071 return innerTextElement()->scrollLeft();
1072 return RenderBlock::scrollLeft();
1073 }
1074
scrollTop() const1075 int RenderTextControlSingleLine::scrollTop() const
1076 {
1077 if (innerTextElement())
1078 return innerTextElement()->scrollTop();
1079 return RenderBlock::scrollTop();
1080 }
1081
setScrollLeft(int newLeft)1082 void RenderTextControlSingleLine::setScrollLeft(int newLeft)
1083 {
1084 if (innerTextElement())
1085 innerTextElement()->setScrollLeft(newLeft);
1086 }
1087
setScrollTop(int newTop)1088 void RenderTextControlSingleLine::setScrollTop(int newTop)
1089 {
1090 if (innerTextElement())
1091 innerTextElement()->setScrollTop(newTop);
1092 }
1093
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier,Node ** stopNode)1094 bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
1095 {
1096 RenderLayer* layer = innerTextElement()->renderBox()->layer();
1097 if (layer && layer->scroll(direction, granularity, multiplier))
1098 return true;
1099 return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
1100 }
1101
logicalScroll(ScrollLogicalDirection direction,ScrollGranularity granularity,float multiplier,Node ** stopNode)1102 bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
1103 {
1104 RenderLayer* layer = innerTextElement()->renderBox()->layer();
1105 if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
1106 return true;
1107 return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
1108 }
1109
createScrollbar(ScrollableArea * scrollableArea,ScrollbarOrientation orientation,ScrollbarControlSize controlSize)1110 PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
1111 {
1112 RefPtr<Scrollbar> widget;
1113 bool hasCustomScrollbarStyle = style()->hasPseudoStyle(SCROLLBAR);
1114 if (hasCustomScrollbarStyle)
1115 widget = RenderScrollbar::createCustomScrollbar(scrollableArea, orientation, this);
1116 else
1117 widget = Scrollbar::createNativeScrollbar(scrollableArea, orientation, controlSize);
1118 return widget.release();
1119 }
1120
inputElement() const1121 InputElement* RenderTextControlSingleLine::inputElement() const
1122 {
1123 return node()->toInputElement();
1124 }
1125
textBlockInsetLeft() const1126 int RenderTextControlSingleLine::textBlockInsetLeft() const
1127 {
1128 int inset = borderLeft() + clientPaddingLeft();
1129 if (HTMLElement* innerText = innerTextElement()) {
1130 if (RenderBox* innerTextRenderer = innerText->renderBox())
1131 inset += innerTextRenderer->paddingLeft();
1132 }
1133 return inset;
1134 }
1135
textBlockInsetRight() const1136 int RenderTextControlSingleLine::textBlockInsetRight() const
1137 {
1138 int inset = borderRight() + clientPaddingRight();
1139 if (HTMLElement* innerText = innerTextElement()) {
1140 if (RenderBox* innerTextRenderer = innerText->renderBox())
1141 inset += innerTextRenderer->paddingRight();
1142 }
1143 return inset;
1144 }
1145
textBlockInsetTop() const1146 int RenderTextControlSingleLine::textBlockInsetTop() const
1147 {
1148 RenderBox* innerRenderer = 0;
1149 if (m_innerBlock)
1150 innerRenderer = m_innerBlock->renderBox();
1151 else if (HTMLElement* innerText = innerTextElement())
1152 innerRenderer = innerText->renderBox();
1153
1154 if (innerRenderer)
1155 return innerRenderer->y();
1156
1157 return borderTop() + paddingTop();
1158 }
1159
1160 }
1161