Closed Bug 450088 Opened 16 years ago Closed 16 years ago

Line breaking regression (in Chinese and other languages)

Categories

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

x86
All
defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla1.9.2a1

People

(Reporter: wuyongwei, Assigned: jfkthame)

References

()

Details

(Keywords: fixed1.9.1)

Attachments

(1 file, 6 obsolete files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1

FF3 has problems dealing breaking lines in non-Western text, which used to be good in FF2.  Resizing the window containing the URL above, at least two problems are noticeable:

* Extra spaces appear in the text, like after "61岁了。"
* Improper line breaking after "“" and before "”"

This is a regression, since FF2 renders it correctly.  Both FF2 and IE ignore the line break in the Chinese text flow, and correctly break the line according to the Chinese rules.  Safari also ignores the line break in the Chinese text flow, but seems to break the line only according to Unicode 5.0.0 Standard Annex 14, without recognizing Chinese-specific rules: it prohibits immediate line breaks before and after "“" or "”" altogether.

I really wonder why this happened, since FF2 is correct in its behaviour.  If for some reasons the old code cannot be (easily) reused, you may be interested in looking at another line breaking library I recently implemented (according to Unicode 5.0.0 Standard Annex 14).  The URL is

http://vimgadgets.cvs.sourceforge.net/vimgadgets/common/tools/linebreak/

Its licence is zlib kind, and is compatible with the Firefox licence.

Reproducible: Always

Steps to Reproduce:
1. Open a Chinese page like the above URL
2. Resize the window slowly to check the line-breaking behaviour
Actual Results:  
1. "“" can be seen at the end of the line; or "”" at the beginning of the line
2. There are extra spaces in the page, like "一 件"

Expected Results:  
1. "“" should not appear at the end of the line; nor should "”" at the beginning of the line
2. There should be no spaces in the Chinese text flow

a) Restore the old line-breaking code in FF2; or
b) Use a new line-breaking library, like

http://vimgadgets.cvs.sourceforge.net/vimgadgets/common/tools/linebreak/
OS: Windows XP → All
Version: unspecified → 3.0 Branch
Component: General → Layout: Text
Product: Firefox → Core
QA Contact: general → layout.fonts-and-text
Version: 3.0 Branch → 1.9.0 Branch
Status: UNCONFIRMED → NEW
Ever confirmed: true
Flags: blocking1.9.1?
Jonathan, this might be fun for you to look at. nsLineBreaker.cpp would be a good place to start.
The "extra spaces" mentioned, such as after "61岁了。" or in the middle of "一 件", appear to be present in the source text, AFAICT. Is it really expected that spaces will magically vanish in the midst of Chinese text? I wouldn't have thought so -- and so I don't think we have an issue there.

The bad breaks after open-quote or before close-quote are due to the character classes in jisx4501class.h, which classifies these as "character" (i.e., like CJK ideographs) rather than as opening or closing punctuation. This in turn derives from their assignment to class 18 (Western characters) in intl/lwbrk/tools/jisx4501class.txt. I guess JIS X 4501 doesn't anticipate the use of "Western" quote marks around CJK text.

We can fix the issue by editing jisx4501class.txt (and regenerating our derived tables); we can assign the open-quotes to class 1, and the close-quotes to class 2 (meaning open and close parenthesis respectively, according to comments in nsJISx4501LineBreaker.cpp, which seems the closest match to the desired behavior).

Is there an upstream source for this data that we should also involve, or do we simply maintain it ourselves?
CSS white-space processing is complicated:
http://www.w3.org/TR/CSS21/text.html#white-space-model
It allows newlines in CJK text to be elided completely (whereas for most text they would be turned into spaces). But it would not be correct per CSS 2.1 to eliminate a space between two CJK characters.

I think we maintain the class data ourselves. Masayuki Nakano maintains that code. Masayuki-san, please comment on whether Jonathan's suggestion makes sense.
Yes, for newlines that makes sense, but AFAICS the test page mentioned here has actual spaces, not newlines.

OK, I tried changing the spaces in the test to newlines, and we still render these as spaces, so that's something we might want to change. Trying the file with Safari, though, I see the same thing: newlines in the Chinese text result in spaces, they are not ignored (as suggested in the original report).
Note that the real patch is the change to jisx4501class.txt; the other modified files are derived from this by running the anzx4501.pl tool.

