void WMLInputElement::defaultEventHandler(Event* evt) { bool clickDefaultFormButton = false; if (evt->type() == eventNames().textInputEvent && evt->isTextEvent()) { TextEvent* textEvent = static_cast<TextEvent*>(evt); if (textEvent->data() == "\n") clickDefaultFormButton = true; else if (renderer() && !isConformedToInputMask(textEvent->data()[0], toRenderTextControl(renderer())->text().length() + 1)) // If the inputed char doesn't conform to the input mask, stop handling return; } if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent() && focused() && document()->frame() && document()->frame()->editor()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) { evt->setDefaultHandled(); return; } // Let the key handling done in EventTargetNode take precedence over the event handling here for editable text fields if (!clickDefaultFormButton) { WMLElement::defaultEventHandler(evt); if (evt->defaultHandled()) return; } // Use key press event here since sending simulated mouse events // on key down blocks the proper sending of the key press event. if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { // Simulate mouse click on the default form button for enter for these types of elements. if (static_cast<KeyboardEvent*>(evt)->charCode() == '\r') clickDefaultFormButton = true; } if (clickDefaultFormButton) { // Fire onChange for text fields. if (wasChangedSinceLastFormControlChangeEvent()) { setChangedSinceLastFormControlChangeEvent(false); dispatchEvent(Event::create(eventNames().changeEvent, true, false)); } evt->setDefaultHandled(); return; } if (evt->isBeforeTextInsertedEvent()) InputElement::handleBeforeTextInsertedEvent(m_data, this, this, evt); if (renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) toRenderTextControlSingleLine(renderer())->forwardEvent(evt); //add. When has two input element, can't move second input element. if (evt->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) { toRenderTextControl(renderer())->subtreeHasChanged(); } /*guoxiaolei 20120827 end>*/ }
void WMLInputElement::defaultEventHandler(Event* evt) { bool clickDefaultFormButton = false; if (evt->type() == eventNames().textInputEvent && evt->isTextEvent()) { TextEvent* textEvent = static_cast<TextEvent*>(evt); if (textEvent->data() == "\n") clickDefaultFormButton = true; else if (renderer() && !isConformedToInputMask(textEvent->data()[0], toRenderTextControl(renderer())->text().length() + 1)) // If the inputed char doesn't conform to the input mask, stop handling return; } if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent() && focused() && document()->frame() && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) { evt->setDefaultHandled(); return; } // Let the key handling done in EventTargetNode take precedence over the event handling here for editable text fields if (!clickDefaultFormButton) { WMLElement::defaultEventHandler(evt); if (evt->defaultHandled()) return; } // Use key press event here since sending simulated mouse events // on key down blocks the proper sending of the key press event. if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { // Simulate mouse click on the default form button for enter for these types of elements. if (static_cast<KeyboardEvent*>(evt)->charCode() == '\r') clickDefaultFormButton = true; } if (clickDefaultFormButton) { // Fire onChange for text fields. RenderObject* r = renderer(); if (r && toRenderTextControl(r)->isEdited()) { dispatchEvent(Event::create(eventNames().changeEvent, true, false)); // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it. r = renderer(); if (r) toRenderTextControl(r)->setEdited(false); } evt->setDefaultHandled(); return; } if (evt->isBeforeTextInsertedEvent()) InputElement::handleBeforeTextInsertedEvent(m_data, this, this, evt); if (renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) toRenderTextControlSingleLine(renderer())->forwardEvent(evt); }
VisibleSelection visibleSelectionForFocusedBlock(Element* element) { int textLength = inputElementText(element).length(); if (DOMSupport::toTextControlElement(element)) { RenderTextControl* textRender = toRenderTextControl(element->renderer()); if (!textRender) return VisibleSelection(); VisiblePosition startPosition = textRender->visiblePositionForIndex(0); VisiblePosition endPosition; if (textLength) endPosition = textRender->visiblePositionForIndex(textLength); else endPosition = startPosition; return VisibleSelection(startPosition, endPosition); } // Must be content editable, generate the range. RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(element, 0, textLength); if (!selectionRange) return VisibleSelection(); if (!textLength) return VisibleSelection(selectionRange->startPosition(), DOWNSTREAM); return VisibleSelection(selectionRange->startPosition(), selectionRange->endPosition()); }
RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout() { if (!isTextFormControl()) return 0; document()->updateLayoutIgnorePendingStylesheets(); return toRenderTextControl(renderer()); }
VisibleSelection visibleSelectionForRangeInputElement(Element* element, int start, int end) { if (DOMSupport::toTextControlElement(element)) { RenderTextControl* textRender = toRenderTextControl(element->renderer()); if (!textRender) return VisibleSelection(); VisiblePosition startPosition = textRender->visiblePositionForIndex(start); VisiblePosition endPosition; if (start == end) endPosition = startPosition; else endPosition = textRender->visiblePositionForIndex(end); return VisibleSelection(startPosition, endPosition); } // Must be content editable, generate the range. RefPtr<Range> selectionRange = TextIterator::rangeFromLocationAndLength(element, start, end - start); if (start == end) return VisibleSelection(selectionRange.get()->startPosition(), DOWNSTREAM); VisiblePosition visibleStart(selectionRange->startPosition(), DOWNSTREAM); VisiblePosition visibleEnd(selectionRange->endPosition(), SEL_DEFAULT_AFFINITY); return VisibleSelection(visibleStart, visibleEnd); }
int HTMLTextAreaElement::selectionStart() { if (!renderer()) return 0; if (document()->focusedNode() != this && m_cachedSelectionStart >= 0) return m_cachedSelectionStart; return toRenderTextControl(renderer())->selectionStart(); }
void HTMLTextAreaElement::updateValue() const { if (formControlValueMatchesRenderer()) return; ASSERT(renderer()); m_value = toRenderTextControl(renderer())->text(); const_cast<HTMLTextAreaElement*>(this)->setFormControlValueMatchesRenderer(true); notifyFormStateChanged(this); }
bool WMLInputElement::isConformedToInputMask(UChar inChar, unsigned inputCharCount, bool isUserInput) { if (m_formatMask.isEmpty()) return true; if (inputCharCount > m_numOfCharsAllowedByMask) return false; unsigned maskIndex = 0; if (isUserInput) { unsigned cursorPosition = 0; if (renderer()) cursorPosition = toRenderTextControl(renderer())->selectionStart(); else cursorPosition = m_data.cachedSelectionStart(); maskIndex = cursorPositionToMaskIndex(cursorPosition); } else maskIndex = cursorPositionToMaskIndex(inputCharCount - 1); bool ok = true; UChar mask = m_formatMask[maskIndex]; // match the inputed character with input mask switch (mask) { case 'A': ok = !WTF::isASCIIDigit(inChar) && !WTF::isASCIILower(inChar) && WTF::isASCIIPrintable(inChar); break; case 'a': ok = !WTF::isASCIIDigit(inChar) && !WTF::isASCIIUpper(inChar) && WTF::isASCIIPrintable(inChar); break; case 'N': ok = WTF::isASCIIDigit(inChar); break; case 'n': ok = !WTF::isASCIIAlpha(inChar) && WTF::isASCIIPrintable(inChar); break; case 'X': ok = !WTF::isASCIILower(inChar) && WTF::isASCIIPrintable(inChar); break; case 'x': ok = !WTF::isASCIIUpper(inChar) && WTF::isASCIIPrintable(inChar); break; case 'M': ok = WTF::isASCII(inChar) ? WTF::isASCIIPrintable(inChar) : true; break; case 'm': ok = WTF::isASCII(inChar) ? WTF::isASCIIPrintable(inChar) : true; break; default: ok = (mask == inChar); break; } return ok; }
bool HTMLTextAreaElement::appendFormData(FormDataList& encoding, bool) { if (name().isEmpty()) return false; // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer. // While we have no evidence this has ever been a practical problem, it would be best to fix it some day. RenderTextControl* control = toRenderTextControl(renderer()); const String& text = (m_wrap == HardWrap && control) ? control->textWithHardLineBreaks() : value(); encoding.appendData(name(), text); return true; }
VisiblePosition RenderTextControlInnerBlock::positionForPoint(const IntPoint& point) { IntPoint contentsPoint(point); // Multiline text controls have the scroll on shadowAncestorNode, so we need to take that // into account here. if (m_multiLine) { RenderTextControl* renderer = toRenderTextControl(node()->shadowAncestorNode()->renderer()); if (renderer->hasOverflowClip()) contentsPoint += renderer->layer()->scrolledContentOffset(); } return RenderBlock::positionForPoint(contentsPoint); }
void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) const { ASSERT(event); ASSERT(renderer()); int signedMaxLength = maxLength(); if (signedMaxLength < 0) return; unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); unsigned currentLength = toRenderTextControl(renderer())->text().numGraphemeClusters(); unsigned selectionLength = plainText(document()->frame()->selection()->selection().toNormalizedRange().get()).numGraphemeClusters(); ASSERT(currentLength >= selectionLength); unsigned baseLength = currentLength - selectionLength; unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0; event->setText(sanitizeUserInputValue(event->text(), appendableLength)); }
void TextControlInnerTextElement::defaultEventHandler(Event* evt) { // FIXME: In the future, we should add a way to have default event listeners. Then we would add one to the text field's inner div, and we wouldn't need this subclass. Node* shadowAncestor = shadowAncestorNode(); if (shadowAncestor && shadowAncestor->renderer()) { ASSERT(shadowAncestor->renderer()->isTextControl()); if (evt->isBeforeTextInsertedEvent()) { if (shadowAncestor->renderer()->isTextField()) static_cast<HTMLInputElement*>(shadowAncestor)->defaultEventHandler(evt); else static_cast<HTMLTextAreaElement*>(shadowAncestor)->defaultEventHandler(evt); } if (evt->type() == eventNames().webkitEditableContentChangedEvent) toRenderTextControl(shadowAncestor->renderer())->subtreeHasChanged(); } if (!evt->defaultHandled()) HTMLDivElement::defaultEventHandler(evt); }
void HTMLTextAreaElement::handleBeforeTextInsertedEvent(BeforeTextInsertedEvent* event) const { ASSERT(event); ASSERT(renderer()); int signedMaxLength = maxLength(); if (signedMaxLength < 0) return; unsigned unsignedMaxLength = static_cast<unsigned>(signedMaxLength); unsigned currentLength = numGraphemeClusters(toRenderTextControl(renderer())->text()); // selectionLength represents the selection length of this text field to be // removed by this insertion. // If the text field has no focus, we don't need to take account of the // selection length. The selection is the source of text drag-and-drop in // that case, and nothing in the text field will be removed. unsigned selectionLength = focused() ? numGraphemeClusters(plainText(document()->frame()->selection()->selection().toNormalizedRange().get())) : 0; ASSERT(currentLength >= selectionLength); unsigned baseLength = currentLength - selectionLength; unsigned appendableLength = unsignedMaxLength > baseLength ? unsignedMaxLength - baseLength : 0; event->setText(sanitizeUserInputValue(event->text(), appendableLength)); }
void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction) { document()->updateLayoutIgnorePendingStylesheets(); if (!renderer() || !renderer()->isTextControl()) return; end = max(end, 0); start = min(max(start, 0), end); RenderTextControl* control = toRenderTextControl(renderer()); if (!hasVisibleTextArea(control, innerTextElement())) { cacheSelection(start, end, direction); return; } VisiblePosition startPosition = control->visiblePositionForIndex(start); VisiblePosition endPosition; if (start == end) endPosition = startPosition; else endPosition = control->visiblePositionForIndex(end); // startPosition and endPosition can be null position for example when // "-webkit-user-select: none" style attribute is specified. if (startPosition.isNotNull() && endPosition.isNotNull()) { ASSERT(startPosition.deepEquivalent().deprecatedNode()->shadowHost() == this && endPosition.deepEquivalent().deprecatedNode()->shadowHost() == this); } VisibleSelection newSelection; if (direction == SelectionHasBackwardDirection) newSelection = VisibleSelection(endPosition, startPosition); else newSelection = VisibleSelection(startPosition, endPosition); newSelection.setIsDirectional(direction != SelectionHasNoDirection); if (Frame* frame = document()->frame()) frame->selection()->setSelection(newSelection); }
void WMLInputElement::select() { if (RenderTextControl* r = toRenderTextControl(renderer())) setSelectionRange(this, 0, r->text().length()); }
VisibleSelection HTMLTextAreaElement::selection() const { if (!renderer() || m_cachedSelectionStart < 0 || m_cachedSelectionEnd < 0) return VisibleSelection(); return toRenderTextControl(renderer())->selection(m_cachedSelectionStart, m_cachedSelectionEnd); }
void WMLInputElement::select() { if (RenderTextControl* r = toRenderTextControl(renderer())) r->select(); }
void SearchFieldCancelButtonElement::defaultEventHandler(Event* event) { // If the element is visible, on mouseup, clear the value, and set selection HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { if (renderer() && renderer()->visibleToHitTesting()) { if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(this); m_capturing = true; } } input->focus(); input->select(); event->setDefaultHandled(); } if (event->type() == eventNames().mouseupEvent && event->isMouseEvent() && static_cast<MouseEvent*>(event)->button() == LeftButton) { if (m_capturing && renderer() && renderer()->visibleToHitTesting()) { if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(0); m_capturing = false; } #if !PLATFORM(OLYMPIA) // FIXME: It's always false on OLYMPIA platform. This problem depends on RIM bug #1067. if (hovered()) { #else if (event->target() == this) { #endif RefPtr<HTMLInputElement> protector(input); String oldValue = input->value(); input->setValue(""); if (!oldValue.isEmpty()) { toRenderTextControl(input->renderer())->setChangedSinceLastChangeEvent(true); input->dispatchEvent(Event::create(eventNames().inputEvent, true, false)); } input->onSearch(); event->setDefaultHandled(); } } } if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); } // ---------------------------- inline SpinButtonElement::SpinButtonElement(HTMLElement* shadowParent) : TextControlInnerElement(shadowParent->document(), shadowParent) , m_capturing(false) , m_upDownState(Indeterminate) , m_pressStartingState(Indeterminate) , m_repeatingTimer(this, &SpinButtonElement::repeatingTimerFired) { } PassRefPtr<SpinButtonElement> SpinButtonElement::create(HTMLElement* shadowParent) { return adoptRef(new SpinButtonElement(shadowParent)); } void SpinButtonElement::defaultEventHandler(Event* event) { if (!event->isMouseEvent()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; } RenderBox* box = renderBox(); if (!box) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; } HTMLInputElement* input = static_cast<HTMLInputElement*>(shadowAncestorNode()); if (input->disabled() || input->isReadOnlyFormControl()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; } MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), false, true)); if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) { if (box->borderBoxRect().contains(local)) { RefPtr<Node> protector(input); input->focus(); input->select(); input->stepUpFromRenderer(m_upDownState == Up ? 1 : -1); event->setDefaultHandled(); startRepeatingTimer(); } } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton) stopRepeatingTimer(); else if (event->type() == eventNames().mousemoveEvent) { if (box->borderBoxRect().contains(local)) { if (!m_capturing) { if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(this); m_capturing = true; } } UpDownState oldUpDownState = m_upDownState; m_upDownState = local.y() < box->height() / 2 ? Up : Down; if (m_upDownState != oldUpDownState) renderer()->repaint(); } else { if (m_capturing) { stopRepeatingTimer(); if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(0); m_capturing = false; } } } } if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); } void SpinButtonElement::startRepeatingTimer() { m_pressStartingState = m_upDownState; ScrollbarTheme* theme = ScrollbarTheme::nativeTheme(); m_repeatingTimer.start(theme->initialAutoscrollTimerDelay(), theme->autoscrollTimerDelay()); }
bool canUseFor(const RenderBlockFlow& flow) { #if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(EFL) // FIXME: Non-mac platforms are hitting ASSERT(run.charactersLength() >= run.length()) // https://bugs.webkit.org/show_bug.cgi?id=123338 return false; #else if (!flow.frame().settings().simpleLineLayoutEnabled()) return false; if (!flow.firstChild()) return false; // This currently covers <blockflow>#text</blockflow> case. // The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover. if (flow.firstChild() != flow.lastChild()) return false; if (!flow.firstChild()->isText()) return false; if (!flow.isHorizontalWritingMode()) return false; if (flow.flowThreadState() != RenderObject::NotInsideFlowThread) return false; if (flow.hasOutline()) return false; if (flow.isRubyText() || flow.isRubyBase()) return false; if (flow.parent()->isDeprecatedFlexibleBox()) return false; // FIXME: Implementation of wrap=hard looks into lineboxes. if (flow.parent()->isTextArea() && flow.parent()->element()->fastHasAttribute(HTMLNames::wrapAttr)) return false; // FIXME: Placeholders do something strange. if (flow.parent()->isTextControl() && toRenderTextControl(*flow.parent()).textFormControlElement().placeholderElement()) return false; // These tests only works during layout. Outside layout this function may give false positives. if (flow.view().layoutState()) { #if ENABLE(CSS_SHAPES) if (flow.view().layoutState()->shapeInsideInfo()) return false; #endif if (flow.view().layoutState()->m_columnInfo) return false; } const RenderStyle& style = flow.style(); if (style.textDecorationsInEffect() != TextDecorationNone) return false; if (style.textAlign() == JUSTIFY) return false; // Non-visible overflow should be pretty easy to support. if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE) return false; if (!style.textIndent().isZero()) return false; if (style.wordSpacing() || style.letterSpacing()) return false; if (style.textTransform() != TTNONE) return false; if (!style.isLeftToRightDirection()) return false; if (style.lineBoxContain() != RenderStyle::initialLineBoxContain()) return false; if (style.writingMode() != TopToBottomWritingMode) return false; if (style.lineBreak() != LineBreakAuto) return false; if (style.wordBreak() != NormalWordBreak) return false; if (style.unicodeBidi() != UBNormal || style.rtlOrdering() != LogicalOrder) return false; if (style.lineAlign() != LineAlignNone || style.lineSnap() != LineSnapNone) return false; if (style.hyphens() == HyphensAuto) return false; if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone) return false; if (style.textShadow()) return false; #if ENABLE(CSS_SHAPES) if (style.resolvedShapeInside()) return true; #endif if (style.textOverflow() || (flow.isAnonymousBlock() && flow.parent()->style().textOverflow())) return false; if (style.hasPseudoStyle(FIRST_LINE) || style.hasPseudoStyle(FIRST_LETTER)) return false; if (style.hasTextCombine()) return false; if (style.backgroundClip() == TextFillBox) return false; if (style.borderFit() == BorderFitLines) return false; const RenderText& textRenderer = toRenderText(*flow.firstChild()); if (flow.containsFloats()) { // We can't use the code path if any lines would need to be shifted below floats. This is because we don't keep per-line y coordinates. // It is enough to test the first line width only as currently all floats must be overhanging. if (textRenderer.minLogicalWidth() > LineWidth(const_cast<RenderBlockFlow&>(flow), false, DoNotIndentText).availableWidth()) return false; } if (textRenderer.isCombineText() || textRenderer.isCounter() || textRenderer.isQuote() || textRenderer.isTextFragment() #if ENABLE(SVG) || textRenderer.isSVGInlineText() #endif ) return false; if (style.font().codePath(TextRun(textRenderer.text())) != Font::Simple) return false; if (style.font().isSVGFont()) return false; // We assume that all lines have metrics based purely on the primary font. auto& primaryFontData = *style.font().primaryFont(); if (primaryFontData.isLoading()) return false; if (!canUseForText(textRenderer, primaryFontData)) return false; return true; #endif }
bool canUseFor(const RenderBlockFlow& flow) { if (!flow.frame().settings().simpleLineLayoutEnabled()) return false; if (!flow.firstChild()) return false; // This currently covers <blockflow>#text</blockflow> case. // The <blockflow><inline>#text</inline></blockflow> case is also popular and should be relatively easy to cover. if (flow.firstChild() != flow.lastChild()) return false; if (!flow.firstChild()->isText()) return false; if (!flow.isHorizontalWritingMode()) return false; if (flow.flowThreadState() != RenderObject::NotInsideFlowThread) return false; if (flow.hasOutline()) return false; if (flow.isRubyText() || flow.isRubyBase()) return false; if (flow.parent()->isDeprecatedFlexibleBox()) return false; // FIXME: Implementation of wrap=hard looks into lineboxes. if (flow.parent()->isTextArea() && flow.parent()->element()->fastHasAttribute(HTMLNames::wrapAttr)) return false; // FIXME: Placeholders do something strange. if (flow.parent()->isTextControl() && toRenderTextControl(*flow.parent()).textFormControlElement().placeholderElement()) return false; const RenderStyle& style = flow.style(); if (style.textDecorationsInEffect() != TextDecorationNone) return false; if (style.textAlign() == JUSTIFY) return false; // Non-visible overflow should be pretty easy to support. if (style.overflowX() != OVISIBLE || style.overflowY() != OVISIBLE) return false; if (!style.textIndent().isZero()) return false; if (!style.wordSpacing().isZero() || style.letterSpacing()) return false; if (style.textTransform() != TTNONE) return false; if (!style.isLeftToRightDirection()) return false; if (style.lineBoxContain() != RenderStyle::initialLineBoxContain()) return false; if (style.writingMode() != TopToBottomWritingMode) return false; if (style.lineBreak() != LineBreakAuto) return false; if (style.wordBreak() != NormalWordBreak) return false; if (style.unicodeBidi() != UBNormal || style.rtlOrdering() != LogicalOrder) return false; if (style.lineAlign() != LineAlignNone || style.lineSnap() != LineSnapNone) return false; if (style.hyphens() == HyphensAuto) return false; if (style.textEmphasisFill() != TextEmphasisFillFilled || style.textEmphasisMark() != TextEmphasisMarkNone) return false; if (style.textShadow()) return false; if (style.textOverflow() || (flow.isAnonymousBlock() && flow.parent()->style().textOverflow())) return false; if (style.hasPseudoStyle(FIRST_LINE) || style.hasPseudoStyle(FIRST_LETTER)) return false; if (style.hasTextCombine()) return false; if (style.backgroundClip() == TextFillBox) return false; if (style.borderFit() == BorderFitLines) return false; const RenderText& textRenderer = toRenderText(*flow.firstChild()); if (flow.containsFloats()) { // We can't use the code path if any lines would need to be shifted below floats. This is because we don't keep per-line y coordinates. float minimumWidthNeeded = textRenderer.minLogicalWidth(); for (auto& floatRenderer : *flow.floatingObjectSet()) { ASSERT(floatRenderer); float availableWidth = flow.availableLogicalWidthForLine(floatRenderer->y(), false); if (availableWidth < minimumWidthNeeded) return false; } } if (textRenderer.isCombineText() || textRenderer.isCounter() || textRenderer.isQuote() || textRenderer.isTextFragment() || textRenderer.isSVGInlineText()) return false; if (style.font().codePath(TextRun(textRenderer.text())) != Font::Simple) return false; if (style.font().isSVGFont()) return false; // We assume that all lines have metrics based purely on the primary font. auto& primaryFontData = *style.font().primaryFont(); if (primaryFontData.isLoading()) return false; if (!canUseForText(textRenderer, primaryFontData)) return false; return true; }
static RenderTextControl* rendererAfterUpdateLayout(HTMLTextAreaElement* element) { element->document()->updateLayoutIgnorePendingStylesheets(); return toRenderTextControl(element->renderer()); }