RenderTextControlSingleLine.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  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. #include "config.h"
  24. #include "RenderTextControlSingleLine.h"
  25. #include "CSSFontSelector.h"
  26. #include "CSSValueKeywords.h"
  27. #include "Chrome.h"
  28. #include "Frame.h"
  29. #include "FrameSelection.h"
  30. #include "FrameView.h"
  31. #include "HTMLNames.h"
  32. #include "HitTestResult.h"
  33. #include "LocalizedStrings.h"
  34. #include "Page.h"
  35. #include "PlatformKeyboardEvent.h"
  36. #include "RenderLayer.h"
  37. #include "RenderScrollbar.h"
  38. #include "RenderTheme.h"
  39. #include "Settings.h"
  40. #include "SimpleFontData.h"
  41. #include "StyleResolver.h"
  42. #include "TextControlInnerElements.h"
  43. #include <wtf/StackStats.h>
  44. using namespace std;
  45. namespace WebCore {
  46. using namespace HTMLNames;
  47. RenderTextControlSingleLine::RenderTextControlSingleLine(Element* element)
  48. : RenderTextControl(element)
  49. , m_shouldDrawCapsLockIndicator(false)
  50. , m_desiredInnerTextLogicalHeight(-1)
  51. {
  52. ASSERT(element->isHTMLElement());
  53. ASSERT(element->toInputElement());
  54. }
  55. RenderTextControlSingleLine::~RenderTextControlSingleLine()
  56. {
  57. }
  58. inline HTMLElement* RenderTextControlSingleLine::innerSpinButtonElement() const
  59. {
  60. return inputElement()->innerSpinButtonElement();
  61. }
  62. RenderStyle* RenderTextControlSingleLine::textBaseStyle() const
  63. {
  64. HTMLElement* innerBlock = innerBlockElement();
  65. return innerBlock ? innerBlock->renderer()->style() : style();
  66. }
  67. void RenderTextControlSingleLine::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
  68. {
  69. RenderTextControl::paint(paintInfo, paintOffset);
  70. if (paintInfo.phase == PaintPhaseBlockBackground && m_shouldDrawCapsLockIndicator) {
  71. LayoutRect contentsRect = contentBoxRect();
  72. // Center in the block progression direction.
  73. if (isHorizontalWritingMode())
  74. contentsRect.setY((height() - contentsRect.height()) / 2);
  75. else
  76. contentsRect.setX((width() - contentsRect.width()) / 2);
  77. // Convert the rect into the coords used for painting the content
  78. contentsRect.moveBy(paintOffset + location());
  79. theme()->paintCapsLockIndicator(this, paintInfo, pixelSnappedIntRect(contentsRect));
  80. }
  81. }
  82. LayoutUnit RenderTextControlSingleLine::computeLogicalHeightLimit() const
  83. {
  84. return containerElement() ? contentLogicalHeight() : logicalHeight();
  85. }
  86. static void setNeedsLayoutOnAncestors(RenderObject* start, RenderObject* ancestor)
  87. {
  88. ASSERT(start != ancestor);
  89. for (RenderObject* renderer = start; renderer != ancestor; renderer = renderer->parent()) {
  90. ASSERT(renderer);
  91. renderer->setNeedsLayout(true, MarkOnlyThis);
  92. }
  93. }
  94. void RenderTextControlSingleLine::layout()
  95. {
  96. StackStats::LayoutCheckPoint layoutCheckPoint;
  97. // FIXME: We should remove the height-related hacks in layout() and
  98. // styleDidChange(). We need them because
  99. // - Center the inner elements vertically if the input height is taller than
  100. // the intrinsic height of the inner elements.
  101. // - Shrink the inner elment heights if the input height is samller than the
  102. // intrinsic heights of the inner elements.
  103. // We don't honor paddings and borders for textfields without decorations
  104. // and type=search if the text height is taller than the contentHeight()
  105. // because of compability.
  106. RenderBox* innerTextRenderer = innerTextElement()->renderBox();
  107. RenderBox* innerBlockRenderer = innerBlockElement() ? innerBlockElement()->renderBox() : 0;
  108. // To ensure consistency between layouts, we need to reset any conditionally overriden height.
  109. if (innerTextRenderer && !innerTextRenderer->style()->logicalHeight().isAuto()) {
  110. innerTextRenderer->style()->setLogicalHeight(Length(Auto));
  111. setNeedsLayoutOnAncestors(innerTextRenderer, this);
  112. }
  113. if (innerBlockRenderer && !innerBlockRenderer->style()->logicalHeight().isAuto()) {
  114. innerBlockRenderer->style()->setLogicalHeight(Length(Auto));
  115. setNeedsLayoutOnAncestors(innerBlockRenderer, this);
  116. }
  117. RenderBlock::layoutBlock(false);
  118. HTMLElement* container = containerElement();
  119. RenderBox* containerRenderer = container ? container->renderBox() : 0;
  120. // Set the text block height
  121. LayoutUnit desiredLogicalHeight = textBlockLogicalHeight();
  122. LayoutUnit logicalHeightLimit = computeLogicalHeightLimit();
  123. if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) {
  124. if (desiredLogicalHeight != innerTextRenderer->logicalHeight())
  125. setNeedsLayout(true, MarkOnlyThis);
  126. m_desiredInnerTextLogicalHeight = desiredLogicalHeight;
  127. innerTextRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed));
  128. innerTextRenderer->setNeedsLayout(true, MarkOnlyThis);
  129. if (innerBlockRenderer) {
  130. innerBlockRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed));
  131. innerBlockRenderer->setNeedsLayout(true, MarkOnlyThis);
  132. }
  133. }
  134. // The container might be taller because of decoration elements.
  135. if (containerRenderer) {
  136. containerRenderer->layoutIfNeeded();
  137. LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight();
  138. if (containerLogicalHeight > logicalHeightLimit) {
  139. containerRenderer->style()->setLogicalHeight(Length(logicalHeightLimit, Fixed));
  140. setNeedsLayout(true, MarkOnlyThis);
  141. } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) {
  142. containerRenderer->style()->setLogicalHeight(Length(contentLogicalHeight(), Fixed));
  143. setNeedsLayout(true, MarkOnlyThis);
  144. } else
  145. containerRenderer->style()->setLogicalHeight(Length(containerLogicalHeight, Fixed));
  146. }
  147. // If we need another layout pass, we have changed one of children's height so we need to relayout them.
  148. if (needsLayout())
  149. RenderBlock::layoutBlock(true);
  150. // Center the child block in the block progression direction (vertical centering for horizontal text fields).
  151. if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) {
  152. LayoutUnit logicalHeightDiff = innerTextRenderer->logicalHeight() - contentLogicalHeight();
  153. innerTextRenderer->setLogicalTop(innerTextRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2)));
  154. } else
  155. centerContainerIfNeeded(containerRenderer);
  156. // Ignores the paddings for the inner spin button.
  157. if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) {
  158. RenderBox* parentBox = innerSpinBox->parentBox();
  159. if (containerRenderer && !containerRenderer->style()->isLeftToRightDirection())
  160. innerSpinBox->setLogicalLocation(LayoutPoint(-paddingLogicalLeft(), -paddingBefore()));
  161. else
  162. innerSpinBox->setLogicalLocation(LayoutPoint(parentBox->logicalWidth() - innerSpinBox->logicalWidth() + paddingLogicalRight(), -paddingBefore()));
  163. innerSpinBox->setLogicalHeight(logicalHeight() - borderBefore() - borderAfter());
  164. }
  165. HTMLElement* placeholderElement = inputElement()->placeholderElement();
  166. if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) {
  167. LayoutSize innerTextSize;
  168. if (innerTextRenderer)
  169. innerTextSize = innerTextRenderer->size();
  170. placeholderBox->style()->setWidth(Length(innerTextSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed));
  171. placeholderBox->style()->setHeight(Length(innerTextSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed));
  172. bool neededLayout = placeholderBox->needsLayout();
  173. bool placeholderBoxHadLayout = placeholderBox->everHadLayout();
  174. placeholderBox->layoutIfNeeded();
  175. LayoutPoint textOffset;
  176. if (innerTextRenderer)
  177. textOffset = innerTextRenderer->location();
  178. if (innerBlockElement() && innerBlockElement()->renderBox())
  179. textOffset += toLayoutSize(innerBlockElement()->renderBox()->location());
  180. if (containerRenderer)
  181. textOffset += toLayoutSize(containerRenderer->location());
  182. placeholderBox->setLocation(textOffset);
  183. if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) {
  184. // This assumes a shadow tree without floats. If floats are added, the
  185. // logic should be shared with RenderBlock::layoutBlockChild.
  186. placeholderBox->repaint();
  187. }
  188. // The placeholder gets layout last, after the parent text control and its other children,
  189. // so in order to get the correct overflow from the placeholder we need to recompute it now.
  190. if (neededLayout)
  191. computeOverflow(clientLogicalBottom());
  192. }
  193. }
  194. bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
  195. {
  196. if (!RenderTextControl::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction))
  197. return false;
  198. // Say that we hit the inner text element if
  199. // - we hit a node inside the inner text element,
  200. // - we hit the <input> element (e.g. we're over the border or padding), or
  201. // - we hit regions not in any decoration buttons.
  202. HTMLElement* container = containerElement();
  203. if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node() || (container && container == result.innerNode())) {
  204. LayoutPoint pointInParent = locationInContainer.point();
  205. if (container && innerBlockElement()) {
  206. if (innerBlockElement()->renderBox())
  207. pointInParent -= toLayoutSize(innerBlockElement()->renderBox()->location());
  208. if (container->renderBox())
  209. pointInParent -= toLayoutSize(container->renderBox()->location());
  210. }
  211. hitInnerTextElement(result, pointInParent, accumulatedOffset);
  212. }
  213. return true;
  214. }
  215. void RenderTextControlSingleLine::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
  216. {
  217. m_desiredInnerTextLogicalHeight = -1;
  218. RenderTextControl::styleDidChange(diff, oldStyle);
  219. // We may have set the width and the height in the old style in layout().
  220. // Reset them now to avoid getting a spurious layout hint.
  221. HTMLElement* innerBlock = innerBlockElement();
  222. if (RenderObject* innerBlockRenderer = innerBlock ? innerBlock->renderer() : 0) {
  223. innerBlockRenderer->style()->setHeight(Length());
  224. innerBlockRenderer->style()->setWidth(Length());
  225. }
  226. HTMLElement* container = containerElement();
  227. if (RenderObject* containerRenderer = container ? container->renderer() : 0) {
  228. containerRenderer->style()->setHeight(Length());
  229. containerRenderer->style()->setWidth(Length());
  230. }
  231. RenderObject* innerTextRenderer = innerTextElement()->renderer();
  232. if (innerTextRenderer && diff == StyleDifferenceLayout)
  233. innerTextRenderer->setNeedsLayout(true, MarkContainingBlockChain);
  234. if (HTMLElement* placeholder = inputElement()->placeholderElement())
  235. placeholder->setInlineStyleProperty(CSSPropertyTextOverflow, textShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip);
  236. setHasOverflowClip(false);
  237. }
  238. void RenderTextControlSingleLine::capsLockStateMayHaveChanged()
  239. {
  240. if (!node() || !document())
  241. return;
  242. // Only draw the caps lock indicator if these things are true:
  243. // 1) The field is a password field
  244. // 2) The frame is active
  245. // 3) The element is focused
  246. // 4) The caps lock is on
  247. bool shouldDrawCapsLockIndicator = false;
  248. if (Frame* frame = document()->frame())
  249. shouldDrawCapsLockIndicator = inputElement()->isPasswordField()
  250. && frame->selection()->isFocusedAndActive()
  251. && document()->focusedElement() == node()
  252. && PlatformKeyboardEvent::currentCapsLockState();
  253. if (shouldDrawCapsLockIndicator != m_shouldDrawCapsLockIndicator) {
  254. m_shouldDrawCapsLockIndicator = shouldDrawCapsLockIndicator;
  255. repaint();
  256. }
  257. }
  258. bool RenderTextControlSingleLine::hasControlClip() const
  259. {
  260. // Apply control clip for text fields with decorations.
  261. return !!containerElement();
  262. }
  263. LayoutRect RenderTextControlSingleLine::controlClipRect(const LayoutPoint& additionalOffset) const
  264. {
  265. ASSERT(hasControlClip());
  266. LayoutRect clipRect = contentBoxRect();
  267. if (containerElement()->renderBox())
  268. clipRect = unionRect(clipRect, containerElement()->renderBox()->frameRect());
  269. clipRect.moveBy(additionalOffset);
  270. return clipRect;
  271. }
  272. float RenderTextControlSingleLine::getAvgCharWidth(AtomicString family)
  273. {
  274. // Since Lucida Grande is the default font, we want this to match the width
  275. // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
  276. // IE for some encodings (in IE, the default font is encoding specific).
  277. // 901 is the avgCharWidth value in the OS/2 table for MS Shell Dlg.
  278. if (family == "Lucida Grande")
  279. return scaleEmToUnits(901);
  280. return RenderTextControl::getAvgCharWidth(family);
  281. }
  282. LayoutUnit RenderTextControlSingleLine::preferredContentLogicalWidth(float charWidth) const
  283. {
  284. int factor;
  285. bool includesDecoration = inputElement()->sizeShouldIncludeDecoration(factor);
  286. if (factor <= 0)
  287. factor = 20;
  288. LayoutUnit result = static_cast<LayoutUnit>(ceiledLayoutUnit(charWidth * factor));
  289. float maxCharWidth = 0.f;
  290. const AtomicString& family = style()->font().firstFamily();
  291. // Since Lucida Grande is the default font, we want this to match the width
  292. // of MS Shell Dlg, the default font for textareas in Firefox, Safari Win and
  293. // IE for some encodings (in IE, the default font is encoding specific).
  294. // 4027 is the (xMax - xMin) value in the "head" font table for MS Shell Dlg.
  295. if (family == "Lucida Grande")
  296. maxCharWidth = scaleEmToUnits(4027);
  297. else if (hasValidAvgCharWidth(family))
  298. maxCharWidth = roundf(style()->font().primaryFont()->maxCharWidth());
  299. // For text inputs, IE adds some extra width.
  300. if (maxCharWidth > 0.f)
  301. result += maxCharWidth - charWidth;
  302. if (includesDecoration) {
  303. HTMLElement* spinButton = innerSpinButtonElement();
  304. if (RenderBox* spinRenderer = spinButton ? spinButton->renderBox() : 0) {
  305. result += spinRenderer->borderAndPaddingLogicalWidth();
  306. // Since the width of spinRenderer is not calculated yet, spinRenderer->logicalWidth() returns 0.
  307. // So computedStyle()->logicalWidth() is used instead.
  308. result += spinButton->computedStyle()->logicalWidth().value();
  309. }
  310. }
  311. return result;
  312. }
  313. LayoutUnit RenderTextControlSingleLine::computeControlLogicalHeight(LayoutUnit lineHeight, LayoutUnit nonContentHeight) const
  314. {
  315. return lineHeight + nonContentHeight;
  316. }
  317. void RenderTextControlSingleLine::updateFromElement()
  318. {
  319. RenderTextControl::updateFromElement();
  320. }
  321. PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const RenderStyle* startStyle) const
  322. {
  323. RefPtr<RenderStyle> textBlockStyle = RenderStyle::create();
  324. textBlockStyle->inheritFrom(startStyle);
  325. adjustInnerTextStyle(startStyle, textBlockStyle.get());
  326. textBlockStyle->setWhiteSpace(PRE);
  327. textBlockStyle->setOverflowWrap(NormalOverflowWrap);
  328. textBlockStyle->setOverflowX(OHIDDEN);
  329. textBlockStyle->setOverflowY(OHIDDEN);
  330. textBlockStyle->setTextOverflow(textShouldBeTruncated() ? TextOverflowEllipsis : TextOverflowClip);
  331. if (m_desiredInnerTextLogicalHeight >= 0)
  332. textBlockStyle->setLogicalHeight(Length(m_desiredInnerTextLogicalHeight, Fixed));
  333. // Do not allow line-height to be smaller than our default.
  334. if (textBlockStyle->fontMetrics().lineSpacing() > lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes))
  335. textBlockStyle->setLineHeight(RenderStyle::initialLineHeight());
  336. textBlockStyle->setDisplay(BLOCK);
  337. return textBlockStyle.release();
  338. }
  339. PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerBlockStyle(const RenderStyle* startStyle) const
  340. {
  341. RefPtr<RenderStyle> innerBlockStyle = RenderStyle::create();
  342. innerBlockStyle->inheritFrom(startStyle);
  343. innerBlockStyle->setFlexGrow(1);
  344. // min-width: 0; is needed for correct shrinking.
  345. // FIXME: Remove this line when https://bugs.webkit.org/show_bug.cgi?id=111790 is fixed.
  346. innerBlockStyle->setMinWidth(Length(0, Fixed));
  347. innerBlockStyle->setDisplay(BLOCK);
  348. innerBlockStyle->setDirection(LTR);
  349. // 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.
  350. innerBlockStyle->setUserModify(READ_ONLY);
  351. return innerBlockStyle.release();
  352. }
  353. bool RenderTextControlSingleLine::textShouldBeTruncated() const
  354. {
  355. return document()->focusedElement() != node()
  356. && style()->textOverflow() == TextOverflowEllipsis;
  357. }
  358. void RenderTextControlSingleLine::autoscroll(const IntPoint& position)
  359. {
  360. RenderBox* renderer = innerTextElement()->renderBox();
  361. if (!renderer)
  362. return;
  363. RenderLayer* layer = renderer->layer();
  364. if (layer)
  365. layer->autoscroll(position);
  366. }
  367. int RenderTextControlSingleLine::scrollWidth() const
  368. {
  369. if (innerTextElement())
  370. return innerTextElement()->scrollWidth();
  371. return RenderBlock::scrollWidth();
  372. }
  373. int RenderTextControlSingleLine::scrollHeight() const
  374. {
  375. if (innerTextElement())
  376. return innerTextElement()->scrollHeight();
  377. return RenderBlock::scrollHeight();
  378. }
  379. int RenderTextControlSingleLine::scrollLeft() const
  380. {
  381. if (innerTextElement())
  382. return innerTextElement()->scrollLeft();
  383. return RenderBlock::scrollLeft();
  384. }
  385. int RenderTextControlSingleLine::scrollTop() const
  386. {
  387. if (innerTextElement())
  388. return innerTextElement()->scrollTop();
  389. return RenderBlock::scrollTop();
  390. }
  391. void RenderTextControlSingleLine::setScrollLeft(int newLeft)
  392. {
  393. if (innerTextElement())
  394. innerTextElement()->setScrollLeft(newLeft);
  395. }
  396. void RenderTextControlSingleLine::setScrollTop(int newTop)
  397. {
  398. if (innerTextElement())
  399. innerTextElement()->setScrollTop(newTop);
  400. }
  401. bool RenderTextControlSingleLine::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
  402. {
  403. RenderBox* renderer = innerTextElement()->renderBox();
  404. if (!renderer)
  405. return false;
  406. RenderLayer* layer = renderer->layer();
  407. if (layer && layer->scroll(direction, granularity, multiplier))
  408. return true;
  409. return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
  410. }
  411. bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
  412. {
  413. RenderLayer* layer = innerTextElement()->renderBox()->layer();
  414. if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
  415. return true;
  416. return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
  417. }
  418. HTMLInputElement* RenderTextControlSingleLine::inputElement() const
  419. {
  420. return node()->toInputElement();
  421. }
  422. }