Open Bug 299943 Opened 19 years ago Updated 2 years ago

refactor letter-spacing

Categories

(Core :: Layout: Text and Fonts, defect, P3)

defect

Tracking

()

Future

People

(Reporter: masayuki, Unassigned)

References

(Blocks 6 open bugs, )

Details

Attachments

(2 files)

extra spaces of letter-spacing should be applied half on each side of the
character. But the spacing must not be applied at the beginning or at the end of
a line.

It is specified by CSS3 text module(but that is WD).
http://www.w3.org/TR/2005/WD-css3-text-20050627/#letter-spacing

Spec says:
> Spacing should be applied half on each side of the grapheme cluster. Spacing
> must not be applied at the beginning or at the end of a line.

But we don't support grapheme cluster yet. See bug 229896.
We should implement by character, not grapheme cluster.
Priority: -- → P2
Target Milestone: --- → mozilla1.9alpha
Note: The grapheme cluster stuff may be affected by smontagu's work in 297074.
I still don't see much benefit from the "half" spacing thing. It instead seems
so far that it creates more complications/ambiguities to outweigh any benefit it
might have.
The purpose is to make it so that letter-spacing applied to an inline element
will result in half-spacing before and after the element, not no spacing before
and full spacing afterward. Whether it's actually implemented as half on each
side of each character is not relevant.

I'll try to clarify this in the next draft.
> Whether it's actually implemented as half on each
> side of each character is not relevant.

If we implement to add extra space as half on each side of each character,
we get "natural" interface for text selection.
Currently, if a text has large letter-spacing, we cannot select from center of a
character to center of another character.

i.e.,

Curreytly:

|a    |b    |c    |d    |
       ^-----^  <- Drag this range, we can select b only.

If adding space as half on each sides on each character:

|  a  |  b  |  c  |  d  |
         ^-----^  <- Drag this range, we can select b and c.
fantasai:

> The purpose is to make it so that letter-spacing applied to an inline element
> will result in half-spacing before and after the element, not no spacing before
> and full spacing afterward.

Don't you change this idea? I'll work on this soon. If you have another suggestions, please tell me.
Status: NEW → ASSIGNED
Attached file testcase
I have a question on this test case. If an inline image is existing(img element or object element), should we add full-width extra space around these characters?
I.e.,

'ab<img>cd'

is rendered:

'a  b  <img>  c  d'
      ^     ^
instead of:

'a  b <img> c  d'

? I think that it's natural. But I think that this makes bad performance. Because when layout time, we cannot know that we succeed in loading of the image... We should not use this layout for performance (and keeping simple code).
> Don't you change this idea?

Sorry, I don't understand the question...

>  If an inline image is existing (img element or object element), should we add
> full-width extra space around these characters?

That's a really good question, but I don't know how to answer it. :/
I guess you can implement it however is easier, and I will mark it as an issue
in the next CSS3 Text draft.
(In reply to comment #7)
> > Don't you change this idea?
> 
> Sorry, I don't understand the question...
My question is that your idea of comment 3 is changed or not changed still now.
I.e., if you changed your mind, please tell me latest your opinion.

> >  If an inline image is existing (img element or object element), should we add
> > full-width extra space around these characters?
> 
> That's a really good question, but I don't know how to answer it. :/
> I guess you can implement it however is easier, and I will mark it as an issue
> in the next CSS3 Text draft.

Maybe it's not easy on nsTextFrame. However, I don't know that it's not easy on image frame too.
Give me a few days to go dig around in the library. Apparently German used to use letter-spacing for emphasis, and I want to see what they did at the edges of the words (which would correspond to what we should do at the edges of elements).
I own German books from the beginning of the last century, and also Hebrew books printed in Germany from the same period that use the same convention. Inter-word spacing does not seem to be affected. (I can attach scans or send them off-line, whichever you would prefer).
I think I've got the definition worked out, although I'd still be interested in seeing your scans. :) Attaching them to the bug report should be fine.

Applying the letter-spacing to spaces within the letter-spaced element is well
established implementation-wise, so that can't change. But the behavior at
element boundaries is inconsistent, so we can spec that to be consistent and
reasonable.

Here's what I've drafted so far:

  | At element boundaries, the letter spacing is given by and rendered within
  | the innermost element that contains the boundary.
  | 
  | For example, given the markup
  |
  |   <P>a<LS>b<Z>cd</Z><Y>ef</Y></LS>g</P>
  |
  | and the style sheet
  |
  |   LS { letter-spacing: 1em; }
  |   Z { letter-spacing: 0.3em; }
  |   Y { letter-spacing: 0.4em; }
  |
  | The spacing would be
  |
  |   a[0]b[1em]c[0.3em]d[1em]e[0.4em]f[0]g

Masayuki, I believe that would address your concern with images. Boundaries
are handled as, I believe, they ideally should be. And given that definition,
it doesn't matter how the letter-spacing is actually applied. Splitting it to
either side would, as you pointed out, result in a more natural selection UI.
In that case you'd have to not put any space at the start and end of the inline
and put double space next to each child inline. But as far as CSS layout is
concerned, selection UI is out-of-scope.

Word-spacing would be given, naturally, by the word separator's parent inline.
Word-spacing has to be split on either side of the character, though, because
some word separators are visible.

Is this ok?
Yeah, thanks for the comment.

Your idea will make simple layout code, the nsTextFrames will be created as following:

> a[0]b[1em]c[0.3em]d[1em]e[0.4em]f[0]g

+-+-+     +---------+     +---------+-+
|a|b|[1em]|c[0.3em]d|[1em]|e[0.4em]f|g|
+-+-+     +---------+     +---------+-+

But this way has some problems on Gecko.
1. the selection background is separated by the letter-spacing between nsTextFrames.
2. the text-decoration on quirks mode is separated by the letter-spacing between nsTextFrames.

I.e., we need to create following frames:

+-+------+--------------+------------+-+
|a|b[1em]|c[0.3em]d[1em]|e[0.4em]f[0]|g|
+-+------+--------------+------------+-+

I'll try to fix this problem on next week.
Summary: extra spaces of letter-spacing should be applied half on each side of the character → refactor letter-spacing
And there is a question.
Doesn't the letter-spacing of end of line appear, right?
Oops. We have a problem.

> <P>a<LS>b<Z>cd</Z><Y>ef</Y></LS>g</P>
> LS { letter-spacing: 1em; }
> Z { letter-spacing: 0.3em; text-decoration: underline; }
> Y { letter-spacing: 0.4em; }

Should we render as:

a[0]b[1em]c[0.3em]d[1em]e[0.4em]f[0]g
          ~~~~~~~~~
? If so, we cannot use following approach.
> +-+------+--------------+------------+-+
> |a|b[1em]|c[0.3em]d[1em]|e[0.4em]f[0]|g|
> +-+------+--------------+------------+-+

This is very bad for quirks mode...
And...

Should we render:

<p style="letter-spacing: 1em;">ab<img/>cd</p>

as

a[1em]b[1em]<img/>[1em]c[1em]d

? Or

a[1em]b<img/>c[1em]d

?
FYI: I think we should not set space around <img/>, <button/>, <input/> and <object/>. Becuase page authors can use 'margin' for these elements.
My comment 16 may not be correct.

example:

<p>ab<img alt="cd"/>ef</p>
p{ letter-spacing: 1em; }
img{ margin: 1em; }

In this case, if the image is loaded:

a[1em]b[1em]<img/>[1em]e[1em]f

but if the image is not loaded:

a[1em]b[1em][1em]c[1em]d[1em][1em]e[1em]f
       ^^^^^^^^^^       ^^^^^^^^^^

Maybe, we should apply letter-spacing to edge of inline replaced elements.
> Doesn't the letter-spacing of end of line appear, right?

No letter-spacing at the beginning or end of a line.

> Should we render as:
> a[0]b[1em]c[0.3em]d[1em]e[0.4em]f[0]g
>           ~~~~~~~~~

Yes.

I would set up frames like this:

+-+------+---------+-----+---------+-+
|a|b[1em]|c[0.3em]d|[1em]|e[0.4em]f|g|
+-+------+---------+-----+---------+-+

Imagine putting backgrounds or borders on the elements.
The hierarchy needs to come out like this:

         +---------+     +---------+
  +------|---------|-----|---------+
+-|------|---------|-----|---------|-+
|a|b[1em]|c[0.3em]d|[1em]|e[0.4em]f|g|


> <p style="letter-spacing: 1em;">ab<img/>cd</p>

That should render as a[1em]b[1em]<img/>[1em]c[1em]d

Although authors could technically set margins on those elements,
I think it makes more sense for them to be spaced out just as everything
else is. It's also more consistent to handle implementation-wise: it
doesn't matter whether the next element is replaced or not, the rendering
is the same within the text frames.
thanks,

>> Should we render as:
>> a[0]b[1em]c[0.3em]d[1em]e[0.4em]f[0]g
>>           ~~~~~~~~~
> 
> Yes.
> 
> I would set up frames like this:
> 
> +-+------+---------+-----+---------+-+
> |a|b[1em]|c[0.3em]d|[1em]|e[0.4em]f|g|
> +-+------+---------+-----+---------+-+
> 
> Imagine putting backgrounds or borders on the elements.
> The hierarchy needs to come out like this:
> 
>          +---------+     +---------+
>   +------|---------|-----|---------+
> +-|------|---------|-----|---------|-+
> |a|b[1em]|c[0.3em]d|[1em]|e[0.4em]f|g|

