diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderRubyRun.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderRubyRun.cpp | 121 |
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 |