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 PseudoElement::attach(const AttachContext& context) { ASSERT(!layoutObject()); Element::attach(context); LayoutObject* renderer = this->layoutObject(); if (!renderer) return; ComputedStyle& style = renderer->mutableStyleRef(); if (style.styleType() != BEFORE && style.styleType() != AFTER) return; ASSERT(style.contentData()); for (const ContentData* content = style.contentData(); content; content = content->next()) { LayoutObject* child = content->createLayoutObject(document(), style); if (renderer->isChildAllowed(child, style)) { renderer->addChild(child); if (child->isQuote()) toLayoutQuote(child)->attachQuote(); } else child->destroy(); } }
bool LayoutListItem::updateMarkerLocation() { ASSERT(m_marker); LayoutObject* markerParent = m_marker->parent(); LayoutObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); if (!lineBoxParent) { // If the marker is currently contained inside an anonymous box, then we // are the only item in that anonymous box (since no line box parent was // found). It's ok to just leave the marker where it is in this case. if (markerParent && markerParent->isAnonymousBlock()) lineBoxParent = markerParent; else lineBoxParent = this; } if (markerParent != lineBoxParent) { m_marker->remove(); lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); m_marker->updateMarginsAndContent(); // If markerParent is an anonymous block with no children, destroy it. if (markerParent && markerParent->isAnonymousBlock() && !toLayoutBlock(markerParent)->firstChild() && !toLayoutBlock(markerParent)->continuation()) markerParent->destroy(); return true; } return false; }
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); }
void LayoutTreeBuilderForElement::createLayoutObject() { ComputedStyle& style = this->style(); LayoutObject* newLayoutObject = m_node->createLayoutObject(style); if (!newLayoutObject) return; LayoutObject* parentLayoutObject = this->parentLayoutObject(); if (!parentLayoutObject->isChildAllowed(newLayoutObject, style)) { newLayoutObject->destroy(); return; } // Make sure the LayoutObject already knows it is going to be added to a LayoutFlowThread before we set the style // for the first time. Otherwise code using inLayoutFlowThread() in the styleWillChange and styleDidChange will fail. newLayoutObject->setIsInsideFlowThread(parentLayoutObject->isInsideFlowThread()); LayoutObject* nextLayoutObject = this->nextLayoutObject(); m_node->setLayoutObject(newLayoutObject); newLayoutObject->setStyle(&style); // setStyle() can depend on layoutObject() already being set. if (Fullscreen::isActiveFullScreenElement(*m_node)) { newLayoutObject = LayoutFullScreen::wrapLayoutObject(newLayoutObject, parentLayoutObject, &m_node->document()); if (!newLayoutObject) return; } // Note: Adding newLayoutObject instead of layoutObject(). layoutObject() may be a child of newLayoutObject. parentLayoutObject->addChild(newLayoutObject, nextLayoutObject); }
void PseudoElement::attachLayoutTree(const AttachContext& context) { DCHECK(!layoutObject()); Element::attachLayoutTree(context); LayoutObject* layoutObject = this->layoutObject(); if (!layoutObject) return; ComputedStyle& style = layoutObject->mutableStyleRef(); if (style.styleType() != PseudoIdBefore && style.styleType() != PseudoIdAfter) return; DCHECK(style.contentData()); for (const ContentData* content = style.contentData(); content; content = content->next()) { LayoutObject* child = content->createLayoutObject(document(), style); if (layoutObject->isChildAllowed(child, style)) { layoutObject->addChild(child); if (child->isQuote()) toLayoutQuote(child)->attachQuote(); } else { child->destroy(); } } }
bool LayoutListItem::updateMarkerLocation() { ASSERT(m_marker); LayoutObject* markerParent = m_marker->parent(); // list-style-position:inside makes the ::marker pseudo an ordinary // position:static element that should be attached to LayoutListItem block. LayoutObject* lineBoxParent = m_marker->isInside() ? this : getParentOfFirstLineBox(this, m_marker); if (!lineBoxParent) { // If the marker is currently contained inside an anonymous box, then we // are the only item in that anonymous box (since no line box parent was // found). It's ok to just leave the marker where it is in this case. if (markerParent && markerParent->isAnonymousBlock()) lineBoxParent = markerParent; else lineBoxParent = this; } if (markerParent != lineBoxParent) { m_marker->remove(); lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); // TODO(rhogan): lineBoxParent and markerParent may be deleted by addChild, // so they are not safe to reference here. // Once we have a safe way of referencing them delete markerParent if it is // an empty anonymous block. m_marker->updateMarginsAndContent(); return true; } return false; }
void LayoutTableRow::addChild(LayoutObject* child, LayoutObject* beforeChild) { if (!child->isTableCell()) { LayoutObject* last = beforeChild; if (!last) last = lastCell(); if (last && last->isAnonymous() && last->isTableCell() && !last->isBeforeOrAfterContent()) { LayoutTableCell* lastCell = toLayoutTableCell(last); if (beforeChild == lastCell) beforeChild = lastCell->firstChild(); lastCell->addChild(child, beforeChild); return; } if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) { LayoutObject* cell = beforeChild->previousSibling(); if (cell && cell->isTableCell() && cell->isAnonymous()) { cell->addChild(child); return; } } // If beforeChild is inside an anonymous cell, insert into the cell. if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous() && !last->parent()->isBeforeOrAfterContent()) { last->parent()->addChild(child, beforeChild); return; } LayoutTableCell* cell = LayoutTableCell::createAnonymousWithParent(this); addChild(cell, beforeChild); cell->addChild(child); return; } if (beforeChild && beforeChild->parent() != this) beforeChild = splitAnonymousBoxesAroundChild(beforeChild); LayoutTableCell* cell = toLayoutTableCell(child); ASSERT(!beforeChild || beforeChild->isTableCell()); LayoutBox::addChild(cell, beforeChild); // Generated content can result in us having a null section so make sure to null check our parent. if (parent()) section()->addCell(cell, this); if (beforeChild || nextRow()) section()->setNeedsCellRecalc(); }
void LayoutTableRow::addChild(LayoutObject* child, LayoutObject* beforeChild) { if (!child->isTableCell()) { LayoutObject* last = beforeChild; if (!last) last = lastCell(); if (last && last->isAnonymous() && last->isTableCell() && !last->isBeforeOrAfterContent()) { LayoutTableCell* lastCell = toLayoutTableCell(last); if (beforeChild == lastCell) beforeChild = lastCell->firstChild(); lastCell->addChild(child, beforeChild); return; } if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) { LayoutObject* cell = beforeChild->previousSibling(); if (cell && cell->isTableCell() && cell->isAnonymous()) { cell->addChild(child); return; } } // If beforeChild is inside an anonymous cell, insert into the cell. if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous() && !last->parent()->isBeforeOrAfterContent()) { last->parent()->addChild(child, beforeChild); return; } LayoutTableCell* cell = LayoutTableCell::createAnonymousWithParent(this); addChild(cell, beforeChild); cell->addChild(child); return; } if (beforeChild && beforeChild->parent() != this) beforeChild = splitAnonymousBoxesAroundChild(beforeChild); LayoutTableCell* cell = toLayoutTableCell(child); ASSERT(!beforeChild || beforeChild->isTableCell()); LayoutTableBoxComponent::addChild(cell, beforeChild); // Generated content can result in us having a null section so make sure to // null check our parent. if (parent()) { section()->addCell(cell, this); // When borders collapse, adding a cell can affect the the width of // neighboring cells. LayoutTable* enclosingTable = table(); if (enclosingTable && enclosingTable->collapseBorders()) { if (LayoutTableCell* previousCell = cell->previousCell()) previousCell->setNeedsLayoutAndPrefWidthsRecalc( LayoutInvalidationReason::TableChanged); if (LayoutTableCell* nextCell = cell->nextCell()) nextCell->setNeedsLayoutAndPrefWidthsRecalc( LayoutInvalidationReason::TableChanged); } } if (beforeChild || nextRow()) section()->setNeedsCellRecalc(); }