Commit 4ef836ad authored by Rune Lillesveen's avatar Rune Lillesveen Committed by Commit Bot

[Squad] Make style of inner editor not rely on LayoutObject.

Move custom style computation to TextControlInnerEditorElement and make
sure its style does not rely on the input host LayoutObject. Necessary
to be able to compute all elements' style in the RecalcStyle pass.

Bug: 813057
Change-Id: I823ca67b5ddaba08ce7adfc26a29f45f73d88b8f
Reviewed-on: https://chromium-review.googlesource.com/925701
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: default avatarKent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550589}
parent 873cba5e
......@@ -21,7 +21,7 @@ Input before setting suggested values:
| <div>
| id="placeholder"
| pseudo="-webkit-input-placeholder"
| style="display: block !important; text-overflow: clip;"
| style="display: block !important;"
| shadow:pseudoId="-webkit-input-placeholder"
| "initial placeholder"
| <div>
......@@ -104,7 +104,7 @@ Input after setting suggestedValue:
| <div>
| id="placeholder"
| pseudo="-internal-input-suggested"
| style="display: block !important; text-overflow: clip;"
| style="display: block !important;"
| shadow:pseudoId="-internal-input-suggested"
| "suggested value"
| <div>
......@@ -197,7 +197,7 @@ After resetting suggestedValue value:
| <div>
| id="placeholder"
| pseudo="-webkit-input-placeholder"
| style="display: block !important; text-overflow: clip;"
| style="display: block !important;"
| shadow:pseudoId="-webkit-input-placeholder"
| "initial placeholder"
| <div>
......
......@@ -510,6 +510,7 @@ textarea {
}
input::-webkit-input-placeholder {
text-overflow: inherit;
line-height: initial;
white-space: pre;
word-wrap: normal;
......@@ -518,7 +519,7 @@ input::-webkit-input-placeholder {
}
input::-internal-input-suggested {
text-overflow: ellipsis;
text-overflow: inherit;
white-space: nowrap;
overflow: hidden;
}
......
......@@ -667,6 +667,24 @@ void StyleAdjuster::AdjustComputedStyle(StyleResolverState& state,
}
}
if (element && style.TextOverflow() == ETextOverflow::kEllipsis) {
const AtomicString& pseudo_id = element->ShadowPseudoId();
if (pseudo_id == "-webkit-input-placeholder" ||
pseudo_id == "-internal-input-suggested") {
TextControlElement* text_control =
ToTextControl(element->OwnerShadowHost());
DCHECK(text_control);
// TODO(futhark@chromium.org): We force clipping text overflow for focused
// input elements since we don't want to render ellipsis during editing.
// We should do this as a general solution which also includes
// contenteditable elements being edited. The computed style should not
// change, but LayoutBlockFlow::ShouldTruncateOverflowingText() should
// instead return false when text is being edited inside that block.
// https://crbug.com/814954
style.SetTextOverflow(text_control->ValueForTextOverflow());
}
}
if (RuntimeEnabledFeatures::LayoutNGEnabled() && !style.ForceLegacyLayout() &&
element) {
const Document& document = element->GetDocument();
......
......@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
......@@ -953,13 +954,11 @@ void TextControlElement::SetSuggestedValue(const String& value) {
if (!suggested_value_.IsEmpty() && !InnerEditorValue().IsEmpty()) {
// If there is an inner editor value, hide it so the suggested value can be
// shown to the user.
static_cast<TextControlInnerEditorElement*>(InnerEditorElement())
->SetVisibility(false);
InnerEditorElement()->SetVisibility(false);
} else if (suggested_value_.IsEmpty() && InnerEditorElement()) {
// If there is no suggested value and there is an InnerEditorElement, reset
// its visibility.
static_cast<TextControlInnerEditorElement*>(InnerEditorElement())
->SetVisibility(true);
InnerEditorElement()->SetVisibility(true);
}
UpdatePlaceholderText();
......@@ -1003,4 +1002,10 @@ void TextControlElement::CloneNonAttributePropertiesFrom(
HTMLFormControlElement::CloneNonAttributePropertiesFrom(source, flag);
}
ETextOverflow TextControlElement::ValueForTextOverflow() const {
if (GetDocument().FocusedElement() == this)
return ETextOverflow::kClip;
return ComputedStyleRef().TextOverflow();
}
} // namespace blink
......@@ -31,6 +31,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element_with_state.h"
#include "third_party/blink/renderer/core/html/forms/text_control_inner_elements.h"
namespace blink {
......@@ -126,7 +127,9 @@ class CORE_EXPORT TextControlElement : public HTMLFormControlElementWithState {
TextControlSetValueSelection =
TextControlSetValueSelection::kSetSelectionToEnd) = 0;
HTMLElement* InnerEditorElement() const { return inner_editor_; }
TextControlInnerEditorElement* InnerEditorElement() const {
return inner_editor_;
}
HTMLElement* CreateInnerEditorElement();
void DropInnerEditorElement() { inner_editor_ = nullptr; }
......@@ -147,6 +150,8 @@ class CORE_EXPORT TextControlElement : public HTMLFormControlElementWithState {
void Trace(Visitor*) override;
ETextOverflow ValueForTextOverflow() const;
protected:
TextControlElement(const QualifiedName&, Document&);
bool IsPlaceholderEmpty() const;
......@@ -206,7 +211,7 @@ class CORE_EXPORT TextControlElement : public HTMLFormControlElementWithState {
// Held directly instead of looked up by ID for speed.
// Not only is the lookup faster, but for simple text inputs it avoids
// creating a number of TreeScope data structures to track elements by ID.
Member<HTMLElement> inner_editor_;
Member<TextControlInnerEditorElement> inner_editor_;
// In m_valueBeforeFirstUserEdit, we distinguish a null String and zero-length
// String. Null String means the field doesn't have any data yet, and
......
......@@ -142,12 +142,7 @@ LayoutObject* TextControlInnerEditorElement::CreateLayoutObject(
scoped_refptr<ComputedStyle>
TextControlInnerEditorElement::CustomStyleForLayoutObject() {
LayoutObject* parent_layout_object = OwnerShadowHost()->GetLayoutObject();
if (!parent_layout_object || !parent_layout_object->IsTextControl())
return OriginalStyleForLayoutObject();
LayoutTextControl* text_control = ToLayoutTextControl(parent_layout_object);
scoped_refptr<ComputedStyle> inner_editor_style =
text_control->CreateInnerEditorStyle(text_control->StyleRef());
scoped_refptr<ComputedStyle> inner_editor_style = CreateInnerEditorStyle();
// Using StyleAdjuster::adjustComputedStyle updates unwanted style. We'd like
// to apply only editing-related and alignment-related.
StyleAdjuster::AdjustStyleForEditing(*inner_editor_style);
......@@ -156,6 +151,70 @@ TextControlInnerEditorElement::CustomStyleForLayoutObject() {
return inner_editor_style;
}
scoped_refptr<ComputedStyle>
TextControlInnerEditorElement::CreateInnerEditorStyle() const {
Element* host = OwnerShadowHost();
DCHECK(host);
const ComputedStyle& start_style = host->ComputedStyleRef();
scoped_refptr<ComputedStyle> text_block_style = ComputedStyle::Create();
text_block_style->InheritFrom(start_style);
// The inner block, if present, always has its direction set to LTR,
// so we need to inherit the direction and unicode-bidi style from the
// element.
text_block_style->SetDirection(start_style.Direction());
text_block_style->SetUnicodeBidi(start_style.GetUnicodeBidi());
text_block_style->SetUserSelect(EUserSelect::kText);
text_block_style->SetUserModify(
ToHTMLFormControlElement(host)->IsDisabledOrReadOnly()
? EUserModify::kReadOnly
: EUserModify::kReadWritePlaintextOnly);
text_block_style->SetDisplay(EDisplay::kBlock);
text_block_style->SetUnique();
if (!IsHTMLTextAreaElement(host)) {
text_block_style->SetWhiteSpace(EWhiteSpace::kPre);
text_block_style->SetOverflowWrap(EOverflowWrap::kNormal);
text_block_style->SetTextOverflow(
ToTextControl(host)->ValueForTextOverflow());
int computed_line_height = start_style.ComputedLineHeight();
// Do not allow line-height to be smaller than our default.
if (text_block_style->FontSize() >= computed_line_height) {
text_block_style->SetLineHeight(
ComputedStyleInitialValues::InitialLineHeight());
}
// We'd like to remove line-height if it's unnecessary because
// overflow:scroll clips editing text by line-height.
Length logical_height = start_style.LogicalHeight();
// Here, we remove line-height if the INPUT fixed height is taller than the
// line-height. It's not the precise condition because logicalHeight
// includes border and padding if box-sizing:border-box, and there are cases
// in which we don't want to remove line-height with percent or calculated
// length.
// TODO(tkent): This should be done during layout.
if (logical_height.IsPercentOrCalc() ||
(logical_height.IsFixed() &&
logical_height.GetFloatValue() > computed_line_height)) {
text_block_style->SetLineHeight(
ComputedStyleInitialValues::InitialLineHeight());
}
if (ToHTMLInputElement(host)->ShouldRevealPassword())
text_block_style->SetTextSecurity(ETextSecurity::kNone);
text_block_style->SetOverflowX(EOverflow::kScroll);
// overflow-y:visible doesn't work because overflow-x:scroll makes a layer.
text_block_style->SetOverflowY(EOverflow::kScroll);
scoped_refptr<ComputedStyle> no_scrollbar_style = ComputedStyle::Create();
no_scrollbar_style->SetStyleType(kPseudoIdScrollbar);
no_scrollbar_style->SetDisplay(EDisplay::kNone);
text_block_style->AddCachedPseudoStyle(no_scrollbar_style);
text_block_style->SetHasPseudoStyle(kPseudoIdScrollbar);
}
return text_block_style;
}
// ----------------------------
inline SearchFieldCancelButtonElement::SearchFieldCancelButtonElement(
......
......@@ -60,6 +60,7 @@ class TextControlInnerEditorElement final : public HTMLDivElement {
void DefaultEventHandler(Event*) override;
void SetVisibility(bool is_visible);
scoped_refptr<ComputedStyle> CreateInnerEditorStyle() const;
private:
explicit TextControlInnerEditorElement(Document&);
......
......@@ -41,14 +41,14 @@ TextControlElement* LayoutTextControl::GetTextControlElement() const {
return ToTextControl(GetNode());
}
HTMLElement* LayoutTextControl::InnerEditorElement() const {
TextControlInnerEditorElement* LayoutTextControl::InnerEditorElement() const {
return GetTextControlElement()->InnerEditorElement();
}
void LayoutTextControl::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
LayoutBlockFlow::StyleDidChange(diff, old_style);
Element* inner_editor = InnerEditorElement();
TextControlInnerEditorElement* inner_editor = InnerEditorElement();
if (!inner_editor)
return;
LayoutBlock* inner_editor_layout_object =
......@@ -58,7 +58,8 @@ void LayoutTextControl::StyleDidChange(StyleDifference diff,
// Reset them now to avoid getting a spurious layout hint.
inner_editor_layout_object->MutableStyleRef().SetHeight(Length());
inner_editor_layout_object->MutableStyleRef().SetWidth(Length());
inner_editor_layout_object->SetStyle(CreateInnerEditorStyle(StyleRef()));
inner_editor_layout_object->SetStyle(
inner_editor->CreateInnerEditorStyle());
inner_editor->SetNeedsStyleRecalc(
kSubtreeStyleChange,
StyleChangeReasonForTracing::Create(StyleChangeReason::kControl));
......@@ -82,18 +83,6 @@ static inline void UpdateUserModifyProperty(TextControlElement& node,
: EUserModify::kReadWritePlaintextOnly);
}
void LayoutTextControl::AdjustInnerEditorStyle(
ComputedStyle& text_block_style) const {
// The inner block, if present, always has its direction set to LTR,
// so we need to inherit the direction and unicode-bidi style from the
// element.
text_block_style.SetDirection(Style()->Direction());
text_block_style.SetUnicodeBidi(Style()->GetUnicodeBidi());
text_block_style.SetUserSelect(EUserSelect::kText);
UpdateUserModifyProperty(*GetTextControlElement(), text_block_style);
}
int LayoutTextControl::TextBlockLogicalHeight() const {
return (LogicalHeight() - BorderAndPaddingLogicalHeight()).ToInt();
}
......
......@@ -30,15 +30,13 @@
namespace blink {
class TextControlElement;
class TextControlInnerEditorElement;
class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
public:
~LayoutTextControl() override;
TextControlElement* GetTextControlElement() const;
virtual scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
const ComputedStyle& start_style) const = 0;
const char* GetName() const override { return "LayoutTextControl"; }
protected:
......@@ -46,10 +44,9 @@ class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
// This convenience function should not be made public because
// innerEditorElement may outlive the layout tree.
HTMLElement* InnerEditorElement() const;
TextControlInnerEditorElement* InnerEditorElement() const;
int ScrollbarThickness() const;
void AdjustInnerEditorStyle(ComputedStyle& text_block_style) const;
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
......
......@@ -88,17 +88,6 @@ LayoutUnit LayoutTextControlMultiLine::BaselinePosition(
line_position_mode);
}
scoped_refptr<ComputedStyle> LayoutTextControlMultiLine::CreateInnerEditorStyle(
const ComputedStyle& start_style) const {
scoped_refptr<ComputedStyle> text_block_style = ComputedStyle::Create();
text_block_style->InheritFrom(start_style);
AdjustInnerEditorStyle(*text_block_style);
text_block_style->SetDisplay(EDisplay::kBlock);
text_block_style->SetUnique();
return text_block_style;
}
LayoutObject* LayoutTextControlMultiLine::LayoutSpecialExcludedChild(
bool relayout_children,
SubtreeLayoutScope& layout_scope) {
......
......@@ -60,8 +60,6 @@ class LayoutTextControlMultiLine final : public LayoutTextControl {
return LayoutUnit(-1);
}
scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
const ComputedStyle& start_style) const override;
LayoutObject* LayoutSpecialExcludedChild(bool relayout_children,
SubtreeLayoutScope&) override;
};
......
......@@ -200,16 +200,6 @@ bool LayoutTextControlSingleLine::NodeAtPoint(
return true;
}
void LayoutTextControlSingleLine::StyleDidChange(
StyleDifference diff,
const ComputedStyle* old_style) {
LayoutTextControl::StyleDidChange(diff, old_style);
if (HTMLElement* placeholder = InputElement()->PlaceholderElement())
placeholder->SetInlineStyleProperty(
CSSPropertyTextOverflow,
TextShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip);
}
void LayoutTextControlSingleLine::CapsLockStateMayHaveChanged() {
if (!GetNode())
return;
......@@ -304,66 +294,6 @@ LayoutUnit LayoutTextControlSingleLine::ComputeControlLogicalHeight(
return line_height + non_content_height;
}
scoped_refptr<ComputedStyle>
LayoutTextControlSingleLine::CreateInnerEditorStyle(
const ComputedStyle& start_style) const {
scoped_refptr<ComputedStyle> text_block_style = ComputedStyle::Create();
text_block_style->InheritFrom(start_style);
AdjustInnerEditorStyle(*text_block_style);
text_block_style->SetWhiteSpace(EWhiteSpace::kPre);
text_block_style->SetOverflowWrap(EOverflowWrap::kNormal);
text_block_style->SetTextOverflow(TextShouldBeTruncated()
? ETextOverflow::kEllipsis
: ETextOverflow::kClip);
int computed_line_height =
LineHeight(true, kHorizontalLine, kPositionOfInteriorLineBoxes).ToInt();
// Do not allow line-height to be smaller than our default.
if (text_block_style->FontSize() >= computed_line_height) {
text_block_style->SetLineHeight(
ComputedStyleInitialValues::InitialLineHeight());
}
// We'd like to remove line-height if it's unnecessary because
// overflow:scroll clips editing text by line-height.
Length logical_height = start_style.LogicalHeight();
// Here, we remove line-height if the INPUT fixed height is taller than the
// line-height. It's not the precise condition because logicalHeight
// includes border and padding if box-sizing:border-box, and there are cases
// in which we don't want to remove line-height with percent or calculated
// length.
// TODO(tkent): This should be done during layout.
if (logical_height.IsPercentOrCalc() ||
(logical_height.IsFixed() &&
logical_height.GetFloatValue() > computed_line_height)) {
text_block_style->SetLineHeight(
ComputedStyleInitialValues::InitialLineHeight());
}
text_block_style->SetDisplay(EDisplay::kBlock);
text_block_style->SetUnique();
if (InputElement()->ShouldRevealPassword())
text_block_style->SetTextSecurity(ETextSecurity::kNone);
text_block_style->SetOverflowX(EOverflow::kScroll);
// overflow-y:visible doesn't work because overflow-x:scroll makes a layer.
text_block_style->SetOverflowY(EOverflow::kScroll);
scoped_refptr<ComputedStyle> no_scrollbar_style = ComputedStyle::Create();
no_scrollbar_style->SetStyleType(kPseudoIdScrollbar);
no_scrollbar_style->SetDisplay(EDisplay::kNone);
text_block_style->AddCachedPseudoStyle(no_scrollbar_style);
text_block_style->SetHasPseudoStyle(kPseudoIdScrollbar);
return text_block_style;
}
bool LayoutTextControlSingleLine::TextShouldBeTruncated() const {
return GetDocument().FocusedElement() != GetNode() &&
StyleRef().TextOverflow() == ETextOverflow::kEllipsis;
}
void LayoutTextControlSingleLine::Autoscroll(const IntPoint& position) {
LayoutBox* layout_object = InnerEditorElement()->GetLayoutBox();
if (!layout_object)
......
......@@ -35,9 +35,6 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
public:
LayoutTextControlSingleLine(HTMLInputElement*);
~LayoutTextControlSingleLine() override;
// FIXME: Move createInnerEditorStyle() to TextControlInnerEditorElement.
scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
const ComputedStyle& start_style) const final;
void CapsLockStateMayHaveChanged();
......@@ -77,12 +74,10 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
LayoutUnit ComputeControlLogicalHeight(
LayoutUnit line_height,
LayoutUnit non_content_height) const override;
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) final;
void AddOverflowFromChildren() final;
bool AllowsOverflowClip() const override { return false; }
bool TextShouldBeTruncated() const;
HTMLElement* InnerSpinButtonElement() const;
bool should_draw_caps_lock_indicator_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment