Bug 3676 - MIR Image replacement technique (negative letter-spacing) does not always work
Summary: MIR Image replacement technique (negative letter-spacing) does not always work
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Layout and Rendering (show other bugs)
Version: 412
Hardware: All All
: P2 Normal
Assignee: zalan
URL:
Keywords: BrowserCompat, InRadar
Depends on:
Blocks:
 
Reported: 2005-06-23 05:08 PDT by Niels Leenheer (HTML5test)
Modified: 2022-12-29 12:40 PST (History)
7 users (show)

See Also:


Attachments
Testcase (888 bytes, text/html)
2005-06-23 05:11 PDT, Niels Leenheer (HTML5test)
no flags Details
Possible patch (756 bytes, patch)
2005-06-23 05:12 PDT, Niels Leenheer (HTML5test)
no flags Details | Formatted Diff | Diff
testcase for negative-letter-spacing (573 bytes, text/html)
2022-12-26 18:44 PST, Karl Dubost
no flags Details
rendering in safari, firefox, chrome (113.14 KB, image/png)
2022-12-26 18:46 PST, Karl Dubost
no flags Details
Test reduction (206 bytes, text/html)
2022-12-28 20:39 PST, zalan
no flags Details
Test case screenshot (13.23 KB, image/png)
2022-12-28 21:23 PST, zalan
no flags Details
Test case screenshot (2) (24.30 KB, image/png)
2022-12-28 21:24 PST, zalan
no flags Details
test case screenshot (original) (121.90 KB, image/png)
2022-12-28 21:25 PST, zalan
no flags Details
Patch (6.60 KB, patch)
2022-12-29 10:39 PST, zalan
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Niels Leenheer (HTML5test) 2005-06-23 05:08:29 PDT
If a letter-spacing is applied to text each character is written seperately.
After each letter is written the width of that character is added to the x
coordinate. Then the letter-spacing will be added and the next character is
drawn at the new x coordinate. The difference between the old x and the new x is
what I call deltax below.

A positive letter-spacing means that deltax is larger than it would have been if
the letter-spacing was not applied. Similarly, a negative letter-spacing means
that deltax is smaller than it would have been if the letter-spacing was not
applied. 

CURRENT BEHAVOIR:
If you increase the negative letter-spacing it will eventually become larger
than the width of the characters and at that point deltax will become negative
and the text starts to flow backwards.

If the width of the negative letter-spacing is larger than the width of a
character the text will run backwards. This can be demonstrated by the following
little snipped of HTML:

<h1 style='padding-left: 10em; letter-spacing: -32px;'>The quick brown
fox...</h1>"

This is displayed as:
...xof nworb kciuq ehT


DESIRED BEHAVOIR:
If you increase the negative letter-spacing it will eventually become larger
than the width of the characters and at that point deltax will become negative.
If deltax is don't draw the character. This means that text that used to flow
backwards now simply is not shown at all, as desired by the MIR image
replacement technique.
Comment 1 Niels Leenheer (HTML5test) 2005-06-23 05:11:24 PDT
Created attachment 2580 [details]
Testcase

This testcase contains 10 lines.
- Line 1 - 3 should contain the string 
  "The quick brown fox jumps..." in various letter spacings.
- Line 4 - 9 should be completely empty.
- Line 10 should contain the string 
  "The quick brown  over the lazy dog".
Comment 2 Niels Leenheer (HTML5test) 2005-06-23 05:12:25 PDT
Created attachment 2581 [details]
Possible patch

This seems too simple, but it does solve the problem on 
various testcases and live websites. Any comments?
Comment 3 Ian 'Hixie' Hickson 2005-06-23 07:23:05 PDT
This is invalid. Negative letter spacing _should_ make the text go backwards.
That fact that it doesn't in other browsers is a bug in those browsers.
Comment 4 Ian 'Hixie' Hickson 2005-06-23 07:32:13 PDT
Filed https://bugzilla.mozilla.org/show_bug.cgi?id=298579
Comment 5 Niels Leenheer (HTML5test) 2005-06-23 23:47:17 PDT
The CSS 2.1 spec says the following about negative letter-spacing:

   Values may be negative, but there may be implementation-specific limits.

At the moment the two browsers that are used most, Internet Explorer
and Firefox both have an implementation-specific limit that result in
the text disappearing when a large negative value is used. 

Emulating the behavoir of those two browsers and adding an artificial
limit to KHTML/Webcore is not contrary to the CSS 2.1 spec. On the other
hand it will improve compatibility with websites that employ the MIR
image replacement technique, which depends on the behavoir of IE and
Firefox.
Comment 6 Dave Hyatt 2005-06-24 11:32:41 PDT
Agreed.
Comment 7 Ian 'Hixie' Hickson 2005-06-25 18:09:34 PDT
Doing what IE does here is stupid. It makes it impossible to achieve several
dynamic effects. Opera already does the right thing here, as will Mozilla in due
course. The implementation-specific limits clause is not supposed to mean you
can fail to do the right thing if you want to, it's to allow small devices that
can't handle negative numbers to do a "best effort" rendering.

This bug is INVALID. If it is "fixed" it should be in quirks mode only, and
important pages that it breaks should be listed.
Comment 8 Dave Hyatt 2005-06-25 19:18:11 PDT
Can someone from Gecko comment on whether they intend to fix the bug?  If they don't, then I feel that 
we should change  to match.
Comment 9 Robert O'Callahan 2006-04-16 17:49:52 PDT
I think it's a bug that we should fix in Gecko.
Comment 10 Brent Fulgham 2022-07-06 11:29:47 PDT
We do not have the same behavior as Chrome or Firefox for the final line of the test case (the string with multiple colors).
Comment 11 Radar WebKit Bug Importer 2022-07-06 11:30:02 PDT
<rdar://problem/96534455>
Comment 12 Karl Dubost 2022-12-26 18:44:45 PST
Created attachment 464215 [details]
testcase for negative-letter-spacing

As Brent said, Only the last test case is now failing.
Let's make it simpler and easier to understand what is happening.
Comment 13 Karl Dubost 2022-12-26 18:46:33 PST
Created attachment 464216 [details]
rendering in safari, firefox, chrome

Tested on macOS 13.3
---
Safari Technology Preview  160           18615.1.14.3
Firefox Nightly            110.0a1       11022.12.14
Google Chrome Canary       111.0.5499.0  5499.0
Comment 14 zalan 2022-12-28 20:39:53 PST
Created attachment 464239 [details]
Test reduction

Thank you Karl for the negative letter-spacing test case.
Comment 15 zalan 2022-12-28 21:23:41 PST
Created attachment 464241 [details]
Test case screenshot

This fixes both test cases.

diff --git a/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp b/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
index a1d927521680..7d84517d22cd 100644
--- a/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
+++ b/Source/WebCore/layout/formattingContexts/inline/InlineLine.cpp
@@ -403,7 +403,8 @@ void Line::appendInlineBoxEnd(const InlineItem& inlineItem, const RenderStyle& s
     // https://drafts.csswg.org/css-text-3/#letter-spacing-property See example 21.
     removeTrailingLetterSpacing();
     m_contentLogicalWidth -= removeBorderAndPaddingEndForInlineBoxDecorationClone(inlineItem);
-    auto logicalLeft = lastRunLogicalRight();
+    // Negative letter spacing should only shorten the content to the boundary of the previous run.
+    auto logicalLeft = style.letterSpacing() < 0 ? m_contentLogicalWidth : lastRunLogicalRight();
     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);
Comment 16 zalan 2022-12-28 21:24:11 PST
Created attachment 464242 [details]
Test case screenshot (2)
Comment 17 zalan 2022-12-28 21:25:28 PST
Created attachment 464243 [details]
test case screenshot (original)
Comment 18 zalan 2022-12-29 10:39:32 PST
Created attachment 464249 [details]
Patch
Comment 19 Antti Koivisto 2022-12-29 11:18:35 PST
Comment on attachment 464249 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=464249&action=review

> COMMIT_MESSAGE:2
> +https://bugs.webkit.org/show_bug.cgi?id=3676

nice!
Comment 20 Antti Koivisto 2022-12-29 11:54:15 PST
Comment on attachment 2581 [details]
Possible patch

View in context: https://bugs.webkit.org/attachment.cgi?id=2581&action=review

> font.cpp:107
> -            if ( d == QPainter::RTL )
> +            
> +            if ( d == QPainter::RTL ) {
> +                if (chw > 0)
> +                    return;
> +                
>                  x -= chw;
> +            } else if (chw < 0)
> +                return;

I do like this patch too.
Comment 21 zalan 2022-12-29 12:03:52 PST
(In reply to Antti Koivisto from comment #20)
> Comment on attachment 2581 [details]
> Possible patch
> 
> View in context: https://bugs.webkit.org/attachment.cgi?id=2581&action=review
> 
> > font.cpp:107
> > -            if ( d == QPainter::RTL )
> > +            
> > +            if ( d == QPainter::RTL ) {
> > +                if (chw > 0)
> > +                    return;
> > +                
> >                  x -= chw;
> > +            } else if (chw < 0)
> > +                return;
> 
> I do like this patch too.
will check if it applies (need to install cvs first)
Comment 22 EWS 2022-12-29 12:40:50 PST
Committed 258356@main (4aee4f4a4f9d): <https://commits.webkit.org/258356@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 464249 [details].