void LayoutRubyAsInline::addChild(LayoutObject* child, LayoutObject* beforeChild) { // If the child is a ruby run, just add it normally. if (child->isRubyRun()) { LayoutInline::addChild(child, beforeChild); return; } if (beforeChild) { // insert child into run LayoutObject* run = beforeChild; while (run && !run->isRubyRun()) run = run->parent(); if (run) { if (beforeChild == run) beforeChild = toLayoutRubyRun(beforeChild)->firstChild(); ASSERT(!beforeChild || beforeChild->isDescendantOf(run)); run->addChild(child, beforeChild); return; } ASSERT_NOT_REACHED(); // beforeChild should always have a run as parent! // Emergency fallback: fall through and just append. } // If the new child would be appended, try to add the child to the previous run // if possible, or create a new run otherwise. // (The LayoutRubyRun object will handle the details) LayoutRubyRun* lastRun = lastRubyRun(this); if (!lastRun || lastRun->hasRubyText()) { lastRun = LayoutRubyRun::staticCreateRubyRun(this); LayoutInline::addChild(lastRun, beforeChild); } lastRun->addChild(child); }
LayoutRubyRun* LayoutRubyRun::staticCreateRubyRun(const LayoutObject* parentRuby) { ASSERT(parentRuby && parentRuby->isRuby()); LayoutRubyRun* rr = new LayoutRubyRun(); rr->setDocumentForAnonymous(&parentRuby->document()); RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parentRuby->styleRef(), INLINE_BLOCK); rr->setStyle(newStyle.release()); return rr; }
void LayoutRubyRun::addChild(LayoutObject* child, LayoutObject* beforeChild) { ASSERT(child); if (child->isRubyText()) { if (!beforeChild) { // LayoutRuby has already ascertained that we can add the child here. ASSERT(!hasRubyText()); // prepend ruby texts as first child LayoutBlockFlow::addChild(child, firstChild()); } else if (beforeChild->isRubyText()) { // New text is inserted just before another. // In this case the new text takes the place of the old one, and // the old text goes into a new run that is inserted as next sibling. ASSERT(beforeChild->parent() == this); LayoutObject* ruby = parent(); ASSERT(ruby->isRuby()); LayoutBlock* newRun = staticCreateRubyRun(ruby); ruby->addChild(newRun, nextSibling()); // Add the new ruby text and move the old one to the new run // Note: Doing it in this order and not using LayoutRubyRun's methods, // in order to avoid automatic removal of the ruby run in case there is no // other child besides the old ruby text. LayoutBlockFlow::addChild(child, beforeChild); LayoutBlockFlow::removeChild(beforeChild); newRun->addChild(beforeChild); } else if (hasRubyBase()) { // Insertion before a ruby base object. // In this case we need insert a new run before the current one and split the base. LayoutObject* ruby = parent(); LayoutRubyRun* newRun = staticCreateRubyRun(ruby); ruby->addChild(newRun, this); newRun->addChild(child); // Make sure we don't leave anything in the percentage descendant // map before moving the children to the new base. if (hasPercentHeightDescendants()) clearPercentHeightDescendants(); rubyBaseSafe()->moveChildren(newRun->rubyBaseSafe(), beforeChild); } } else { // child is not a text -> insert it into the base // (append it instead if beforeChild is the ruby text) LayoutRubyBase* base = rubyBaseSafe(); if (beforeChild == base) beforeChild = base->firstChild(); if (beforeChild && beforeChild->isRubyText()) beforeChild = 0; ASSERT(!beforeChild || beforeChild->isDescendantOf(base)); base->addChild(child, beforeChild); } }
void LayoutRubyAsBlock::removeChild(LayoutObject* child) { // If the child's parent is *this (must be a ruby run), just use the normal remove method. if (child->parent() == this) { ASSERT(child->isRubyRun()); LayoutBlockFlow::removeChild(child); return; } // Otherwise find the containing run and remove it from there. LayoutRubyRun* run = findRubyRunParent(child); ASSERT(run); run->removeChild(child); }
void LayoutRubyRun::removeChild(LayoutObject* 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()) { LayoutRubyBase* base = rubyBase(); LayoutObject* rightNeighbour = nextSibling(); if (base && rightNeighbour && rightNeighbour->isRubyRun()) { // Ruby run without a base can happen only at the first run. LayoutRubyRun* rightRun = toLayoutRubyRun(rightNeighbour); if (rightRun->hasRubyBase()) { LayoutRubyBase* rightBase = rightRun->rubyBaseSafe(); // Collect all children in a single base, then swap the bases. rightBase->moveChildren(base); moveChildTo(rightRun, base); rightRun->moveChildTo(this, rightBase); // The now empty ruby base will be removed below. ASSERT(!rubyBase()->firstChild()); } } } LayoutBlockFlow::removeChild(child); if (!beingDestroyed() && !documentBeingDestroyed()) { // Check if our base (if any) is now empty. If so, destroy it. LayoutBlock* base = rubyBase(); if (base && !base->firstChild()) { LayoutBlockFlow::removeChild(base); base->deleteLineBoxTree(); base->destroy(); } // If any of the above leaves the run empty, destroy it as well. if (!hasRubyText() && !hasRubyBase()) { deleteLineBoxTree(); destroy(); } } }