Commit 65c13376 authored by kojii@chromium.org's avatar kojii@chromium.org

Fix Japanese line breaking rule before and after ruby

This patch fixes Japanese line breaking rules before and after ruby
elements. This patch is a port of http://wkb.ug/91588 with the
following changes:
* The WebKit patch sets ruby base text to the prior context for breaks
  after the ruby. Since U+FFFD Object Replacement Character can cover
  most of the common cases that this patch does not include that part.
* canBreakBefore() is fixed to include the correct UAX#14[1] classes
  that prohibit line breaks after. The original patch is a mix of
  before and after, and lacks some important after classes.

This patch fixes the common use cases in CJK, but it's hard to say this
is the right way to fix. There are two issues that block doing so at
this moment:
1. RubyRun is LayoutBlockFlow, but after WebKit implemented, the ruby
   spec was updated to allow line breaking within ruby, so it should be
   like inline, not a replaced element.
2. The CSS WG discussed on line breaking around replaced elements, but
   the discussion is not making much progress.
Changes in this patch should be updated when these issues are resolved.

[1] http://unicode.org/reports/tr14/

BUG=522826

Review URL: https://codereview.chromium.org/1304993003

git-svn-id: svn://svn.chromium.org/blink/trunk@201073 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 5a410370
......@@ -277,6 +277,8 @@ crbug.com/487281 [ Mac ] fast/forms/menulist-narrow-width.html [ ImageOnlyFailur
crbug.com/441840 [ Mac XP ] cssom/ahem-ex-units.html [ Failure ]
crbug.com/522826 [ Linux SnowLeopard Lion MountainLion Mavericks Retina ] fast/writing-mode/Kusa-Makura-background-canvas.html [ NeedsRebaseline ]
# In root-layer-scrolls, the scrollbars make the scroll offsets difficult to compute.
crbug.com/487948 virtual/rootlayerscrolls/fast/scrolling/keyboard-scroll-page-scale.html [ Failure ]
crbug.com/487948 virtual/rootlayerscrolls/fast/scrolling/editor-command-scroll-page-scale.html [ Failure ]
......
<!DOCTYPE html>
<meta charset="utf-8">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<style>
#container > div {
line-height:2;
margin-bottom:1em;
}
</style>
<div id="container">
<div title="ID+CL" style="width:2em;">あい)か</div>
<div title="span+CL" style="width:2em;"><span></span>)か</div>
<div title="ruby+CL" style="width:2em;"><ruby><rt></rt></ruby>)か</div>
<div title="OP+ID" style="width:2em;">あ(かき</div>
<div title="OP+ruby" style="width:2em;">あ(<ruby><rt></rt></ruby></div>
<div title="OP+ruby+CL" style="width:3em;">あ(<ruby><rt></rt></ruby>)か</div>
<div title="OP+ruby+CL (overflow)" style="width:2em;">あ(<ruby><rt></rt></ruby>)か</div>
</div>
<script>
runTests();
function runTests() {
var lineHeight = parseFloat(getComputedStyle(container.firstElementChild).lineHeight);
Array.prototype.forEach.call(container.children, function (element) {
test(function () {
var lineCount = element.offsetHeight / lineHeight;
assert_equals(lineCount, 3);
}, element.title);
});
if (window.testRunner)
container.style.display = "none";
}
</script>
......@@ -302,4 +302,29 @@ void LayoutRubyRun::getOverhang(bool firstLine, LayoutObject* startLayoutObject,
endOverhang = std::min<int>(endOverhang, std::min<int>(toLayoutText(endLayoutObject)->minLogicalWidth(), halfWidthOfFontSize));
}
bool LayoutRubyRun::canBreakBefore(const LazyLineBreakIterator& iterator) const
{
// TODO(kojii): It would be nice to improve this so that it isn't just
// hard-coded, but lookahead in this case is particularly problematic.
// See crbug.com/522826.
if (!iterator.priorContextLength())
return true;
UChar ch = iterator.lastCharacter();
ULineBreak lineBreak = static_cast<ULineBreak>(u_getIntPropertyValue(ch, UCHAR_LINE_BREAK));
// UNICODE LINE BREAKING ALGORITHM
// http://www.unicode.org/reports/tr14/
// And Requirements for Japanese Text Layout, 3.1.7 Characters Not Starting a Line
// http://www.w3.org/TR/2012/NOTE-jlreq-20120403/#characters_not_starting_a_line
switch (lineBreak) {
case U_LB_WORD_JOINER:
case U_LB_GLUE:
case U_LB_OPEN_PUNCTUATION:
return false;
default:
break;
}
return true;
}
} // namespace blink
......@@ -62,6 +62,8 @@ public:
static LayoutRubyRun* staticCreateRubyRun(const LayoutObject* parentRuby);
bool canBreakBefore(const LazyLineBreakIterator&) const;
const char* name() const override { return "LayoutRubyRun"; }
protected:
......
......@@ -457,8 +457,10 @@ inline void BreakingContext::handleReplaced()
if (m_atStart)
m_width.updateAvailableWidth(replacedBox.logicalHeight());
// Break on replaced elements if either has normal white-space.
if ((m_autoWrap || ComputedStyle::autoWrap(m_lastWS)) && (!m_current.object().isImage() || m_allowImagesToBreak)) {
// Break on replaced elements if either has normal white-space,
// or if the replaced element is ruby that can break before.
if ((m_autoWrap || ComputedStyle::autoWrap(m_lastWS)) && (!m_current.object().isImage() || m_allowImagesToBreak)
&& (!m_current.object().isRubyRun() || toLayoutRubyRun(m_current.object())->canBreakBefore(m_layoutTextInfo.m_lineBreakIterator))) {
m_width.commit();
m_lineBreak.moveToStartOf(m_current.object());
}
......@@ -892,7 +894,8 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()
if (!m_current.object().isFloatingOrOutOfFlowPositioned()) {
m_lastObject = m_current.object();
if (m_lastObject.isReplaced() && m_autoWrap && (!m_lastObject.isImage() || m_allowImagesToBreak) && (!m_lastObject.isListMarker() || LineLayoutListMarker(m_lastObject).isInside())) {
if (m_lastObject.isReplaced() && m_autoWrap && (!m_lastObject.isImage() || m_allowImagesToBreak) && (!m_lastObject.isListMarker() || LineLayoutListMarker(m_lastObject).isInside())
&& !m_lastObject.isRubyRun()) {
m_width.commit();
m_lineBreak.moveToStartOf(m_nextObject);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment