summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderRubyRun.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/RenderRubyRun.cpp')
-rw-r--r--Source/WebCore/rendering/RenderRubyRun.cpp121
1 files changed, 84 insertions, 37 deletions
diff --git a/Source/WebCore/rendering/RenderRubyRun.cpp b/Source/WebCore/rendering/RenderRubyRun.cpp
index 6cc6fc061..3cedf610d 100644
--- a/Source/WebCore/rendering/RenderRubyRun.cpp
+++ b/Source/WebCore/rendering/RenderRubyRun.cpp
@@ -32,6 +32,7 @@
#include "RenderRubyRun.h"
+#include "RenderRuby.h"
#include "RenderRubyBase.h"
#include "RenderRubyText.h"
#include "RenderText.h"
@@ -41,8 +42,12 @@
namespace WebCore {
-RenderRubyRun::RenderRubyRun(Document& document, PassRef<RenderStyle> style)
- : RenderBlockFlow(document, std::move(style))
+using namespace std;
+
+RenderRubyRun::RenderRubyRun(Document& document, RenderStyle&& style)
+ : RenderBlockFlow(document, WTFMove(style))
+ , m_lastCharacter(0)
+ , m_secondToLastCharacter(0)
{
setReplaced(true);
setInline(true);
@@ -66,11 +71,6 @@ bool RenderRubyRun::hasRubyBase() const
return lastChild() && lastChild()->isRubyBase();
}
-bool RenderRubyRun::isEmpty() const
-{
- return !hasRubyText() && !hasRubyBase();
-}
-
RenderRubyText* RenderRubyRun::rubyText() const
{
RenderObject* child = firstChild();
@@ -101,7 +101,7 @@ RenderBlock* RenderRubyRun::firstLineBlock() const
return 0;
}
-void RenderRubyRun::updateFirstLetter()
+void RenderRubyRun::updateFirstLetter(RenderTreeMutationIsAllowed)
{
}
@@ -126,7 +126,7 @@ void RenderRubyRun::addChild(RenderObject* child, RenderObject* beforeChild)
// the old text goes into a new run that is inserted as next sibling.
ASSERT(beforeChild->parent() == this);
RenderElement* ruby = parent();
- ASSERT(ruby->isRuby());
+ ASSERT(isRuby(ruby));
RenderBlock* newRun = staticCreateRubyRun(ruby);
ruby->addChild(newRun, nextSibling());
// Add the new ruby text and move the old one to the new run
@@ -158,18 +158,18 @@ void RenderRubyRun::removeChild(RenderObject& child)
{
// If the child is a ruby text, then merge the ruby base with the base of
// the right sibling run, if possible.
- if (!beingDestroyed() && !documentBeingDestroyed() && child.isRubyText()) {
+ if (!beingDestroyed() && !renderTreeBeingDestroyed() && child.isRubyText()) {
RenderRubyBase* base = rubyBase();
RenderObject* rightNeighbour = nextSibling();
- if (base && rightNeighbour && rightNeighbour->isRubyRun()) {
+ if (base && is<RenderRubyRun>(rightNeighbour)) {
// Ruby run without a base can happen only at the first run.
- RenderRubyRun* rightRun = toRenderRubyRun(rightNeighbour);
- if (rightRun->hasRubyBase()) {
- RenderRubyBase* rightBase = rightRun->rubyBaseSafe();
+ RenderRubyRun& rightRun = downcast<RenderRubyRun>(*rightNeighbour);
+ if (rightRun.hasRubyBase()) {
+ RenderRubyBase* rightBase = rightRun.rubyBaseSafe();
// Collect all children in a single base, then swap the bases.
- rightBase->moveChildren(base);
- moveChildTo(rightRun, base);
- rightRun->moveChildTo(this, rightBase);
+ rightBase->mergeChildrenWithBase(*base);
+ moveChildTo(&rightRun, base);
+ rightRun.moveChildTo(this, rightBase);
// The now empty ruby base will be removed below.
ASSERT(!rubyBase()->firstChild());
}
@@ -178,7 +178,7 @@ void RenderRubyRun::removeChild(RenderObject& child)
RenderBlockFlow::removeChild(child);
- if (!beingDestroyed() && !documentBeingDestroyed()) {
+ if (!beingDestroyed() && !renderTreeBeingDestroyed()) {
// Check if our base (if any) is now empty. If so, destroy it.
RenderBlock* base = rubyBase();
if (base && !base->firstChild()) {
@@ -188,7 +188,7 @@ void RenderRubyRun::removeChild(RenderObject& child)
}
// If any of the above leaves the run empty, destroy it as well.
- if (isEmpty()) {
+ if (!hasRubyText() && !hasRubyBase()) {
parent()->removeChild(*this);
deleteLines();
destroy();
@@ -198,17 +198,17 @@ void RenderRubyRun::removeChild(RenderObject& child)
RenderRubyBase* RenderRubyRun::createRubyBase() const
{
- auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK);
- newStyle.get().setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
- auto renderer = new RenderRubyBase(document(), std::move(newStyle));
+ auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
+ newStyle.setTextAlign(CENTER); // FIXME: use WEBKIT_CENTER?
+ auto renderer = new RenderRubyBase(document(), WTFMove(newStyle));
renderer->initializeStyle();
return renderer;
}
RenderRubyRun* RenderRubyRun::staticCreateRubyRun(const RenderObject* parentRuby)
{
- ASSERT(parentRuby && parentRuby->isRuby());
- auto renderer = new RenderRubyRun(parentRuby->document(), RenderStyle::createAnonymousStyleWithDisplay(&parentRuby->style(), INLINE_BLOCK));
+ ASSERT(isRuby(parentRuby));
+ auto renderer = new RenderRubyRun(parentRuby->document(), RenderStyle::createAnonymousStyleWithDisplay(parentRuby->style(), INLINE_BLOCK));
renderer->initializeStyle();
return renderer;
}
@@ -228,14 +228,28 @@ RenderObject* RenderRubyRun::layoutSpecialExcludedChild(bool relayoutChildren)
void RenderRubyRun::layout()
{
+ if (RenderRubyBase* base = rubyBase())
+ base->reset();
RenderBlockFlow::layout();
-
+}
+
+void RenderRubyRun::layoutBlock(bool relayoutChildren, LayoutUnit pageHeight)
+{
+ if (!relayoutChildren) {
+ // Since the extra relayout in RenderBlockFlow::updateRubyForJustifiedText() causes the size of the RenderRubyText/RenderRubyBase
+ // dependent on the line's current expansion, whenever we relayout the RenderRubyRun, we need to relayout the RenderRubyBase/RenderRubyText as well.
+ // FIXME: We should take the expansion opportunities into account if possible.
+ relayoutChildren = style().textAlign() == JUSTIFY;
+ }
+
+ RenderBlockFlow::layoutBlock(relayoutChildren, pageHeight);
+
RenderRubyText* rt = rubyText();
if (!rt)
return;
rt->setLogicalLeft(0);
-
+
// Place the RenderRubyText such that its bottom is flush with the lineTop of the first line of the RenderRubyBase.
LayoutUnit lastLineRubyTextBottom = rt->logicalHeight();
LayoutUnit firstLineRubyTextTop = 0;
@@ -245,8 +259,28 @@ void RenderRubyRun::layout()
firstLineRubyTextTop = rt->firstRootBox()->logicalTopLayoutOverflow();
lastLineRubyTextBottom = rootBox->logicalBottomLayoutOverflow();
}
-
- if (style().isFlippedLinesWritingMode() == (style().rubyPosition() == RubyPositionAfter)) {
+
+ if (isHorizontalWritingMode() && rt->style().rubyPosition() == RubyPositionInterCharacter) {
+ // Bopomofo. We need to move the RenderRubyText over to the right side and center it
+ // vertically relative to the base.
+ const FontCascade& font = style().fontCascade();
+ float distanceBetweenBase = max(font.letterSpacing(), 2.0f * rt->style().fontCascade().fontMetrics().height());
+ setWidth(width() + distanceBetweenBase - font.letterSpacing());
+ if (RenderRubyBase* rb = rubyBase()) {
+ LayoutUnit firstLineTop = 0;
+ LayoutUnit lastLineBottom = logicalHeight();
+ RootInlineBox* rootBox = rb->firstRootBox();
+ if (rootBox)
+ firstLineTop = rootBox->logicalTopLayoutOverflow();
+ firstLineTop += rb->logicalTop();
+ if (rootBox)
+ lastLineBottom = rootBox->logicalBottomLayoutOverflow();
+ lastLineBottom += rb->logicalTop();
+ rt->setX(rb->x() + rb->width() - font.letterSpacing());
+ LayoutUnit extent = lastLineBottom - firstLineTop;
+ rt->setY(firstLineTop + (extent - rt->height()) / 2);
+ }
+ } else if (style().isFlippedLinesWritingMode() == (style().rubyPosition() == RubyPositionAfter)) {
LayoutUnit firstLineTop = 0;
if (RenderRubyBase* rb = rubyBase()) {
RootInlineBox* rootBox = rb->firstRootBox();
@@ -281,7 +315,7 @@ static bool shouldOverhang(bool firstLine, const RenderObject* renderer, const R
return style.fontSize() <= rubyBaseStyle.fontSize();
}
-void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, int& startOverhang, int& endOverhang) const
+void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, RenderObject* endRenderer, float& startOverhang, float& endOverhang) const
{
ASSERT(!needsLayout());
@@ -297,12 +331,12 @@ void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, Ren
if (!rubyBase->firstRootBox())
return;
- int logicalWidth = this->logicalWidth();
- int logicalLeftOverhang = std::numeric_limits<int>::max();
- int logicalRightOverhang = std::numeric_limits<int>::max();
+ LayoutUnit logicalWidth = this->logicalWidth();
+ float logicalLeftOverhang = std::numeric_limits<float>::max();
+ float logicalRightOverhang = std::numeric_limits<float>::max();
for (RootInlineBox* rootInlineBox = rubyBase->firstRootBox(); rootInlineBox; rootInlineBox = rootInlineBox->nextRootBox()) {
- logicalLeftOverhang = std::min<int>(logicalLeftOverhang, rootInlineBox->logicalLeft());
- logicalRightOverhang = std::min<int>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
+ logicalLeftOverhang = std::min<float>(logicalLeftOverhang, rootInlineBox->logicalLeft());
+ logicalRightOverhang = std::min<float>(logicalRightOverhang, logicalWidth - rootInlineBox->logicalRight());
}
startOverhang = style().isLeftToRightDirection() ? logicalLeftOverhang : logicalRightOverhang;
@@ -317,11 +351,24 @@ void RenderRubyRun::getOverhang(bool firstLine, RenderObject* startRenderer, Ren
// We can overhang the ruby by no more than half the width of the neighboring text
// and no more than half the font size.
const RenderStyle& rubyTextStyle = firstLine ? rubyText->firstLineStyle() : rubyText->style();
- int halfWidthOfFontSize = rubyTextStyle.fontSize() / 2;
+ float halfWidthOfFontSize = rubyTextStyle.fontSize() / 2.;
if (startOverhang)
- startOverhang = std::min<int>(startOverhang, std::min<int>(toRenderText(startRenderer)->minLogicalWidth(), halfWidthOfFontSize));
+ startOverhang = std::min(startOverhang, std::min(downcast<RenderText>(*startRenderer).minLogicalWidth(), halfWidthOfFontSize));
if (endOverhang)
- endOverhang = std::min<int>(endOverhang, std::min<int>(toRenderText(endRenderer)->minLogicalWidth(), halfWidthOfFontSize));
+ endOverhang = std::min(endOverhang, std::min(downcast<RenderText>(*endRenderer).minLogicalWidth(), halfWidthOfFontSize));
+}
+
+void RenderRubyRun::updatePriorContextFromCachedBreakIterator(LazyLineBreakIterator& iterator) const
+{
+ iterator.setPriorContext(m_lastCharacter, m_secondToLastCharacter);
+}
+
+bool RenderRubyRun::canBreakBefore(const LazyLineBreakIterator& iterator) const
+{
+ RenderRubyText* rubyText = this->rubyText();
+ if (!rubyText)
+ return true;
+ return rubyText->canBreakBefore(iterator);
}
} // namespace WebCore