Closed Bug 588 Opened 26 years ago Closed 24 years ago

{feature} [TEXT] Full justification of text doesn't work

Categories

(Core :: Layout, defect, P1)

defect

Tracking

()

VERIFIED FIXED

People

(Reporter: angus, Assigned: roc)

References

()

Details

(Keywords: css1)

Attachments

(4 files)

We don't support justified text yet. Does this fit in with the whitespace work?
It's also a style issue. See URL for test case and sample code.
Status: NEW → ASSIGNED
Component: Unknown → Style System
Priority: P2 → P3
It is now partially implemented, though it could use some work. I'm leaving the
bug open, but at a reduced priority because there are some easy to create
conditions where the justification fails to operate as expected.
*** Bug 1047 has been marked as a duplicate of this bug. ***
Setting all current Open/Normal to M4.
*** Bug 3222 has been marked as a duplicate of this bug. ***
Summary: Full justification of text doesn't work → Full justification of text doesn't work
The regression I reported in 3222 occurred between the builds of 99-02-11 and
99-02-16.
*** Bug 2475 has been marked as a duplicate of this bug. ***
*** Bug 1783 has been marked as a duplicate of this bug. ***
*** Bug 3923 has been marked as a duplicate of this bug. ***
*** Bug 3493 has been marked as a duplicate of this bug. ***
Severity: normal → enhancement
Priority: P3 → P5
Summary: Full justification of text doesn't work → {feature} Full justification of text doesn't work
*** Bug 4397 has been marked as a duplicate of this bug. ***
*** Bug 4447 has been marked as a duplicate of this bug. ***
See also http://schist/4447.html
*** Bug 5017 has been marked as a duplicate of this bug. ***
Summary: {feature} Full justification of text doesn't work → {css1{feature} Full justification of text doesn't work
Summary: {css1{feature} Full justification of text doesn't work → {feature} Full justification of text doesn't work
Priority: P5 → P4
Summary: {feature} Full justification of text doesn't work → {css1} {feature} Full justification of text doesn't work
Increasing priority a little because this is a CSS1 issue and there are some
CSS2 issues at enhancement/P5.

The interaction of text-align:justify and white-space:pre is covered by bug
6011.
Summary: {css1} {feature} Full justification of text doesn't work → [4.xP]{css1} {feature} Full justification of text doesn't work
Priority: P4 → P5
*** Bug 10798 has been marked as a duplicate of this bug. ***
Summary: [4.xP]{css1} {feature} Full justification of text doesn't work → [4.xP] {css1} {feature} Full justification of text doesn't work
*** Bug 14279 has been marked as a duplicate of this bug. ***
Target Milestone: M17 → M15
*** Bug 19195 has been marked as a duplicate of this bug. ***
A simple testcase (also demonstrating bug 20260) is at
http://www.thirdnipple.com/mozilla/.

This also occurs without the table in this page, but I didn't feel like typing a
whole screen's worth of filler text :) I'd suggest that this is a problem which
ought to be fixed before beta, as a lot of websites rely on full justification
to look nice... The priority IMHO ought to be higher, but I'll leave that to the
people who know this bug better.
*** Bug 20703 has been marked as a duplicate of this bug. ***
*** Bug 20571 has been marked as a duplicate of this bug. ***
Assignee: kipp → pierre
Status: ASSIGNED → NEW
Updating to default Style System Assignee...kipp no longer with us :-(
Summary: [4.xP] {css1} {feature} Full justification of text doesn't work → [4.xP] {css1} {feature} [TEXT] Full justification of text doesn't work
Keywords: css1
Migrating from {css1} to css1 keyword. The {css1}, {css2}, {css3} and {css-moz}
radars should now be considered deprecated in favour of keywords.
I am *really* sorry about the spam...
Assigned to kipp so that this hopefully doesn't get
overlooked for much longer by the new layout kings.
OS: Windows 95 → All
Hardware: PC → All
based on the number of pages effected, the comments in this bug, and follow-up 
comments on the newsgroup, maing this P1.
Priority: P3 → P1
Setting the keyword all open [4.xp] bugs to 4xp.
Keywords: 4xp
*** Bug 25803 has been marked as a duplicate of this bug. ***
*** Bug 26287 has been marked as a duplicate of this bug. ***
Keywords: beta1
Adding 'beta1' to keywords. Beta1 should support all CSS1 styles. 
Putting on PDT+ radar for beta1.
Summary: [4.xP] {css1} {feature} [TEXT] Full justification of text doesn't work → {feature} [TEXT] Full justification of text doesn't work
Whiteboard: [PDT+]
this is likely to be very hard.
Whiteboard: [PDT+] → [PDT+] no idea when this will land, no one has looked into this yet
This used to work (somewhat buggily) about a year ago, so the code is there,
somewhere.  It stopped working correctly in March 1999 and then I think Kipp
disabled it.  It may also have had i18n problems.
Give it to Knuth! Knuth will code anything!
I looked at this today.  There is some code in the block frame that figures out 
whether a line can be fully justified and passes that boolean to 
nsLineLayout::HorizontalAlignFrames().  This code was ifdefed out and I 
re-enabled it in my build.  Even with this enabled, though, text does not get 
fully justified because HorizontalAlignFrames() doesn't do anything for that 
case.

I'm attaching a really simple test case which has a single line of fully 
justified text.

Since I can't find any code that tries to fully justify text, implementing it 
will take some time.  This is definitely not possible for M14.  Updating status 
whiteboard to indicate as such.
Whiteboard: [PDT+] no idea when this will land, no one has looked into this yet → [PDT+] Cannot be done for M14
Here is Kipp's initial justify work:
http://bonsai.mozilla.org/cvsquery.cgi?treeid=default&module=SeaMonkeyAll&branch=HEAD&branchtype=match&dir=&file=&filetype=match&who=kipp*&whotype=regexp&sortby=Date&hours=2&date=explicit&mindate=10%2F25%2F1998+00%3A00%3A00&maxdate=10%2F27%2F1998+09%3A00%3A00&cvsroot=%2Fcvsroot

It seemed to involve calculating a special wordspacing, and adding the extra
space to the whitespace glyph width. There was also a JustifyFrames method that
took care of this, but, that was probably replaced by
nsInlineFrame::AdjustFrameSize
A good place to start would probably be enabling the disabled code in
nsBlockFrame::PlaceLine, and seeing what happens.
Removing PDT+ and beta1 keyword, because this work cannot be done for M14. We 
also think it's not required for beta 1 that we support full justification
Keywords: beta1
Whiteboard: [PDT+] Cannot be done for M14 → Cannot be done for M14
mine! mine mine mine!  all mine!  whoo-hoo!
Assignee: kipp → buster
Note that the justification algorithm should handle the properities
word-spacing, letter-spacing, and white-space (and probably others...).
*** Bug 31056 has been marked as a duplicate of this bug. ***
*** Bug 31920 has been marked as a duplicate of this bug. ***
I've done some work on this, and I'm ready to try testing it. However, I don't 
have a compiler. If anyone wants to take a look, I've uploaded a copy here:

http://fantasai.tripod.com/Mozilla/TXJ/

So, if anyone gets this to compile, please tell me what happens? 
I'm rather curious to know what it will do.
*** Bug 34764 has been marked as a duplicate of this bug. ***
moving all buster m15 bugs to m16.
Target Milestone: M15 → M16
I have implemented this. I will attach the patch momentarily.

I got a few ideas from fantasai's patch (thanks!) but mine is rather different.
In particular, I've avoided adding any fields to nsTextFrame or any of the style
contexts. The basic idea is that nsLineLayout collects information from the text
frames during reflow; in particular it collects the number of spaces in each
text frame. It then uses this in HorizontalAlignFrames to distribute leftover
line space appropriately to each text frame. Justified text frames notice when
they are bigger than they need to be and distribute the extra space internally
in the correct manner.

There are probably some bugs. In fact, I found and fixed a number of other bugs
while I was doing this; they are marked "NOTE:" in the patch.

Regarding PRE: I treat nonbreaking spaces (which is what all PRE spaces turn
into) as regular spaces for the purposes of justification. Spaces derived from
tab expansion are also treated the same way. I don't know if this is "correct"
or not, but it works in that it makes justification useful in the context of PRE.

Word-spacing and letter-spacing work. It all even works in Composer (modulo a
few display glitches).
I have to say I don't think justification should do anything for PRE, since the
lines in PRE are broken by forced breaks, and forced breaks are not justified.
Turning off justification for preformatted text is as simple as making 
mJustifying depend on !mPreformatted, a one-line change to 
TextStyle::TextStyle(). Then such text frames will not report any spaces or 
letters to nsLineLayout, and will receive no extra space for justification.

One other thing I should mention --- single-word lines are currently not 
justified in any way. My patch prepares the way for using letter-spacing to 
stretch such words across the line, but I haven't actually put it in, because I 
think it looks ugly.
You're quite welcome! I'm glad it helped, at least. Can't really expect one's 
first C++ code to be perfect. ^o^ Actually, I still don't even know if mine 
works or not. -_-;;

I thought of giving Line Layout the number of spaces and characters during 
reflow, but I figured, why waste function calls when most text isn't justified 
anyway? Maybe that's an invalid argument. I wouldn't know.


--Preformatted text can be justified if it's wrapped (-moz-pre-wrap).

--If the author wishes to suppress character-spacing justification, they can 
simply specify 'letter-spacing: 0'. According to the CSS spec, the UA may only 
adjust the letter-spacing if it is set to 'normal' (the default).

--Single word lines (when 'letter-spacing' is set even if extending 
character-spacing is implemented) and lines without text need to be right 
justified if the text direction is rtl.


Oh, and you really should take up word-spacing issues in bug 1046. :)

um.. Did the priority change or is it just my imagination?
> I thought of giving Line Layout the number of spaces and characters during
> reflow, but I figured, why waste function calls when most text isn't justified
> anyway?

The impact of that is minimal. There should be basically no impact on the 
performance of laying out non-justified text. Laying out justified text is 
slower than normal text. It could be sped up a little by caching the value of 
each text frame's "justifcation extra space" somewhere, but that would require 
significant additional space (if you put it in nsTextFrame) or complexity (if 
you put it in an extension record in nsLineBox) --- not worth it in my opinion.

> --Preformatted text can be justified if it's wrapped (-moz-pre-wrap).

Is there a consensus on whether this should be justified? What's it used for? 
It's easy to tweak the patch to handle these cases in whichever way is desired.

RTL support is a good point. It's probably broken. How can I test that? There 
seem to be a lot of lurking RTL problems in this area, I'd rather not be the one 
to have to fix them all.

Browsing around, I have noticed that some sites look bad because the existing 
ShouldJustifyLine code is inadequate. E.g.
<p>Hello kitty<br>
gets justified. We can address that issue separately.

This bug has been P1 for a while, which is why I'm here.
-moz-pre-wrap is used for <PRE width="x">. It keeps whitespace intact, but 
allows wrapping. I don't see any reason why it shouldn't be justified, if full 
justification was specified on it.


As for RTL.. your ApplyFrameJustification returns an nscoord value. Subtract 
this from remainingWidth and delete the 'else' before the RTL check. I did the 
same thing in mine--see the code under "// Apply Justification" in txj.txt.


I didn't see any record for a priority change, so I was wondering..
If you're going to allow justify on PRE elements, I think you should probably
add a rule to ua.css so that PRE can't inherit 'text-align: justify', but it
would have to be specified explicitly.  I think generally justify goes against
the meaning of PRE.
I have updated the patch. It fixes the bug with BR-terminated lines; they are no 
longer justified. I have disabled justification for PRE and -moz-pre-wrap text; 
you can easily see where to turn this on again if desired. I have also brought 
the patch up to date with the tip. I also fixed an existing bug in nsTextFrame 
in the "MeasureTextRuns" code for Win32, where some lines were not being 
correctly wrapped. All the examples I've looked at, including all the examples 
from the duplicates of this bug, are looking good.

I tried some RTL tests, but the existing RTL handling already has bugs and it's 
hard to tell whether I've introduced any new ones.

I decided not to justify -moz-pre-wrapped. The reason is that trailing 
whitespace is not stripped from -moz-pre-wrapped text, so wrapped lines almost 
always have a trailing space. This means that justification will not produce a 
straight right margin. You could argue for stripping trailing whitespace from 
-moz-pre-wrapped text, but that's a separate issue.
Robert:  On first review, your new patch looks great.  I'll spend some time 
reviewing it in greater detail this afternoon.  If all looks good, I'll check it 
in early tomorrow morning.  Or, would you rather have the honors?  Makes no 
difference to me. Do you have cvs access rights?  If I do the checkin, it's 
slightly easier for me because I can merge your changes with my own for 12+ 
other bugs I've been holding and get it all in at once.

Many thanks to fantasia for the first cut, and as always to david for his 
insights.
I don't have CVS access, so you'll have to check it in.
I've done a thorough read-through, and it all looks great.  The only additions I 
plan on making are a few comments, a few assertions (checking for null pointers 
passed into new methods), and some cosmetic changes to bring it up to our coding 
standard (method arguments take the form "aArgName".)

In a second pass, it would be better if the justification-specific data items 
(mTextJustificationNumSpaces, etc.) were off in their own struct, and that 
struct was dynamically allocated only when needed.  This would save us 16 bytes 
per PerFrameData object in the case where justification isn't needed.  We can 
look into that as an optimization later.  similarly, I've already moved all the 
booleans in that data structure into a single PRInt32 bitfield, so I'll just 
go ahead and do the same for mIsBullet now.

I'll run some tests, and if it all is well and if the tree is in good shape 
tomorrow early am PST, it'll be in tomorrow's build.
Status: NEW → ASSIGNED
> method arguments take the form "aArgName"

Oops, thanks for reminding me.

I didn't realize the size of PerFrameData was important. They only exist while 
their line is being reflowed, right? Actually, those fields are costing 8 bytes 
per PerFrameData, and 8 bytes per nsLineLayout. (So having a dynamic structure 
within PerFrameData would only save 4 bytes for the non-justifying case.) It 
probably wouldn't be too hard to get to 0 bytes per PerFrameData and 16 bytes 
per nsLineLayout, by getting rid of ComputeJustificationWeights and keeping 
running totals of the total space and letter counts in nsLineLayout::PlaceFrame. 
Alternatively, I could get rid of all the space overhead if I could just call a 
method in nsTextFrame to fetch the space and letter counts during 
ComputeJustificationWeights, but I'm not sure how to do the cast in a totally 
safe way.
At some point, now that nsIFrame::AdjustFrameSize isn't going to be used, it 
should be deleted.

For optimization purposes, maybe we could add a method to nsIFrame that 
retrieves space and letter counts. The default implementation would return 0s, 
and nsTextFrame would override with the snippet that I added to 
nsTextFrame::Reflow. This would be called during the ComputeJustificationWeights 
traversal, and nothing would need to be recorded in the PerFrameData --- zero 
space overhead. It would also get rid of the need to correct overestimated space 
counts after whitespae trimming, because whitespace would already be trimmed by 
the time we compute the counts.

I'll try this out once the basic patch is in.
Keywords: patch
Most tests passed perfectly.  But I had to make a small change to your logic to 
get mail to run correctly.  I don't fully understand this, because the way you 
had the code looked fine. Basically, I had to revert a change you made, as shown 
below.  There are two adjacent code snippets marked with comments starting with
O'Callahan XXX:


      for (lastSegment = 0; textRun.mBreaks[lastSegment] < numCharsFit; 
lastSegment++) ;
      NS_ASSERTION(lastSegment < textRun.mNumSegments, "failed to find 
segment");
      // now we have textRun.mBreaks[lastSegment] >= numCharsFit
      /* O'Callahan XXX: This snippet together with the snippet below prevents 
mail from loading
         Justification seems to work just fine without these changes.
         We get into trouble in a case where lastSegment gets set to -1

      if (textRun.mBreaks[lastSegment] > numCharsFit) {
        // NOTE: this segment did not actually fit!
        lastSegment--;
      }
      */
    }

    /* O'Callahan XXX: This snippet together with the snippet above prevents 
mail from loading

    if (lastSegment < 0) {        
      // no segments fit
      break;
    } else */
    if (lastSegment == 0) {
      // Only one segment fit
      prevColumn = column;
      prevOffset = aTextData.mOffset;
    } else {


I plan on checking it in this way because it passes all my tests, plus the 
justification works fine.  Maybe you could spend a little time figuring out why 
your code creates some bad state that triggers an assertion in nsBlockFrame:

    NS_ASSERTION(aState.IsImpactedByFloater(),
                 "redo line on totally empty line");
OK. I made that change to resolve a rather obscure bug that I believe is exposed 
by (rather than caused by) justification. Assuming I can reproduce it after 
justification lands, I will file a separate bug and try to resolve the 
situation.

The bug involves some lines not being broken correctly. Basically, the Win32 
GetWidth using textRun will occasionally return a numCharsFit that is in the 
middle of a word. MeasureText simply can't handle that; it computes a value for 
"lastSegment" where the end of the line actually falls somewhere inside the 
segment, and then assumes that all the text in lastSegment will actually fit on 
the line, which is wrong. My changes simply try to do the right thing in this 
case.
fix checked in for Robert O'Callahan <roc+moz@cs.cmu.edu>.  Should be able to 
verify against 4/17/00 build.
Status: ASSIGNED → RESOLVED
Closed: 24 years ago
Resolution: --- → FIXED
Whiteboard: Cannot be done for M14
Looks good in 2000041708.

I can't reproduce the GetWidth-related bug I was seeing. Let's forget about it
for now :-).

I will file a bug regarding the excessive space consumption, and provide a patch
when I get around to it.

I will also file a bug regarding the minor display glitches in Composer. It is
probably a layout problem and might come up in non-Composer contexts (dynamic
content).
Tested on Windows, Mac and Linux. Windows and Linux work fine but justification 
on Mac is buggy. Separate bug written up for that. Verifying this bug fixed.
Status: RESOLVED → VERIFIED
Assignee: buster → roc
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: