void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* beforeChild) { ASSERT(!childrenInline()); ASSERT_ARG(toBase, toBase); if (!firstChild()) return; if (toBase->childrenInline()) toBase->makeChildrenNonInline(); // If an anonymous block would be put next to another such block, then merge those. RenderObject* firstChildHere = firstChild(); RenderObject* lastChildThere = toBase->lastChild(); if (firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline() && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) { RenderBlock* anonBlockHere = toRenderBlock(firstChildHere); RenderBlock* anonBlockThere = toRenderBlock(lastChildThere); anonBlockHere->moveAllChildrenTo(anonBlockThere, true); anonBlockHere->deleteLineBoxTree(); anonBlockHere->destroy(); } // Move all remaining children normally. moveChildrenTo(toBase, firstChild(), beforeChild); }
void RenderRubyBase::mergeBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) { // This function removes all children that are before fromBeforeChild and appends them to toBase. ASSERT(!childrenInline()); ASSERT(toBase); ASSERT(!toBase->childrenInline()); // Quick check whether we have anything to do, to simplify the following code. if (fromBeforeChild != firstChild()) return; // If an anonymous block would be put next to another such block, then merge those. RenderObject* firstChildHere = firstChild(); RenderObject* lastChildThere = toBase->lastChild(); if (firstChildHere && firstChildHere->isAnonymousBlock() && firstChildHere->childrenInline() && lastChildThere && lastChildThere->isAnonymousBlock() && lastChildThere->childrenInline()) { RenderBlock* anonBlockHere = toRenderBlock(firstChildHere); RenderBlock* anonBlockThere = toRenderBlock(lastChildThere); anonBlockHere->moveAllChildrenTo(anonBlockThere, anonBlockThere->children()); anonBlockHere->deleteLineBoxTree(); anonBlockHere->destroy(); } // Move all remaining children normally. moveChildrenTo(toBase, firstChild(), fromBeforeChild); }
static inline bool isRubyAfterBlock(const RenderObject* object) { return isAnonymousRubyInlineBlock(object) && !object->nextSibling() && toRenderBlock(object)->firstChild() && toRenderBlock(object)->firstChild()->style()->styleType() == AFTER; }
static inline bool isRubyBeforeBlock(const RenderObject* object) { return isAnonymousRubyInlineBlock(object) && !object->previousSibling() && toRenderBlock(object)->firstChild() && toRenderBlock(object)->firstChild()->style()->styleType() == BEFORE; }
void RenderRubyBase::moveBlockChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) { if (toBase->childrenInline()) { // First check whether we move only wrapped inline objects. if (hasOnlyWrappedInlineChildren(fromBeforeChild)) { // The reason why the base is in block flow must be after beforeChild. // We therefore can extract the inline objects and move them to toBase. for (RenderObject* child = firstChild(); child != fromBeforeChild; child = firstChild()) { if (child->isAnonymousBlock()) { RenderBlock* anonBlock = toRenderBlock(child); ASSERT(anonBlock->childrenInline()); ASSERT(!anonBlock->inlineElementContinuation()); anonBlock->moveAllChildrenTo(toBase, toBase->children()); anonBlock->deleteLineBoxTree(); anonBlock->destroy(); } else { ASSERT(child->isFloatingOrPositioned()); moveChildTo(toBase, child); } } } else { // Moving block children -> have to set toBase as block flow toBase->makeChildrenNonInline(); // Move children, potentially collapsing anonymous block wrappers. mergeBlockChildren(toBase, fromBeforeChild); // Now we need to check if the leftover children are all inline. // If so, make this base inline again. if (hasOnlyWrappedInlineChildren()) { RenderObject* next = 0; for (RenderObject* child = firstChild(); child; child = next) { next = child->nextSibling(); if (child->isFloatingOrPositioned()) continue; ASSERT(child->isAnonymousBlock()); RenderBlock* anonBlock = toRenderBlock(child); ASSERT(anonBlock->childrenInline()); ASSERT(!anonBlock->inlineElementContinuation()); // Move inline children out of anonymous block. anonBlock->moveAllChildrenTo(this, anonBlock); anonBlock->deleteLineBoxTree(); anonBlock->destroy(); } setChildrenInline(true); } } } else mergeBlockChildren(toBase, fromBeforeChild); }
void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const { RenderObject* o = container(); if (!o) return; if (o->isRenderFlowThread()) transformState.move(o->columnOffset(LayoutPoint(transformState.mappedPoint()))); o->mapAbsoluteToLocalPoint(mode, transformState); LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint()); if (!style()->hasOutOfFlowPosition() && o->hasColumns()) { RenderBlock* block = toRenderBlock(o); LayoutPoint point(roundedLayoutPoint(transformState.mappedPoint())); point -= containerOffset; block->adjustForColumnRect(containerOffset, point); } bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D()); if (mode & UseTransforms && shouldUseTransformFromContainer(o)) { TransformationMatrix t; getTransformFromContainer(o, containerOffset, t); transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } else transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); }
static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) { if (!renderer) return 0; if (renderer->isRenderBlock()) { // If we're given a block element, it has to be a RenderSVGText. ASSERT(renderer->isSVGText()); RenderBlock* renderBlock = toRenderBlock(renderer); // RenderSVGText only ever contains a single line box. InlineFlowBox* flowBox = renderBlock->firstLineBox(); ASSERT(flowBox == renderBlock->lastLineBox()); return flowBox; } if (renderer->isRenderInline()) { // We're given a RenderSVGInline or objects that derive from it (RenderSVGTSpan / RenderSVGTextPath) RenderInline* renderInline = toRenderInline(renderer); // RenderSVGInline only ever contains a single line box. InlineFlowBox* flowBox = renderInline->firstLineBox(); ASSERT(flowBox == renderInline->lastLineBox()); return flowBox; } ASSERT_NOT_REACHED(); return 0; }
void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* beforeChild) { ASSERT(childrenInline()); ASSERT_ARG(toBase, toBase); if (!firstChild()) return; RenderBlock* toBlock; if (toBase->childrenInline()) { // The standard and easy case: move the children into the target base toBlock = toBase; } else { // We need to wrap the inline objects into an anonymous block. // If toBase has a suitable block, we re-use it, otherwise create a new one. RenderObject* lastChild = toBase->lastChild(); if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline()) toBlock = toRenderBlock(lastChild); else { toBlock = toBase->createAnonymousBlock(); toBase->insertChildInternal(toBlock, nullptr, NotifyChildren); } } // Move our inline children into the target block we determined above. moveChildrenTo(toBlock, firstChild(), beforeChild); }
VisiblePosition RenderRegion::positionForPoint(const LayoutPoint& point) { ASSERT(m_flowThread); if (!isValid() || !m_flowThread->firstChild()) // checking for empty region blocks. return RenderBlock::positionForPoint(point); return toRenderBlock(m_flowThread->firstChild())->positionForPoint(mapRegionPointIntoFlowThreadCoordinates(point)); }
RenderBlock* RenderTextFragment::blockForAccompanyingFirstLetter() const { if (!m_firstLetter) return 0; for (RenderObject* block = m_firstLetter->parent(); block; block = block->parent()) { if (block->style()->hasPseudoStyle(FIRST_LETTER) && block->canHaveChildren() && block->isRenderBlock()) return toRenderBlock(block); } return 0; }
void RenderFullScreen::unwrapRenderer(bool& requiresRenderTreeRebuild) { requiresRenderTreeRebuild = false; if (parent()) { auto* child = firstChild(); // Things can get very complicated with anonymous block generation. // We can restore correctly without rebuild in simple cases only. // FIXME: We should have a mechanism for removing a block without reconstructing the tree. if (child != lastChild()) requiresRenderTreeRebuild = true; else if (child && child->isAnonymousBlock()) { auto& anonymousBlock = toRenderBlock(*child); if (anonymousBlock.firstChild() != anonymousBlock.lastChild()) requiresRenderTreeRebuild = true; } while ((child = firstChild())) { if (child->isAnonymousBlock() && !requiresRenderTreeRebuild) { if (auto* nonAnonymousChild = toRenderBlock(*child).firstChild()) child = nonAnonymousChild; else { child->removeFromParent(); child->destroy(); continue; } } // We have to clear the override size, because as a flexbox, we // may have set one on the child, and we don't want to leave that // lying around on the child. if (child->isBox()) toRenderBox(child)->clearOverrideSize(); child->removeFromParent(); parent()->addChild(child, this); parent()->setNeedsLayoutAndPrefWidthsRecalc(); } } if (placeholder()) placeholder()->removeFromParent(); removeFromParent(); document().setFullScreenRenderer(0); }
RenderBlock* CaretBase::caretRenderer(Node* node) { if (!node) return 0; RenderObject* renderer = node->renderer(); if (!renderer) return 0; // if caretNode is a block and caret is inside it then caret should be painted by that block bool paintedByBlock = renderer->isRenderBlock() && caretRendersInsideNode(node); return paintedByBlock ? toRenderBlock(renderer) : renderer->containingBlock(); }
static LayoutSize accumulateInFlowPositionOffsets(const RenderObject* child) { if (!child->isAnonymousBlock() || !child->isRelPositioned()) return LayoutSize(); LayoutSize offset; RenderObject* p = toRenderBlock(child)->inlineElementContinuation(); while (p && p->isRenderInline()) { if (p->isRelPositioned()) { RenderInline* renderInline = toRenderInline(p); offset += renderInline->offsetForInFlowPosition(); } p = p->parent(); } return offset; }
void RenderBoxModelObject::moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert) { // We assume that callers have cleared their positioned objects list for child moves (!fullRemoveInsert) so the // positioned renderer maps don't become stale. It would be too slow to do the map lookup on each call. ASSERT(!fullRemoveInsert || !isRenderBlock() || !toRenderBlock(this)->hasPositionedObjects()); ASSERT(this == child->parent()); ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); if (fullRemoveInsert && (toBoxModelObject->isRenderBlock() || toBoxModelObject->isRenderInline())) { // Takes care of adding the new child correctly if toBlock and fromBlock // have different kind of children (block vs inline). toBoxModelObject->addChild(virtualChildren()->removeChildNode(this, child), beforeChild); } else toBoxModelObject->virtualChildren()->insertChildNode(toBoxModelObject, virtualChildren()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert); }
void RenderTextControl::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { RenderBlock::styleDidChange(diff, oldStyle); Element* innerText = innerTextElement(); if (!innerText) return; RenderBlock* innerTextRenderer = toRenderBlock(innerText->renderer()); if (innerTextRenderer) { // We may have set the width and the height in the old style in layout(). // Reset them now to avoid getting a spurious layout hint. innerTextRenderer->style()->setHeight(Length()); innerTextRenderer->style()->setWidth(Length()); innerTextRenderer->setStyle(createInnerTextStyle(style())); innerText->setNeedsStyleRecalc(); } textFormControlElement()->updatePlaceholderVisibility(false); }
InlineBox* EllipsisBox::markupBox() const { if (!m_shouldPaintMarkupBox || !renderer().isRenderBlock()) return 0; RenderBlock& block = toRenderBlock(renderer()); RootInlineBox* lastLine = block.lineAtIndex(block.lineCount() - 1); if (!lastLine) return 0; // If the last line-box on the last line of a block is a link, -webkit-line-clamp paints that box after the ellipsis. // It does not actually move the link. InlineBox* anchorBox = lastLine->lastChild(); if (!anchorBox || !anchorBox->renderer().style()->isLink()) return 0; return anchorBox; }
String HTMLTextFormControlElement::valueWithHardLineBreaks() const { // FIXME: It's not acceptable to ignore the HardWrap setting when there is no renderer. // While we have no evidence this has ever been a practical problem, it would be best to fix it some day. HTMLElement* innerText = innerTextElement(); if (!innerText || !isTextFormControl()) return value(); RenderBlock* renderer = toRenderBlock(innerText->renderer()); if (!renderer) return value(); Node* breakNode; unsigned breakOffset; RootInlineBox* line = renderer->firstRootBox(); if (!line) return value(); getNextSoftBreak(line, breakNode, breakOffset); StringBuilder result; for (Node* node = innerText->firstChild(); node; node = NodeTraversal::next(node, innerText)) { if (node->hasTagName(brTag)) result.append(newlineCharacter); else if (node->isTextNode()) { String data = toText(node)->data(); unsigned length = data.length(); unsigned position = 0; while (breakNode == node && breakOffset <= length) { if (breakOffset > position) { result.append(data.characters() + position, breakOffset - position); position = breakOffset; result.append(newlineCharacter); } getNextSoftBreak(line, breakNode, breakOffset); } result.append(data.characters() + position, length - position); } while (breakNode == node) getNextSoftBreak(line, breakNode, breakOffset); } return finishText(result); }
void RenderBoxModelObject::moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert) { // This condition is rarely hit since this function is usually called on // anonymous blocks which can no longer carry positioned objects (see r120761) // or when fullRemoveInsert is false. if (fullRemoveInsert && isRenderBlock()) { RenderBlock* block = toRenderBlock(this); block->removePositionedObjects(0); if (block->isRenderBlockFlow()) toRenderBlockFlow(block)->removeFloatingObjects(); } ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); for (RenderObject* child = startChild; child && child != endChild; ) { // Save our next sibling as moveChildTo will clear it. RenderObject* nextSibling = child->nextSibling(); moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert); child = nextSibling; } }
static inline SVGRootInlineBox* rootInlineBoxForTextContentElement(const SVGTextContentElement* element) { RenderObject* object = element->renderer(); if (!object || !object->isSVGText() || object->isText()) return 0; RenderBlock* svgText = toRenderBlock(object); // Find root inline box SVGRootInlineBox* rootBox = static_cast<SVGRootInlineBox*>(svgText->firstRootBox()); if (!rootBox) { // Layout is not sync yet! element->document()->updateLayoutIgnorePendingStylesheets(); rootBox = static_cast<SVGRootInlineBox*>(svgText->firstRootBox()); } ASSERT(rootBox); return rootBox; }
void RenderRubyBase::moveInlineChildren(RenderRubyBase* toBase, RenderObject* fromBeforeChild) { RenderBlock* toBlock; if (toBase->childrenInline()) { // The standard and easy case: move the children into the target base toBlock = toBase; } else { // We need to wrap the inline objects into an anonymous block. // If toBase has a suitable block, we re-use it, otherwise create a new one. RenderObject* lastChild = toBase->lastChild(); if (lastChild && lastChild->isAnonymousBlock() && lastChild->childrenInline()) toBlock = toRenderBlock(lastChild); else { toBlock = toBase->createAnonymousBlock(); toBase->children()->appendChildNode(toBase, toBlock); } } // Move our inline children into the target block we determined above. moveChildrenTo(toBlock, firstChild(), fromBeforeChild); }
RenderBlock* RootInlineBox::block() const { return toRenderBlock(renderer()); }
LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint) { LayoutPoint referencePoint = startPoint; // FIXME: This needs to be adapted for different writing modes inside the flow thread. RenderMultiColumnSet* startColumnSet = columnSetAtBlockOffset(referencePoint.y()); if (startColumnSet) { // Take into account the offset coordinates of the columnSet. RenderObject* currObject = startColumnSet; RenderObject* currOffsetParentRenderer; Element* currOffsetParentElement; while ((currOffsetParentElement = currObject->offsetParent()) && (currOffsetParentRenderer = currOffsetParentElement->renderer())) { if (currObject->isBoxModelObject()) referencePoint.move(toRenderBoxModelObject(currObject)->offsetLeft(), toRenderBoxModelObject(currObject)->offsetTop()); // Since we're looking for the offset relative to the body, we must also // take into consideration the borders of the columnSet's offsetParent. if (currOffsetParentRenderer->isBox() && !currOffsetParentRenderer->isBody()) referencePoint.move(toRenderBox(currOffsetParentRenderer)->borderLeft(), toRenderBox(currOffsetParentRenderer)->borderTop()); currObject = currOffsetParentRenderer; } // We need to check if any of this box's containing blocks start in a different columnSet // and if so, drop the object's top position (which was computed relative to its containing block // and is no longer valid) and recompute it using the columnSet in which it flows as reference. bool wasComputedRelativeToOtherRegion = false; const RenderBlock* objContainingBlock = boxModelObject.containingBlock(); while (objContainingBlock) { // Check if this object is in a different columnSet. RenderMultiColumnSet* parentStartRegion = 0; RenderMultiColumnSet* parentEndRegion = 0; getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEndRegion); if (parentStartRegion && parentStartRegion != startColumnSet) { wasComputedRelativeToOtherRegion = true; break; } objContainingBlock = objContainingBlock->containingBlock(); } if (wasComputedRelativeToOtherRegion) { // Get the logical top coordinate of the current object. LayoutUnit top = 0; if (boxModelObject.isRenderBlock()) { top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirstPage(); } else { if (boxModelObject.containingBlock()) top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage(); if (boxModelObject.isBox()) top += toRenderBox(&boxModelObject)->topLeftLocation().y(); else if (boxModelObject.isRenderInline()) top -= toRenderInline(&boxModelObject)->borderTop(); } // Get the logical top of the columnSet this object starts in // and compute the object's top, relative to the columnSet's top. LayoutUnit regionLogicalTop = startColumnSet->pageLogicalTopForOffset(top); LayoutUnit topRelativeToRegion = top - regionLogicalTop; referencePoint.setY(startColumnSet->offsetTop() + topRelativeToRegion); // Since the top has been overriden, check if the // relative positioning must be reconsidered. if (boxModelObject.isRelPositioned()) referencePoint.move(0, boxModelObject.relativePositionOffset().height()); } // Since we're looking for the offset relative to the body, we must also // take into consideration the borders of the columnSet. referencePoint.move(startColumnSet->borderLeft(), startColumnSet->borderTop()); } return referencePoint; }
void RenderLayerScrollableArea::updateAfterLayout() { m_scrollDimensionsDirty = true; IntSize originalScrollOffset = adjustedScrollOffset(); computeScrollDimensions(); // Layout may cause us to be at an invalid scroll position. In this case we need // to pull our scroll offsets back to the max (or push them up to the min). IntSize clampedScrollOffset = clampScrollOffset(adjustedScrollOffset()); if (clampedScrollOffset != adjustedScrollOffset()) scrollToOffset(clampedScrollOffset); if (originalScrollOffset != adjustedScrollOffset()) scrollToOffsetWithoutAnimation(-scrollOrigin() + adjustedScrollOffset()); bool hasHorizontalOverflow = this->hasHorizontalOverflow(); bool hasVerticalOverflow = this->hasVerticalOverflow(); { // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. DisableCompositingQueryAsserts disabler; // overflow:scroll should just enable/disable. if (box().style()->overflowX() == OSCROLL) horizontalScrollbar()->setEnabled(hasHorizontalOverflow); if (box().style()->overflowY() == OSCROLL) verticalScrollbar()->setEnabled(hasVerticalOverflow); } // overflow:auto may need to lay out again if scrollbars got added/removed. bool autoHorizontalScrollBarChanged = box().hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow); bool autoVerticalScrollBarChanged = box().hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow); if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) { if (box().hasAutoHorizontalScrollbar()) setHasHorizontalScrollbar(hasHorizontalOverflow); if (box().hasAutoVerticalScrollbar()) setHasVerticalScrollbar(hasVerticalOverflow); layer()->updateSelfPaintingLayer(); if (box().style()->overflowX() == OAUTO || box().style()->overflowY() == OAUTO) { if (!m_inOverflowRelayout) { // Our proprietary overflow: overlay value doesn't trigger a layout. m_inOverflowRelayout = true; SubtreeLayoutScope layoutScope(box()); layoutScope.setNeedsLayout(&box()); if (box().isRenderBlock()) { RenderBlock& block = toRenderBlock(box()); block.scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged); block.layoutBlock(true); } else { box().layout(); } m_inOverflowRelayout = false; } } } { // Hits in compositing/overflow/automatically-opt-into-composited-scrolling-after-style-change.html. DisableCompositingQueryAsserts disabler; // Set up the range (and page step/line step). if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { int clientWidth = box().pixelSnappedClientWidth(); horizontalScrollbar->setProportion(clientWidth, overflowRect().width()); } if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) { int clientHeight = box().pixelSnappedClientHeight(); verticalScrollbar->setProportion(clientHeight, overflowRect().height()); } } bool hasOverflow = hasScrollableHorizontalOverflow() || hasScrollableVerticalOverflow(); updateScrollableAreaSet(hasOverflow); if (hasOverflow) { DisableCompositingQueryAsserts disabler; positionOverflowControls(IntSize()); } }
// This method returns the maximum page size of a region with auto-height. This is the initial // height value for auto-height regions in the first layout phase of the parent named flow. LayoutUnit RenderNamedFlowFragment::maxPageLogicalHeight() const { ASSERT(m_flowThread); ASSERT(hasAutoLogicalHeight() && m_flowThread->inMeasureContentLayoutPhase()); ASSERT(isAnonymous()); ASSERT(parent()); const RenderStyle& styleToUse = parent()->style(); return styleToUse.logicalMaxHeight().isUndefined() ? RenderFlowThread::maxLogicalHeight() : toRenderBlock(parent())->computeReplacedLogicalHeightUsing(styleToUse.logicalMaxHeight()); }
void write(TextStream& ts, const RenderObject& o, int indent, RenderAsTextBehavior behavior) { #if ENABLE(SVG) if (o.isSVGPath()) { write(ts, *toRenderSVGPath(&o), indent); return; } if (o.isSVGGradientStop()) { writeSVGGradientStop(ts, *toRenderSVGGradientStop(&o), indent); return; } if (o.isSVGResourceContainer()) { writeSVGResourceContainer(ts, o, indent); return; } if (o.isSVGContainer()) { writeSVGContainer(ts, o, indent); return; } if (o.isSVGRoot()) { write(ts, *toRenderSVGRoot(&o), indent); return; } if (o.isSVGText()) { writeSVGText(ts, *toRenderBlock(&o), indent); return; } if (o.isSVGInlineText()) { writeSVGInlineText(ts, *toRenderText(&o), indent); return; } if (o.isSVGImage()) { writeSVGImage(ts, *toRenderSVGImage(&o), indent); return; } #endif writeIndent(ts, indent); RenderTreeAsText::writeRenderObject(ts, o, behavior); ts << "\n"; if (o.isText() && !o.isBR()) { const RenderText& text = *toRenderText(&o); for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) { writeIndent(ts, indent + 1); writeTextRun(ts, text, *box); } } for (RenderObject* child = o.firstChild(); child; child = child->nextSibling()) { if (child->hasLayer()) continue; write(ts, *child, indent + 1, behavior); } if (o.isWidget()) { Widget* widget = toRenderWidget(&o)->widget(); if (widget && widget->isFrameView()) { FrameView* view = static_cast<FrameView*>(widget); RenderView* root = view->frame()->contentRenderer(); if (root) { view->layout(); RenderLayer* l = root->layer(); if (l) writeLayers(ts, l, l, IntRect(l->x(), l->y(), l->width(), l->height()), indent + 1, behavior); } } } }
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject) { // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. ASSERT(owner->document()->usesBeforeAfterRules()); // In CSS2, before/after pseudo-content cannot nest. Check this first. if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER) return; if (!styledObject) styledObject = owner; RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); RenderObject* child; switch (type) { case BEFORE: child = beforePseudoElementRenderer(owner); break; case AFTER: child = afterPseudoElementRenderer(owner); break; default: ASSERT_NOT_REACHED(); return; } // Whether or not we currently have generated content attached. bool oldContentPresent = child; // Whether or not we now want generated content. bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE; // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate // :after content and not :before content. if (newContentWanted && type == BEFORE && owner->isElementContinuation()) newContentWanted = false; // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, // then we don't generate the :after content. if (newContentWanted && type == AFTER && owner->virtualContinuation()) newContentWanted = false; // If we don't want generated content any longer, or if we have generated content, but it's no longer // identical to the new content data we want to build render objects for, then we nuke all // of the old generated content. if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle, owner->document()) == Node::Detach)) { // Nuke the child. if (child->style()->styleType() == type) { oldContentPresent = false; child->destroy(); child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild(); } } // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we // have no generated content and can now return. if (!newContentWanted) return; if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && !pseudoElementStyle->isFloating() && !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition)) // According to the CSS2 spec (the end of section 12.1), the only allowed // display values for the pseudo style are NONE and INLINE for inline flows. // FIXME: CSS2.1 lifted this restriction, but block display types will crash. // For now we at least relax the restriction to allow all inline types like inline-block // and inline-table. pseudoElementStyle->setDisplay(INLINE); if (oldContentPresent) { updateBeforeAfterStyle(child, type, pseudoElementStyle); return; // We've updated the generated content. That's all we needed to do. } RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0; if (insertBefore && insertBefore->isAnonymousBlock() && insertBefore->childrenInline() && !insertBefore->isEmpty()) { // We are going to add the "before" element. We have to check whether the "insertBefore" element // is an anonymous block with inline children. If it is, then we should insert the "before" element // before the first inline child of the anonymous block, otherwise we will end up with the "before" // element in a different block. We do this only when the anonymous block has children, otherwise // we end up with the before element in a wrong block. insertBefore = insertBefore->firstChild(); } // Nothing goes before the intruded run-in, not even generated content. if (insertBefore && insertBefore->isRunIn() && owner->isRenderBlock() && toRenderBlock(owner)->runInIsPlacedIntoSiblingBlock(insertBefore)) insertBefore = insertBefore->nextSibling(); // Generated content consists of a single container that houses multiple children (specified // by the content property). This generated content container gets the pseudo-element style set on it. RenderObject* generatedContentContainer = 0; // Walk our list of generated content and create render objects for each. for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { RenderObject* renderer = createRendererForBeforeAfterContent(owner, content, pseudoElementStyle); if (renderer) { if (!generatedContentContainer) { // Make a generated box that might be any display type now that we are able to drill down into children // to find the original content properly. generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements. generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode. generatedContentContainer->setStyle(pseudoElementStyle); if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) { // The generated content container is not allowed here -> abort. generatedContentContainer->destroy(); renderer->destroy(); return; } // When we don't have a first child and are part of a continuation chain, // insertBefore is incorrectly set to zero above, which causes the :before // child to end up at the end of continuation chain. // See https://bugs.webkit.org/show_bug.cgi?id=78380. if (!insertBefore && type == BEFORE && owner->virtualContinuation()) owner->addChildIgnoringContinuation(generatedContentContainer, 0); else owner->addChild(generatedContentContainer, insertBefore); } if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle)) generatedContentContainer->addChild(renderer); else renderer->destroy(); } } if (!generatedContentContainer) return; // Handle placement of run-ins. We do the run-in placement at the end since generatedContentContainer can get destroyed. RenderObject* generatedContentContainerImmediateParent = generatedContentContainer->parent(); if (generatedContentContainerImmediateParent->isRenderBlock()) toRenderBlock(generatedContentContainerImmediateParent)->placeRunInIfNeeded(generatedContentContainer, PlaceGeneratedRunIn); }
static inline RenderBlock* rubyBeforeBlock(const RenderObject* ruby) { RenderObject* child = ruby->firstChild(); return isRubyBeforeBlock(child) ? toRenderBlock(child) : 0; }
LayoutState::LayoutState(std::unique_ptr<LayoutState> next, RenderBox* renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo) : m_columnInfo(columnInfo) , m_lineGrid(0) , m_next(std::move(next)) #if ENABLE(CSS_SHAPES) , m_shapeInsideInfo(0) #endif #ifndef NDEBUG , m_renderer(renderer) #endif { ASSERT(m_next); bool fixed = renderer->isOutOfFlowPositioned() && renderer->style().position() == FixedPosition; if (fixed) { // FIXME: This doesn't work correctly with transforms. FloatPoint fixedOffset = renderer->view().localToAbsolute(FloatPoint(), IsFixed); m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset; } else m_paintOffset = m_next->m_paintOffset + offset; if (renderer->isOutOfFlowPositioned() && !fixed) { if (RenderElement* container = renderer->container()) { if (container->isInFlowPositioned() && container->isRenderInline()) m_paintOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer); } } m_layoutOffset = m_paintOffset; if (renderer->isInFlowPositioned() && renderer->hasLayer()) m_paintOffset += renderer->layer()->offsetForInFlowPosition(); m_clipped = !fixed && m_next->m_clipped; if (m_clipped) m_clipRect = m_next->m_clipRect; if (renderer->hasOverflowClip()) { LayoutRect clipRect(toPoint(m_paintOffset) + renderer->view().layoutDelta(), renderer->cachedSizeForOverflowClip()); if (m_clipped) m_clipRect.intersect(clipRect); else { m_clipRect = clipRect; m_clipped = true; } m_paintOffset -= renderer->scrolledContentOffset(); } // If we establish a new page height, then cache the offset to the top of the first page. // We can compare this later on to figure out what part of the page we're actually on, if (pageLogicalHeight || m_columnInfo || renderer->isRenderFlowThread()) { m_pageLogicalHeight = pageLogicalHeight; bool isFlipped = renderer->style().isFlippedBlocksWritingMode(); m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer->borderLeft() + renderer->paddingLeft() : renderer->borderRight() + renderer->paddingRight()), m_layoutOffset.height() + (!isFlipped ? renderer->borderTop() + renderer->paddingTop() : renderer->borderBottom() + renderer->paddingBottom())); m_pageLogicalHeightChanged = pageLogicalHeightChanged; } else { // If we don't establish a new page height, then propagate the old page height and offset down. m_pageLogicalHeight = m_next->m_pageLogicalHeight; m_pageLogicalHeightChanged = m_next->m_pageLogicalHeightChanged; m_pageOffset = m_next->m_pageOffset; // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and // writing mode roots. if (renderer->isUnsplittableForPagination()) m_pageLogicalHeight = 0; } // Propagate line grid information. propagateLineGridInfo(renderer); if (!m_columnInfo) m_columnInfo = m_next->m_columnInfo; #if ENABLE(CSS_SHAPES) if (renderer->isRenderBlock()) { const RenderBlock* renderBlock = toRenderBlock(renderer); m_shapeInsideInfo = renderBlock->shapeInsideInfo(); if (!m_shapeInsideInfo && m_next->m_shapeInsideInfo && renderBlock->allowsShapeInsideInfoSharing()) m_shapeInsideInfo = m_next->m_shapeInsideInfo; } #endif m_layoutDelta = m_next->m_layoutDelta; #if !ASSERT_DISABLED && ENABLE(SATURATED_LAYOUT_ARITHMETIC) m_layoutDeltaXSaturated = m_next->m_layoutDeltaXSaturated; m_layoutDeltaYSaturated = m_next->m_layoutDeltaYSaturated; #endif m_isPaginated = m_pageLogicalHeight || m_columnInfo || renderer->isRenderFlowThread(); if (lineGrid() && renderer->hasColumns() && renderer->style().hasInlineColumnAxis()) computeLineGridPaginationOrigin(renderer); // If we have a new grid to track, then add it to our set. if (renderer->style().lineGrid() != RenderStyle::initialLineGrid() && renderer->isRenderBlockFlow()) establishLineGrid(toRenderBlockFlow(renderer)); // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. }
static inline RenderBlock* rubyAfterBlock(const RenderObject* ruby) { RenderObject* child = ruby->lastChild(); return isRubyAfterBlock(child) ? toRenderBlock(child) : 0; }