Yes, this is best. But we don't have a frame between 'Z' and 'Y'.
Hm. Do we need one in non-quirks mode?
(In reply to comment #20)
> Hm. Do we need one in non-quirks mode?
> 

For selection background between inline elements, we need it.
I'm trying to create the empty text frame.
should fix only on new text frame.
Depends on: 333659
No longer depends on: 297074
Target Milestone: mozilla1.9alpha1 → Future
Attached patch Patch v0.1Splinter Review
Inserting the spaces to both side of each character except that the left most character and right most character of each line.
Perhaps the way to do what http://www.w3.org/TR/css3-text/#letter-spacing says:
  # Letter-spacing must not be applied at the beginning or at the end of a
  # line. At element boundaries, the letter spacing is given by and rendered
  # within the innermost element that contains the boundary. 
is to handle the spacing within text runs in a different part of the code from the spacing between them.  The spacing within a text run would be based on the style for that text run; the spacing between adjacent text runs could be handled at a higher level.

However, it's still not clear to me how letter-spacing is supposed to behave when there's a replaced element, inline-block, etc., in the middle of a run of text.  This means I'm really not at all sure how the latter half (in the separation described in the previous paragraph) of the code should behave.
Blocks: 722284
What's hard about implementing the model now described in the spec is that it sometimes requires that the letter-spacing be at a point where there isn't a text frame.  So some of the letter-spacing code will need to be in nsLineLayout.  (And the interaction with bidi is also hard since I think it applies after bidi reordering.)
(In reply to David Baron [:dbaron] ⏰UTC-7 from comment #24)
> 
> However, it's still not clear to me how letter-spacing is supposed to behave
> when there's a replaced element, inline-block, etc., in the middle of a run
> of text.

Hi David Baron,

I wonder how mozilla will implement this in future? I believe some web pages already depend on current firefox and webkit/blink's behavior, i.e. replaced/inline-block never adds letter spacing to the line it lives in. For example, pdf2htmlEX tool (https://github.com/coolwanglu/pdf2htmlEX) uses inline-blocks to properly offset characters, so if a line has non-zero letter-spacing, and browsers change current behavior, the positions of characters all go wrong.

Current spec (http://dev.w3.org/csswg/css-text-3/#letter-spacing-property) says:

  For the purpose of letter-spacing, each consecutive run of atomic inlines (such as images
  and inline blocks) is treated as a single typographic character unit. 

Does it mean
  <div style="letter-spacing:10px">M<img><img>M<div>
Should be rendered as
  M[10px]<img><img>[10px]M

If so, this will definitely break pdf2htmlEX, as it assumes the following rendering behavior:
  M[10px]<img><img>M
ni'ing dbaron in regard of comment 27.

Sebastian
Flags: needinfo?(dbaron)
(In reply to Duan Yao from comment #27)
> Current spec (http://dev.w3.org/csswg/css-text-3/#letter-spacing-property)
> says:
> 
>   For the purpose of letter-spacing, each consecutive run of atomic inlines
> (such as images
>   and inline blocks) is treated as a single typographic character unit. 
> 
> Does it mean
>   <div style="letter-spacing:10px">M<img><img>M<div>
> Should be rendered as
>   M[10px]<img><img>[10px]M

Yes, that's what is supposed to happen.

> If so, this will definitely break pdf2htmlEX, as it assumes the following
> rendering behavior:
>   M[10px]<img><img>M

Why does it assume that?
Flags: needinfo?(dbaron)
(In reply to David Baron [:dbaron] ⌚️UTC-8 from comment #29)
> (In reply to Duan Yao from comment #27)
> > Current spec (http://dev.w3.org/csswg/css-text-3/#letter-spacing-property)
> > says:
> > 
> >   For the purpose of letter-spacing, each consecutive run of atomic inlines
> > (such as images
> >   and inline blocks) is treated as a single typographic character unit. 
> > 
> > Does it mean
> >   <div style="letter-spacing:10px">M<img><img>M<div>
> > Should be rendered as
> >   M[10px]<img><img>[10px]M
> 
> Yes, that's what is supposed to happen.
> 
> > If so, this will definitely break pdf2htmlEX, as it assumes the following
> > rendering behavior:
> >   M[10px]<img><img>M
> 
> Why does it assume that?

In PDF, arbitrary offsets can be added between letters, and pdf2htmlEx inserts inline-blocks(empty spans) between letters to emulate such offsets. Because that is the current behavior of browsers, so pdf2htmlEx have to assume that.
I don't have time to work on layout. So, I step down from assignee of this bug.
Assignee: masayuki → nobody
Status: ASSIGNED → NEW
Moving to p3 because no activity for at least 1 year(s).
See https://github.com/mozilla/bug-handling/blob/master/policy/triage-bugzilla.md#how-do-you-triage for more information
Priority: P2 → P3
Blocks: 1762819
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.