This source file includes following definitions.
- textFormControlElement
- innerTextElement
- addChild
- styleDidChange
- updateUserModifyProperty
- adjustInnerTextStyle
- textBlockLogicalHeight
- textBlockLogicalWidth
- updateFromElement
- scrollbarThickness
- computeLogicalHeight
- hitInnerTextElement
- hasValidAvgCharWidth
- getAvgCharWidth
- scaleEmToUnits
- computeIntrinsicLogicalWidths
- computePreferredLogicalWidths
- addFocusRingRects
- layoutSpecialExcludedChild
#include "config.h"
#include "core/rendering/RenderTextControl.h"
#include "core/html/HTMLTextFormControlElement.h"
#include "core/rendering/HitTestResult.h"
#include "core/rendering/RenderTheme.h"
#include "platform/scroll/ScrollbarTheme.h"
#include "wtf/unicode/CharacterNames.h"
using namespace std;
namespace WebCore {
RenderTextControl::RenderTextControl(HTMLTextFormControlElement* element)
: RenderBlockFlow(element)
{
ASSERT(element);
}
RenderTextControl::~RenderTextControl()
{
}
HTMLTextFormControlElement* RenderTextControl::textFormControlElement() const
{
return toHTMLTextFormControlElement(node());
}
HTMLElement* RenderTextControl::innerTextElement() const
{
return textFormControlElement()->innerTextElement();
}
void RenderTextControl::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
Node* node = newChild->node();
if (node && node->isElementNode() && toElement(node)->shadowPseudoId() == "-webkit-input-placeholder")
RenderBlockFlow::addChild(newChild, firstChild());
else
RenderBlockFlow::addChild(newChild, beforeChild);
}
void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
RenderBlockFlow::styleDidChange(diff, oldStyle);
Element* innerText = innerTextElement();
if (!innerText)
return;
RenderBlock* innerTextRenderer = toRenderBlock(innerText->renderer());
if (innerTextRenderer) {
innerTextRenderer->style()->setHeight(Length());
innerTextRenderer->style()->setWidth(Length());
innerTextRenderer->setStyle(createInnerTextStyle(style()));
innerText->setNeedsStyleRecalc(SubtreeStyleChange);
}
textFormControlElement()->updatePlaceholderVisibility(false);
}
static inline void updateUserModifyProperty(HTMLTextFormControlElement* node, RenderStyle* style)
{
style->setUserModify(node->isDisabledOrReadOnly() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY);
}
void RenderTextControl::adjustInnerTextStyle(RenderStyle* textBlockStyle) const
{
textBlockStyle->setDirection(style()->direction());
textBlockStyle->setUnicodeBidi(style()->unicodeBidi());
updateUserModifyProperty(textFormControlElement(), textBlockStyle);
}
int RenderTextControl::textBlockLogicalHeight() const
{
return logicalHeight() - borderAndPaddingLogicalHeight();
}
int RenderTextControl::textBlockLogicalWidth() const
{
Element* innerText = innerTextElement();
ASSERT(innerText);
LayoutUnit unitWidth = logicalWidth() - borderAndPaddingLogicalWidth();
if (innerText->renderer())
unitWidth -= innerText->renderBox()->paddingStart() + innerText->renderBox()->paddingEnd();
return unitWidth;
}
void RenderTextControl::updateFromElement()
{
Element* innerText = innerTextElement();
if (innerText && innerText->renderer())
updateUserModifyProperty(textFormControlElement(), innerText->renderer()->style());
}
int RenderTextControl::scrollbarThickness() const
{
return ScrollbarTheme::theme()->scrollbarThickness();
}
void RenderTextControl::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
{
HTMLElement* innerText = innerTextElement();
ASSERT(innerText);
if (RenderBox* innerTextBox = innerText->renderBox()) {
LayoutUnit nonContentHeight = innerTextBox->borderAndPaddingHeight() + innerTextBox->marginHeight();
logicalHeight = computeControlLogicalHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + borderAndPaddingHeight();
if ((isHorizontalWritingMode() && (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap)))
|| (!isHorizontalWritingMode() && (style()->overflowY() == OSCROLL || (style()->overflowY() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap))))
logicalHeight += scrollbarThickness();
}
RenderBox::computeLogicalHeight(logicalHeight, logicalTop, computedValues);
}
void RenderTextControl::hitInnerTextElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset)
{
HTMLElement* innerText = innerTextElement();
if (!innerText->renderer())
return;
LayoutPoint adjustedLocation = accumulatedOffset + location();
LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerText->renderBox()->location());
if (hasOverflowClip())
localPoint += scrolledContentOffset();
result.setInnerNode(innerText);
result.setInnerNonSharedNode(innerText);
result.setLocalPoint(localPoint);
}
static const char* const fontFamiliesWithInvalidCharWidth[] = {
"American Typewriter",
"Arial Hebrew",
"Chalkboard",
"Cochin",
"Corsiva Hebrew",
"Courier",
"Euphemia UCAS",
"Geneva",
"Gill Sans",
"Hei",
"Helvetica",
"Hoefler Text",
"InaiMathi",
"Kai",
"Lucida Grande",
"Marker Felt",
"Monaco",
"Mshtakan",
"New Peninim MT",
"Osaka",
"Raanana",
"STHeiti",
"Symbol",
"Times",
"Apple Braille",
"Apple LiGothic",
"Apple LiSung",
"Apple Symbols",
"AppleGothic",
"AppleMyungjo",
"#GungSeo",
"#HeadLineA",
"#PCMyungjo",
"#PilGi",
};
bool RenderTextControl::hasValidAvgCharWidth(AtomicString family)
{
static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
if (family.isEmpty())
return false;
if (!fontFamiliesWithInvalidCharWidthMap) {
fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>;
for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontFamiliesWithInvalidCharWidth); ++i)
fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWithInvalidCharWidth[i]));
}
return !fontFamiliesWithInvalidCharWidthMap->contains(family);
}
float RenderTextControl::getAvgCharWidth(AtomicString family)
{
if (hasValidAvgCharWidth(family))
return roundf(style()->font().primaryFont()->avgCharWidth());
const UChar ch = '0';
const String str = String(&ch, 1);
const Font& font = style()->font();
TextRun textRun = constructTextRun(this, font, str, style(), TextRun::AllowTrailingExpansion);
textRun.disableRoundingHacks();
return font.width(textRun);
}
float RenderTextControl::scaleEmToUnits(int x) const
{
float unitsPerEm = 2048.0f;
return roundf(style()->font().fontDescription().computedSize() * x / unitsPerEm);
}
void RenderTextControl::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
{
AtomicString family = style()->font().fontDescription().family().family();
maxLogicalWidth = preferredContentLogicalWidth(const_cast<RenderTextControl*>(this)->getAvgCharWidth(family));
if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox())
maxLogicalWidth += innerTextRenderBox->paddingStart() + innerTextRenderBox->paddingEnd();
if (!style()->logicalWidth().isPercent())
minLogicalWidth = maxLogicalWidth;
}
void RenderTextControl::computePreferredLogicalWidths()
{
ASSERT(preferredLogicalWidthsDirty());
m_minPreferredLogicalWidth = 0;
m_maxPreferredLogicalWidth = 0;
if (style()->logicalWidth().isFixed() && style()->logicalWidth().value() >= 0)
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->logicalWidth().value());
else
computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) {
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMinWidth().value()));
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMinWidth().value()));
}
if (style()->logicalMaxWidth().isFixed()) {
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMaxWidth().value()));
m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->logicalMaxWidth().value()));
}
LayoutUnit toAdd = borderAndPaddingLogicalWidth();
m_minPreferredLogicalWidth += toAdd;
m_maxPreferredLogicalWidth += toAdd;
clearPreferredLogicalWidthsDirty();
}
void RenderTextControl::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
{
if (!size().isEmpty())
rects.append(pixelSnappedIntRect(additionalOffset, size()));
}
RenderObject* RenderTextControl::layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope& layoutScope)
{
HTMLElement* placeholder = toHTMLTextFormControlElement(node())->placeholderElement();
RenderObject* placeholderRenderer = placeholder ? placeholder->renderer() : 0;
if (!placeholderRenderer)
return 0;
if (relayoutChildren)
layoutScope.setChildNeedsLayout(placeholderRenderer);
return placeholderRenderer;
}
}