Skip to content
Permalink
Browse files
MIR Image replacement technique (negative letter-spacing) does not al…
…ways work

https://bugs.webkit.org/show_bug.cgi?id=3676
<rdar://problem/96534455>

Reviewed by Antti Koivisto.

Do not let the negative letter-spacing pull content to the logical left direction from outside
of the inline box (or in other words, do not let (negative) letter spacing spill out of the inline box).

* LayoutTests/fast/inline/negative-letter-spacing-on-inline-box-expected.html: Added.
* LayoutTests/fast/inline/negative-letter-spacing-on-inline-box.html: Added.
* Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp:
(WebCore::Layout::Line::appendInlineBoxStart):
(WebCore::Layout::Line::appendInlineBoxEnd): Empty stack means line spanning inline box.
* Source/WebCore/layout/formattingContexts/inline/InlineLine.h:

Canonical link: https://commits.webkit.org/258356@main
  • Loading branch information
alanbaradlay committed Dec 29, 2022
1 parent 5f782c4 commit 4aee4f4a4f9de2de3b6a0b546aa9d38cb27d5892
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 5 deletions.
@@ -0,0 +1,18 @@
<style>
div {
font-size: 20px;
font-family: Monospace;
margin: 10px;
border: 1px solid;
overflow: hidden;
}
span {
color: transparent;
letter-spacing: -2em;
}
</style>
<div>PASS if this is visible</div>
<div><br>PASS if this is visible</div>
<div><span style="margin-left: -5px;"></span>PASS if this is partially visible</div>
<div><span style="margin-right: -5px;"></span>PASS if this is partially visible</div>
<div><span style="margin: -2.5px;"></span>PASS if this is partially visible</div>
@@ -0,0 +1,18 @@
<style>
div {
font-size: 20px;
font-family: Monospace;
margin: 10px;
border: 1px solid;
overflow: hidden;
}
span {
color: transparent;
letter-spacing: -2em;
}
</style>
<div><span>XX</span>PASS if this is visible</div>
<div><span>X<br>X</span>PASS if this is visible</div>
<div><span style="margin-left: -5px;">XX</span>PASS if this is partially visible</div>
<div><span style="margin-right: -5px;">XX</span>PASS if this is partially visible</div>
<div><span style="margin: -2.5px;">XX</span>PASS if this is partially visible</div>
@@ -56,6 +56,7 @@ void Line::initialize(const Vector<InlineItem>& lineSpanningInlineBoxes, bool is
m_nonSpanningInlineLevelBoxCount = 0;
m_hasNonDefaultBidiLevelRun = false;
m_contentLogicalWidth = { };
m_inlineBoxLogicalLeftStack.clear();
m_runs.clear();
resetTrailingContent();
auto appendLineSpanningInlineBoxes = [&] {
@@ -381,12 +382,18 @@ void Line::appendInlineBoxStart(const InlineItem& inlineItem, const RenderStyle&
m_contentLogicalWidth = std::max(m_contentLogicalWidth, logicalLeft + logicalWidth);

auto marginStart = inlineBoxGeometry.marginStart();
if (marginStart >= 0) {
m_runs.append({ inlineItem, style, logicalLeft, logicalWidth - borderAndPaddingEndForDecorationClone });
return;
if (marginStart < 0) {
// Negative margin-start pulls the content to the logical left direction.
logicalLeft += marginStart;
logicalWidth -= marginStart;
}
// Negative margin-start pulls the content to the logical left direction.
m_runs.append({ inlineItem, style, logicalLeft + marginStart, logicalWidth - marginStart - borderAndPaddingEndForDecorationClone });
logicalWidth -= borderAndPaddingEndForDecorationClone;

auto mayPullNonInlineBoxContentToLogicalLeft = style.letterSpacing() < 0;
if (mayPullNonInlineBoxContentToLogicalLeft)
m_inlineBoxLogicalLeftStack.append(logicalLeft);

m_runs.append({ inlineItem, style, logicalLeft, logicalWidth });
}

void Line::appendInlineBoxEnd(const InlineItem& inlineItem, const RenderStyle& style, InlineLayoutUnit logicalWidth)
@@ -404,6 +411,12 @@ void Line::appendInlineBoxEnd(const InlineItem& inlineItem, const RenderStyle& s
removeTrailingLetterSpacing();
m_contentLogicalWidth -= removeBorderAndPaddingEndForInlineBoxDecorationClone(inlineItem);
auto logicalLeft = lastRunLogicalRight();
auto mayPullNonInlineBoxContentToLogicalLeft = style.letterSpacing() < 0;
if (mayPullNonInlineBoxContentToLogicalLeft) {
// Do not let negative spacing pull content to the left of the inline box logical left.
// e.g. <span style="border-left: solid red; letter-spacing: -200px;">content</span>This should not be to the left of the red border)
logicalLeft = std::max(logicalLeft, m_inlineBoxLogicalLeftStack.isEmpty() ? 0.f : m_inlineBoxLogicalLeftStack.takeLast());
}
m_runs.append({ inlineItem, style, logicalLeft, logicalWidth });
// Do not let negative margin make the content shorter than it already is.
m_contentLogicalWidth = std::max(m_contentLogicalWidth, logicalLeft + logicalWidth);
@@ -283,6 +283,7 @@ class Line {
bool m_hasNonDefaultBidiLevelRun { false };
bool m_contentIsTruncated { false };
bool m_isFirstFormattedLine { false };
Vector<InlineLayoutUnit> m_inlineBoxLogicalLeftStack;
};

inline bool Line::hasContent() const

0 comments on commit 4aee4f4

Please sign in to comment.