The appropriate classes for U+20xx quote marks are not always clear-cut, because of widely differing quote mark usage in various Western languages; one person's opening quote mark may be another person's closer. In practice, though, I suspect that only the "English-like" convention is likely to be used with CJK text, so as long as U+2018/2019 and U+201C/201D are classified as open/close pairs, we'll be OK.

This patch does not address the issue of ignoring newlines within CJK text, it only resolves the bad breaks adjacent to quote marks.
Attachment #347866 - Flags: review?(masayuki)
That's fine. We quite commonly take a bug with multiple issues and refocus it onto one issue. People can file followup bugs to tackle the remaining issues, although in this case, it seems the remaining issue is not a bug so we probably shouldn't bother.
(In reply to comment #4)
> OK, I tried changing the spaces in the test to newlines, and we still render
> these as spaces, so that's something we might want to change. Trying the file
> with Safari, though, I see the same thing: newlines in the Chinese text result
> in spaces, they are not ignored (as suggested in the original report).

It's probably worth testing Windows IE in addition to Safari.  IE/Windows (the layout engine, partly via other browsers) has (high?) ninety-some percent share in the Chinese browser market, I think.
(In reply to comment #3)
> CSS white-space processing is complicated:
> http://www.w3.org/TR/CSS21/text.html#white-space-model
> It allows newlines in CJK text to be elided completely (whereas for most text
> they would be turned into spaces). But it would not be correct per CSS 2.1 to
> eliminate a space between two CJK characters.

See here:
http://www.w3.org/TR/html401/struct/text.html#h-9.1

> in Latin scripts, inter-word space is typically rendered as an ASCII space ( ),
> while in Thai it is a zero-width word separator (​).
> In Japanese and Chinese, inter-word space is not typically rendered at all.

The last line is important. The old textframe removed the white spaces if it has LF. But new textframe is not so.

> I think we maintain the class data ourselves. Masayuki Nakano maintains that
> code. Masayuki-san, please comment on whether Jonathan's suggestion makes
> sense.

Please wait, I'm checking...
Comment on attachment 347866 [details] [diff] [review]
patch to correct CJK linebreak behavior at quote marks

201A, 201B, 201E, 201F should be 18, probably. The reason was said by you.

2018 and 201C should be 22, and also 2019 and 201D should be 23. The risk of these class is lower for Western languages. If some web pages uses these 4 quotations as different meanings from our definition in Western text, we don't break around these quotations.

00AB and 00BB should be same. Use 22 and 23.
Oh, but following case, we cannot render like web designer wanted.
data:text/html,<div style="width:0;">”字”</div>

But we don't have good mechanism for this case. And it's OK. It might be broken on Fx2.

And you should add some testcases to layout/reftests/line-breaking/quotationmarks-1.html And then, you should use entities for non-ASCII characters in its file.
(In reply to comment #10)
> And you should add some testcases to
> layout/reftests/line-breaking/quotationmarks-1.html And then, you should use
> entities for non-ASCII characters in its file.

Oops, these characters are already tested. Therefore, you need to change the reference file (quotationmakrs-1-ref.html) for new behavior.
(In reply to comment #4)
> Yes, for newlines that makes sense, but AFAICS the test page mentioned here has
> actual spaces, not newlines.
> 
> OK, I tried changing the spaces in the test to newlines, and we still render
> these as spaces, so that's something we might want to change. Trying the file
> with Safari, though, I see the same thing: newlines in the Chinese text result
> in spaces, they are not ignored (as suggested in the original report).

The "extra spaces" I mentioned are newlines in the source.

However, I was mistaken about the Safari case, probably because the space was rendered very narrow.  Chrome behaves the same as Safari.  So it means WebKit currently also has this problem in Chinese rendering.

IE and FF2 behave as I expect, eliminating the newline completely between two Chinese characters.  This makes sense, since Chinese text generally does not contain any spaces.  Without this specific rendering rule, a long paragraph in Chinese may have to be a long line in the source, which presents an issue for some editors.
(In reply to comment #5)
> Created an attachment (id=347866) [details]
> patch to correct CJK linebreak behavior at quote marks
> 
> Note that the real patch is the change to jisx4501class.txt; the other modified
> files are derived from this by running the anzx4501.pl tool.
> 
> The appropriate classes for U+20xx quote marks are not always clear-cut,
> because of widely differing quote mark usage in various Western languages; one
> person's opening quote mark may be another person's closer. In practice,
> though, I suspect that only the "English-like" convention is likely to be used
> with CJK text, so as long as U+2018/2019 and U+201C/201D are classified as
> open/close pairs, we'll be OK.
> 
> This patch does not address the issue of ignoring newlines within CJK text, it
> only resolves the bad breaks adjacent to quote marks.

I am not familiar with the Mozilla code base, so sorry if my question is irrelevant.  Is jisx4501class.txt generic for Unicode line breaking, like the data file for Unicode 5.0.0 Annex 14?

Also notice that a Unicode character may have different line-breaking attributes in different language contexts.  This is conformant to Unicode 5.0.0 Annex 14.  In liblinebreak, U+201C (left double quote) is assigned the "Ambiguous Quotation" class (conservative line breaking in all context); but "Opening Punctuation" in English, Spanish, French, and Chinese; and "Closing Punctuation" in German and Russian.

A quick test shows that the line breaking rule changes with the lang attribute of the text in Internet Explorer too.

Of course, ignoring the lang attribute but make text rendering conformant to Unicode 5.0.0 Annex 14 is better than the current behaviour already.
(In reply to comment #12)
> The "extra spaces" I mentioned are newlines in the source.
> 
> However, I was mistaken about the Safari case, probably because the space was
> rendered very narrow.  Chrome behaves the same as Safari.  So it means WebKit
> currently also has this problem in Chinese rendering.
> 
> IE and FF2 behave as I expect, eliminating the newline completely between two
> Chinese characters.  This makes sense, since Chinese text generally does not
> contain any spaces.  Without this specific rendering rule, a long paragraph in
> Chinese may have to be a long line in the source, which presents an issue for
> some editors.

That's definitely a bug, but harder to fix; please file a separate bug for that, and we'll leave this bug as being about the linebreaking rules.
(In reply to comment #13)

Yes, the character classes from jisx4501class.txt are currently used for line-breaking regardless of language. Making the behavior dependent on the lang attribute would be a nice enhancement but is a separate issue from the current bug.
(In reply to comment #9)

> 201A, 201B, 201E, 201F should be 18, probably. The reason was said by you.

OK, so we'll accept that if these were ever used with CJK text, we could get unwanted breaks. It seems unlikely to be an issue in practice.

> 2018 and 201C should be 22, and also 2019 and 201D should be 23.

Could we have a comment somewhere documenting these class numbers? (Or is there one that I haven't found?) I was initially assuming the classes in jisx4501class.txt should correspond to the first table shown in the comments of nsJISx4501LineBreaker.cpp (around lines 60-80), but that only lists class values up to 20.

Unfortunately, it looks like making 2018 and 201C class 22 here (or class 1 as I initially tried) will lead to breakage for a number of languages such as Belarusian, Danish, Estonian, German, Icelandic, Ukrainian, and others where these are used as *closing* quote marks, so that instead of “quotes” they have „quotes.“ (See http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage.)

To be safer, I think we need a class for 2018 and 201C that prohibits a break after, but does not introduce a break opportunity before the character. It's not clear to me if we have a suitable class for this at the moment, though.
Trying to understand the line-break code in nsJISx4501LineBreaker.cpp more fully, I noticed a mismatch between the comments and actual values in row [d] of the gPairConservative table (item 8 in the comments describing the various classes and tables). Line 310 says

      [d] 0000 1111 1101 1111  = 0x0EDF

and the actual array has 0x0EDF, but the bit pattern shown (which corresponds to the matrix above, noting that the bits are encoded from right to left) would be 0x0FDF.

Masayuki-san, could you check which value is intended here -- it seems to me that either we should change this to 0x0FDF, or remove the X from the Complex column of row [d] in the matrix.
(In reply to comment #16)
> > 2018 and 201C should be 22, and also 2019 and 201D should be 23.
> 
> Could we have a comment somewhere documenting these class numbers? (Or is there
> one that I haven't found?) I was initially assuming the classes in
> jisx4501class.txt should correspond to the first table shown in the comments of
> nsJISx4501LineBreaker.cpp (around lines 60-80), but that only lists class
> values up to 20.

See http://mxr.mozilla.org/mozilla-central/source/intl/lwbrk/tools/jisx4501simp.txt

> Unfortunately, it looks like making 2018 and 201C class 22 here (or class 1 as
> I initially tried) will lead to breakage for a number of languages such as
> Belarusian, Danish, Estonian, German, Icelandic, Ukrainian, and others where
> these are used as *closing* quote marks, so that instead of “quotes” they have
> „quotes.“ (See http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage.)

The class 22 and the class 23 are [c] and [d] in the document of nsJISx4501LineBreaker.cpp. These classes are same behavior as class 1 of the document (character class). So, between a Western alphabet and these classes are not breakable point. So, using class 22 and class 23, you don't change the current behavior on non-CJ text.

(In reply to comment #17)
> Trying to understand the line-break code in nsJISx4501LineBreaker.cpp more
> fully, I noticed a mismatch between the comments and actual values in row [d]
> of the gPairConservative table (item 8 in the comments describing the various
> classes and tables). Line 310 says
> 
>       [d] 0000 1111 1101 1111  = 0x0EDF
> 
> and the actual array has 0x0EDF, but the bit pattern shown (which corresponds
> to the matrix above, noting that the bits are encoded from right to left) would
> be 0x0FDF.
> 
> Masayuki-san, could you check which value is intended here -- it seems to me
> that either we should change this to 0x0FDF, or remove the X from the Complex
> column of row [d] in the matrix.

Oh, it should be 0x0FDF! E.g., ")$" should not be breakable. Thank you.
(In reply to comment #18)

> > Unfortunately, it looks like making 2018 and 201C class 22 here (or class 1 as
> > I initially tried) will lead to breakage for a number of languages such as
> > Belarusian, Danish, Estonian, German, Icelandic, Ukrainian, and others where
> > these are used as *closing* quote marks, so that instead of “quotes” they have
> > „quotes.“ (See http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage.)
> 
> The class 22 and the class 23 are [c] and [d] in the document of
> nsJISx4501LineBreaker.cpp. These classes are same behavior as class 1 of the
> document (character class). So, between a Western alphabet and these classes
> are not breakable point. So, using class 22 and class 23, you don't change the
> current behavior on non-CJ text.

I don't think that's correct. Yes, class 22 won't break after a Western *letter*, but it looks to me like using class 22 for U+2018 and 201C can introduce a possible break between word-final punctuation such as . , : and the following quote. This would be fine in English usage, where these characters are opening quotes, and therefore should "bind" to the following word, but it will be unacceptable for languages that use these same characters as closing quotes (see above).

This shows up in layout/reftests/line-breaking/quotationmarks-1.html, which is purely "Western" sample text, but gets a lot of new line-breaks between punctuation and quote marks if these characters are changed to class 22.

I think we're going to have to subdivide one of the existing classes to make a further distinction, but I'm still figuring out the details.
Attachment #347866 - Attachment is obsolete: true
Attachment #347866 - Flags: review?(masayuki)
(In reply to comment #19)
> (In reply to comment #18)
> 
> > > Unfortunately, it looks like making 2018 and 201C class 22 here (or class 1 as
> > > I initially tried) will lead to breakage for a number of languages such as
> > > Belarusian, Danish, Estonian, German, Icelandic, Ukrainian, and others where
> > > these are used as *closing* quote marks, so that instead of “quotes” they have
> > > „quotes.“ (See http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage.)
> > 
> > The class 22 and the class 23 are [c] and [d] in the document of
> > nsJISx4501LineBreaker.cpp. These classes are same behavior as class 1 of the
> > document (character class). So, between a Western alphabet and these classes
> > are not breakable point. So, using class 22 and class 23, you don't change the
> > current behavior on non-CJ text.
> 
> I don't think that's correct. Yes, class 22 won't break after a Western
> *letter*, but it looks to me like using class 22 for U+2018 and 201C can
> introduce a possible break between word-final punctuation such as . , : and the
> following quote.

ASCII punctuations (e.g., ".,:;") are also 22 or 23, so, they should not be breakable with 22 or 23.

> This shows up in layout/reftests/line-breaking/quotationmarks-1.html, which is
> purely "Western" sample text, but gets a lot of new line-breaks between
> punctuation and quote marks if these characters are changed to class 22.

Really? It's strange...
'(' is class 22, '.' is class 23. But following test code is not broken.

data:text/html,<div style="width:0;">.(</div>
Ah, sorry. This is correct test. I forgot a rule.

data:text/html,<div style="width:0;">aaaaaaaa(.aaaaaaaa</div>

But this line is not also broken.
Oops, I mistook. This is correct. And this is broken.

data:text/html,<div style="width:0;">aaaaaaaa.(aaaaaaaa</div>

You're right. I'll check the cause.
Ah... I'm sorry. I looked conservative table.

Looks like you need to add a new class for quotations now. A line is only broken between the new class character and CJ character.
It's OK for "aaaaaaaa.(aaaaaaaa" to break before the open-paren, I think, and this is the existing behavior.

The problem is that we can't accept the same behavior for the "open" quotes U+2018 and 201C, because they're not always openers, some people use them as closers. So a suitable test case is:

  data:text/html,<div style="width:0;">aaaaaaaa.&#x201C;aaaaaaaa</div>

which doesn't break currently, but does break if we change the quotes to class 22 as suggested above. We need to prevent that break (because of the German, Ukrainian, etc usage), but allow a break before the quote (and not after it) in CJK context.

To solve this, we're going to have to change how the fullwidth punctuation from the U+FFxx block is handled. Currently, these map to the same classes as their ASCII equivalents, but in that case we can't distinguish between

  data:text/html,<div style="width:0;">aaaaaaaa.&#x201C;aaaaaaaa</div>

where we *don't* want a break between period and quote, and

  data:text/html,<div style="width:0;">字字字字字字字字.&#x201C;字字字字字字字字</div>

where we *do* want to allow the break between (full-width) period and quote mark.
(In reply to comment #16)
> > 2018 and 201C should be 22, and also 2019 and 201D should be 23.
> 
> Could we have a comment somewhere documenting these class numbers? (Or is there
> one that I haven't found?) I was initially assuming the classes in
> jisx4501class.txt should correspond to the first table shown in the comments of
> nsJISx4501LineBreaker.cpp (around lines 60-80), but that only lists class
> values up to 20.
> 
> Unfortunately, it looks like making 2018 and 201C class 22 here (or class 1 as
> I initially tried) will lead to breakage for a number of languages such as
> Belarusian, Danish, Estonian, German, Icelandic, Ukrainian, and others where
> these are used as *closing* quote marks, so that instead of “quotes” they have
> „quotes.“ (See http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage.)
> 
> To be safer, I think we need a class for 2018 and 201C that prohibits a break
> after, but does not introduce a break opportunity before the character. It's
> not clear to me if we have a suitable class for this at the moment, though.

I am fully aware of this issue, and that is why I have mentioned repeatedly Unicode 5.0.0 Annex 14 (UAX #14).  In UAX #14, the quotation marks (including U+2018 and U+201C) are given the category "Ambiguous Quotation", i.e. they "act like they are both opening and closing".  In liblinebreak, I specialized them to Opening or Closing only in specific language contexts.

Even if you do not want to use a completely new line-breaking implementation, I strongly suggest that you have a look at UAX #14.
Bug 56652 has a general discussion of UAX #14.
(In reply to comment #25)
> To solve this, we're going to have to change how the fullwidth punctuation from
> the U+FFxx block is handled. Currently, these map to the same classes as their
> ASCII equivalents, but in that case we can't distinguish between
> 
>   data:text/html,<div style="width:0;">aaaaaaaa.&#x201C;aaaaaaaa</div>
> 
> where we *don't* want a break between period and quote, and
> 
>   data:text/html,<div style="width:0;">字字字字字字字字.&#x201C;字字字字字字字字</div>
> 
> where we *do* want to allow the break between (full-width) period and quote
> mark.

Just FYI.  UAX #14 does not deal with this specific issue either.  IMHO, ignoring a breaking chance is better than misusing a breaking chance.

I may even argue that some people do not want this breaking chance.  Can "字字字字字字字字." happen to be a quotation inside a German context?  :-)
Flags: blocking1.9.1? → wanted1.9.1+
This test will fail until 450088 is fixed, due to bad breaks adjacent to quote marks used in a CJK context; see earlier comments on the bug for further discussion.
Attachment #348337 - Flags: review?(masayuki)
With this patch applied, the quotation-cjk reftest (see preceding attachment) now passes. All the other linebreak reftests still pass as well.

Because of the ambiguity of many quote-mark characters, the results will still not be perfect in every situation; in particular, we will not find all the good potential breaks in Western text. But I believe this patch significantly improves CJK behavior, and addresses the specific cases shown in the initial bug report, without disrupting behavior for other scripts.
Attachment #348338 - Flags: review?(masayuki)
Why do you need [f]?

        1 [a] 7  8  9 [b]15 18 COMPLEX [c] [d] [e] [f] [g]
[d]        X              X  X              X   X   X   X
[f]        X              X  X              X   X   X    

looks like the difference is only [d][g] vs [f][g] (all [x][d|f] are same). However, [g] is new class. And I think ASCII closing punctuations and Full-width punctuations should have same behavior.
Sorry, I guess I didn't explain this sufficiently. Purely for use in CJK contexts, yes, we'd want to treat ASCII and full-width closing punctuation the same, but we can't do this at the moment because of the risk of breaking Western-language usage.

The pair [f][g] allows a break between the closing (full-width) punctuation and the following open-quote in cases such as ....她说:“我是.... This is important because otherwise we can often get a run of 4 (or more) characters with no possible line-break, which looks pretty bad.

However, we cannot allow the same break for [d][g], where [d] has the ASCII closing punctuation, because the quote marks in [g] are not universally used as openers; in some Western orthographies such as German they can be closing quotes.

So if the punctuation is ASCII (or generic), we can't risk breaking before the "open" quote, as it might really be a closer. But if the punctuation is fullwidth, I think we can risk assuming this is a CJK context, using the quote marks in the commonly-understood (English-like) sense, and permit this break.

To really do the job right, we would have to pass language/locale information to the line-breaking routine, and provide tailored rules for different orthographic conventions. But that is an enhancement beyond the scope of this bug, I think. For now, we need to fix the bad CJK breaks that were reported, without interfering with the behavior for other scripts.

So because of the quote-mark ambiguities, we have to split [f] away from [d]; otherwise we can't provide the break before [g], and that makes typical CJK text look significantly worse.
Bug 465457 suggests language-specific line breaking. (However, even if/when this is implemented, we will still need a "best guess" fallback behavior for use when we don't have specific language information.)
(In reply to comment #32)
> The pair [f][g] allows a break between the closing (full-width) punctuation and
> the following open-quote in cases such as ....她说:“我是.... This is important
> because otherwise we can often get a run of 4 (or more) characters with no
> possible line-break, which looks pretty bad.

I do not think the break is allowed, unless the language is set to zh, or the encoding is a Chinese legacy one.  Consider this case (though maybe rare; and I am not sure the German is correct enough):

  „字字.“ ist ein chinesisches Angebot.
> However, we cannot allow the same break for [d][g], where [d] has the ASCII
> closing punctuation, because the quote marks in [g] are not universally used as
> openers; in some Western orthographies such as German they can be closing
> quotes.

O.K. We can check whether the text fragment is CJK or not by ContextState::mHasCJKChar. You can pass ContextState to GetClass and you should change the result only when the character is U+2018, U+2019, U+201C and U+201D. Then, we don't make damage to non-CJK text. If so, cannot we keep the same behavior between ASCII closing punctuations and Full-width closing punctuations? And can you reduce the [f] class?

(In reply to comment #34)
> (In reply to comment #32)
> > The pair [f][g] allows a break between the closing (full-width) punctuation and
> > the following open-quote in cases such as ....她说:“我是.... This is important
> > because otherwise we can often get a run of 4 (or more) characters with no
> > possible line-break, which looks pretty bad.
> 
> I do not think the break is allowed, unless the language is set to zh, or the
> encoding is a Chinese legacy one.  Consider this case (though maybe rare; and I
> am not sure the German is correct enough):
> 
>   „字字.“ ist ein chinesisches Angebot.

Right. But it should be fixed by bug 465457. The lang attr should override ContextState.mHasCJKChar. If we can fix this bug by the above way.
Or, should we the characters to NEED_CONTEXTUAL_ANALYSIS?
(In reply to comment #36)
> Or, should we the characters to NEED_CONTEXTUAL_ANALYSIS?

oops, I meant "should we add the...". Sorry for the spam.
This is a completely revised version of the patch. Instead of using new classes, the two key characters U+2018 and 201C are added to NEEDS_CONTEXTUAL_ANALYSIS, and mapped to CLASS_OPEN only if they are followed by a CJK character. This gives us the crucial break opportunity needed for CJK text to look good, while minimizing the risk of bad breaks in obscure cases such as the Chinese phrase quoted in German (see comment #34). Looking ahead at the following character seems the best way to identify this potential break.

There are now no changes to the pair tables (except fixing the typo noted in comment #17). The quote mark classes are updated to 22/23 in jisx4501class.txt, but the openers will normally be overridden by ContextualAnalysis to avoid the potential bad breaks as described in comment #19.

This patch includes the new reftest as well as the changes to linebreak code. It passes all the current linebreak reftests.
Attachment #348337 - Attachment is obsolete: true
Attachment #348338 - Attachment is obsolete: true
Attachment #350398 - Flags: review?(masayuki)
Attachment #348337 - Flags: review?(masayuki)
Attachment #348338 - Flags: review?(masayuki)
Oops, just after submitting the patch I realized I'd forgotten to include the open-guillemet in ContextualAnalysis; this might also get used in CJK contexts, I guess, so we'd better treat it like the open-quotes.
Attachment #350398 - Attachment is obsolete: true
Attachment #350400 - Flags: review?(masayuki)
Attachment #350398 - Flags: review?(masayuki)
+  } else if (cur == U_OPEN_SINGLE_QUOTE ||
+             cur == U_OPEN_DOUBLE_QUOTE ||
+             cur == U_OPEN_GUILLEMET) {
+    // for CJK usage, we treat these as openers to allow a break before them,
+    // but otherwise treat them as normal characters because quote mark usage
+    // in various Western languages varies too much; see bug #450088 discussion.
+    if (!aState.UseConservativeBreaking() && IS_CJK_CHAR(next))
+      return CLASS_OPEN;
+    return CLASS_CHARACTER;
   } else {
     NS_ERROR("Forgot to handle the current character!");
   }
   return GetClass(cur);

Should you fallback to GetClass(cur) instead of |return CLASS_CHARACTER|?
That would be possible (if I update jisx4501class.txt to have 18 rather than 22 for these characters), but it seems like that just sends us through a longer code path with more lookups to reach the same result.

If you feel strongly that we should make it refer back to the lookup tables here, we could do it, but I don't see the benefit (only a small cost).
Please do it. The current table is misleadable.

> -2018;201F;18
> +2018;;22
> +2019;;23
> +201A;;18
> +201B;;18
> +201C;;22
> +201D;;23
> +201E;;18
> +201F;;18

Then, this will be just:

>  2018;201F;18
> +2019;;23
> +201D;;23
OK, it now falls back to GetClass() in the conservative-breaking and non-CJK situations, and the class table has been updated to provide the correct values. The resulting behavior is unchanged from the previous version of the patch, so the line-break reftests still pass (including the new CJK one).
Attachment #350400 - Attachment is obsolete: true
Attachment #350437 - Flags: superreview?
Attachment #350437 - Flags: review?(masayuki)
Attachment #350400 - Flags: review?(masayuki)
Attachment #350437 - Flags: superreview? → superreview?(roc)
Attachment #350437 - Flags: review?(masayuki) → review+
Comment on attachment 350437 [details] [diff] [review]
revised patch as requested by Masayuki-san

Looks good for me. Thank you.
Comment on attachment 350437 [details] [diff] [review]
revised patch as requested by Masayuki-san

Fixes a regression from FF2
Attachment #350437 - Flags: superreview?(roc)
Attachment #350437 - Flags: superreview+
Attachment #350437 - Flags: approval1.9.1?
Has this landed on trunk yet? We should let it bake there for a day before taking it.
pushed to trunk.
http://hg.mozilla.org/mozilla-central/rev/556a93a5ffa6
Assignee: nobody → jfkthame
Status: NEW → RESOLVED
Closed: 16 years ago
Resolution: --- → FIXED
Whiteboard: [c-n: baking for 1.9.1]
Target Milestone: --- → mozilla1.9.2a1
Version: 1.9.0 Branch → Trunk
backed-out the patch. Because the new reftest failed on Linux.
Status: RESOLVED → REOPENED
Resolution: FIXED → ---
Whiteboard: [c-n: baking for 1.9.1]
> REFTEST TEST-UNEXPECTED-FAIL | file:///builds/slave/trunk_linux-7/build/layout/reftests/line-breaking/quotationmarks-cjk-1.html | 
> REFTEST   IMAGE 1 (TEST): data:image/png;base64,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
> REFTEST   IMAGE 2 (REFERENCE): data:image/png;base64,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
> REFTEST number of differing pixels: 94
looks like the test failure is caused by gfx/thebes bug. probably, we should disable the test only for linux.
Weird. The failure isn't due to this patch, though. The line-breaking is fine, the problem has something to do with font/line metrics, I guess, causing the "missing glyph" boxes on the last couple of lines to be drawn in a vertically-squished way, as if the code believes the font height is less there.

I'm guessing we wouldn't get this failure if the test box actually had CJK fonts available. (It worked fine for me on Linux.) It'd be nice to get to the root of the problem, but I would suggest it's actually a separate bug.
Maybe mark the test as random on Linux for now, and file a new bug re the missing-glyph rendering issue.
Jonathan, I think that we should only changes the new reftest should not be checked on linux.
http://mxr.mozilla.org/mozilla-central/source/layout/tools/reftest/README.txt#51
Are you able to reproduce the problem (squashed "missing-glyph boxes") somehow? I was hoping to come up with a test case that demonstrates this, and then file a separate bug, but have not been able to reproduce it locally on my Linux system (or on OS X).
(In reply to comment #54)
> Are you able to reproduce the problem (squashed "missing-glyph boxes") somehow?

I cannot.

> I was hoping to come up with a test case that demonstrates this, and then file
> a separate bug, but have not been able to reproduce it locally on my Linux
> system (or on OS X).

I think for 1.9.1 schedule, we need to land the current patch ASAP, so, you should disable the reftest only for Linux.
OK, I have disabled the new reftest on Linux for now, so AFAIK this should be safe to land. The new patch is taken directly from my .hg/patches dir, with user name and commit message; hope that's all correct.
Attachment #350437 - Attachment is obsolete: true
Attachment #352289 - Flags: review?(masayuki)
Attachment #350437 - Flags: approval1.9.1?
The reftest failure on Linux is due to lack of CJK fonts on the test machines, leading to the use of "missing glyph" boxes for the character U+5B57 in the test. The rendering of the missing glyph is affected by the presence of <br> before it in the reference file; this separates it from the preceding character and prevents the font chosen there from being propagated. In the actual test (not reference), where <br> is not present, the size of the missing glyph box varies according to the font chosen during font-matching for the preceding character.

Karl suggested a workaround using a <span> with a bogus family name, to effectively reset the font-matching process. This seems to work; however, I'm uncomfortable about adding this to the test case here as it "pollutes" the text stream that we're trying to line-break, and so makes it difficult to know whether we are still testing the intended sequence.
Does the test work on Linux if, instead of using a <br>, you set white-space:pre and use newlines in the source?
No, that still causes the missing-glyph after the break to be separated from the (fallback) font-matching that was applied to the character before the break.
Is there a specific reason why the missing glyph is drawn according to the metrics of the immediately-preceding font, or would it make (at least as much) sense to always draw it according to the metrics of the first (available) font from the current set, which is what happens if it occurs in isolation?

It's a tough call, perhaps, but arguably it would be nice to draw all missing glyphs within a given style run in a consistent way, rather than varying depending on the particular character that happened to occur before them. (And if we did this, it would also have the effect of making this test behave more predictably.)
Attachment #352289 - Flags: review?(masayuki) → review+
http://hg.mozilla.org/mozilla-central/rev/1eae54a0f48c

pushed the latest patch, please file a new bug for linux missing glyph issue.
Status: REOPENED → RESOLVED
Closed: 16 years ago16 years ago
Resolution: --- → FIXED
Whiteboard: [c-n: baking for 1.9.1]
(In reply to comment #60)
> Is there a specific reason why the missing glyph is drawn according to the
> metrics of the immediately-preceding font, or would it make (at least as much)
> sense to always draw it according to the metrics of the first (available) font
> from the current set, which is what happens if it occurs in isolation?

The latter would make a lot more sense! Can you do it?
I think so - hoping a trivial fix will work, but needs testing. Filed bug #469005 for this.
Whiteboard: [c-n: baking for 1.9.1] → [needs 191 landing
Comment on attachment 352289 [details] [diff] [review]
updated patch: disabled reftest on Linux, added commit msg

changes the line-breaking spec of after open quotes ([‘]U+2018 and [“]U+201c) and [«]U+AB only when the next character is a CJK character.

This is important changes for Chinese users. And Japanese and Korean users don't have problems by this change, maybe.
Attachment #352289 - Flags: approval1.9.1?
Keywords: checkin-needed
Whiteboard: [needs 191 landing → [needs 191 landing]
Comment on attachment 352289 [details] [diff] [review]
updated patch: disabled reftest on Linux, added commit msg

a191=beltzner
Attachment #352289 - Flags: approval1.9.1? → approval1.9.1+
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: