void RenderRegion::attachRegion() { if (documentBeingDestroyed()) return; // A region starts off invalid. setIsValid(false); // Initialize the flow thread reference and create the flow thread object if needed. // The flow thread lifetime is influenced by the number of regions attached to it, // and we are attaching the region to the flow thread. installFlowThread(); if (!m_flowThread) return; // Only after adding the region to the thread, the region is marked to be valid. m_flowThread->addRegionToThread(this); // The region just got attached to the flow thread, lets check whether // it has region styling rules associated. checkRegionStyle(); if (!isValid()) return; m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); if (hasAutoLogicalHeight()) incrementAutoLogicalHeightCount(); }
void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes) { ASSERT(child); if (!shouldHandleSubtreeMutations()) return; checkLayoutAttributesConsistency(this, m_layoutAttributes); // The positioning elements cache depends on the size of each text renderer in the // subtree. If this changes, clear the cache. It's going to be rebuilt below. m_layoutAttributesBuilder.clearTextPositioningElements(); if (m_layoutAttributes.isEmpty() || !child->isSVGInlineText()) return; // This logic requires that the 'text' child is still inserted in the tree. auto& text = downcast<RenderSVGInlineText>(*child); bool stopAfterNext = false; SVGTextLayoutAttributes* previous = nullptr; SVGTextLayoutAttributes* next = nullptr; if (!documentBeingDestroyed()) findPreviousAndNextAttributes(*this, &text, stopAfterNext, previous, next); if (previous) affectedAttributes.append(previous); if (next) affectedAttributes.append(next); bool removed = m_layoutAttributes.removeFirst(text.layoutAttributes()); ASSERT_UNUSED(removed, removed); }
void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes) { ASSERT(child); if (!shouldHandleSubtreeMutations()) return; checkLayoutAttributesConsistency(this, m_layoutAttributes); // The positioning elements cache depends on the size of each text renderer in the // subtree. If this changes, clear the cache. It's going to be rebuilt below. m_layoutAttributesBuilder.clearTextPositioningElements(); if (m_layoutAttributes.isEmpty() || !child->isSVGInlineText()) return; // This logic requires that the 'text' child is still inserted in the tree. RenderSVGInlineText* text = toRenderSVGInlineText(child); SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; if (!documentBeingDestroyed()) findPreviousAndNextAttributes(this, text, previous, next); if (previous) affectedAttributes.append(previous); if (next) affectedAttributes.append(next); size_t position = m_layoutAttributes.find(text->layoutAttributes()); ASSERT(position != kNotFound); m_layoutAttributes.remove(position); }
void RenderReplaced::willBeDestroyed() { if (!documentBeingDestroyed() && parent()) parent()->dirtyLinesFromChangedChild(this); RenderBox::willBeDestroyed(); }
void LayoutCounter::invalidate() { m_counterNode->removeLayoutObject(this); ASSERT(!m_counterNode); if (documentBeingDestroyed()) return; setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::CountersChanged); }
void RenderCounter::invalidate() { m_counterNode->removeRenderer(this); ASSERT(!m_counterNode); if (documentBeingDestroyed()) return; setNeedsLayoutAndPrefWidthsRecalc(); }
void RenderSVGInlineText::destroy() { if (!documentBeingDestroyed()) { setNeedsLayoutAndPrefWidthsRecalc(); repaint(); } RenderText::destroy(); }
void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) { if (documentBeingDestroyed()) return; if (!m_imageResource) return; if (newImage != m_imageResource->imagePtr()) return; // Per the spec, we let the server-sent header override srcset/other sources of dpr. // https://github.com/igrigorik/http-client-hints/blob/master/draft-grigorik-http-client-hints-01.txt#L255 if (m_imageResource->cachedImage() && m_imageResource->cachedImage()->hasDevicePixelRatioHeaderValue()) m_imageDevicePixelRatio = 1 / m_imageResource->cachedImage()->devicePixelRatioHeaderValue(); // If the RenderImage was just created we don't have style() or a parent() // yet so all we can do is update our intrinsic size. Once we're inserted // the resulting layout will do the rest of the work. if (!parent()) { updateIntrinsicSizeIfNeeded(m_imageResource->intrinsicSize()); return; } RenderReplaced::imageChanged(newImage, rect); ASSERT(isRooted()); LayoutSize oldIntrinsicSize = intrinsicSize(); LayoutSize newIntrinsicSize = m_imageResource->intrinsicSize(); updateIntrinsicSizeIfNeeded(newIntrinsicSize); bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize; if (imageSourceHasChangedSize) setPreferredLogicalWidthsDirty(); // If the actual area occupied by the image has changed and it is not constrained by style then a layout is required. bool imageSizeIsConstrained = style()->logicalWidth().isSpecified() && style()->logicalHeight().isSpecified(); // FIXME: We only need to recompute the containing block's preferred size if the containing block's size // depends on the image's size (i.e., the container uses shrink-to-fit sizing). // There's no easy way to detect that shrink-to-fit is needed, always force a layout. bool containingBlockNeedsToRecomputePreferredSize = style()->logicalWidth().isPercent() || style()->logicalMaxWidth().isPercent() || style()->logicalMinWidth().isPercent(); if (imageSourceHasChangedSize && (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize)) { setNeedsLayout(); return; } // The image hasn't changed in size or its style constrains its size, so a paint invalidation will suffice. if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now // (unless the box has already been scheduled for layout). In order to calculate it, we // may need values from the containing block, though, so make sure that we're not too // early. It may be that layout hasn't even taken place once yet. updateInnerContentRect(); } }
void RenderLineBreak::deleteInlineBoxWrapper() { if (!m_inlineBoxWrapper) return; if (!documentBeingDestroyed()) m_inlineBoxWrapper->removeFromParent(); delete m_inlineBoxWrapper; m_inlineBoxWrapper = nullptr; }
void RenderNamedFlowFragment::attachRegion() { RenderRegion::attachRegion(); if (documentBeingDestroyed() || !isValid()) return; updateRegionFlags(); }
RenderObject* RenderSVGContainer::removeChildNode(RenderObject* oldChild, bool fullRemove) { ASSERT(oldChild->parent() == this); // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or // that a positioned child got yanked). We also repaint, so that the area exposed when the child // disappears gets repainted properly. if (!documentBeingDestroyed() && fullRemove) { oldChild->setNeedsLayoutAndPrefWidthsRecalc(); oldChild->repaint(); } // If we have a line box wrapper, delete it. oldChild->deleteLineBoxWrapper(); if (!documentBeingDestroyed() && fullRemove) { // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The SelectionController should be responsible for this when it // is notified of DOM mutations. if (oldChild->isSelectionBorder()) view()->clearSelection(); } // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (m_firstChild == oldChild) m_firstChild = oldChild->nextSibling(); if (m_lastChild == oldChild) m_lastChild = oldChild->previousSibling(); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); if (AXObjectCache::accessibilityEnabled()) document()->axObjectCache()->childrenChanged(this); return oldChild; }
RenderObject* 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()) { RenderRubyBase* base = rubyBase(); RenderObject* rightNeighbour = nextSibling(); if (base && rightNeighbour && rightNeighbour->isRubyRun()) { // Ruby run without a base can happen only at the first run. RenderRubyRun* rightRun = toRenderRubyRun(rightNeighbour); if (rightRun->hasRubyBase()) { RenderRubyBase* rightBase = rightRun->rubyBaseSafe(); // Collect all children in a single base, then swap the bases. rightBase->mergeChildrenWithBase(base); moveChildTo(rightRun, base); rightRun->moveChildTo(this, rightBase); // The now empty ruby base will be removed below. ASSERT(!rubyBase()->firstChild()); } } } RenderObject* next = RenderBlockFlow::removeChild(child); if (!beingDestroyed() && !documentBeingDestroyed()) { // Check if our base (if any) is now empty. If so, destroy it. RenderBlock* base = rubyBase(); if (base && !base->firstChild()) { next = RenderBlockFlow::removeChild(*base); base->deleteLines(); base->destroy(); } // If any of the above leaves the run empty, destroy it as well. if (isEmpty()) { parent()->removeChild(*this); deleteLines(); destroy(); next = nullptr; } } return next; }
void LayoutMultiColumnSet::attachToFlowThread() { if (documentBeingDestroyed()) return; if (!m_flowThread) return; m_flowThread->addColumnSetToThread(this); }
void RenderSVGText::subtreeChildWasAdded(RenderObject* child) { ASSERT(child); if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt. FontCachePurgePreventer fontCachePurgePreventer; // The positioning elements cache doesn't include the new 'child' yet. Clear the // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it. m_layoutAttributesBuilder.clearTextPositioningElements(); if (!child->isSVGInlineText() && !child->isSVGInline()) return; // Detect changes in layout attributes and only measure those text parts that have changed! Vector<SVGTextLayoutAttributes*> newLayoutAttributes; collectLayoutAttributes(this, newLayoutAttributes); if (newLayoutAttributes.isEmpty()) { ASSERT(m_layoutAttributes.isEmpty()); return; } // Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added. size_t size = newLayoutAttributes.size(); SVGTextLayoutAttributes* attributes = 0; for (size_t i = 0; i < size; ++i) { attributes = newLayoutAttributes[i]; if (m_layoutAttributes.find(attributes) == notFound) { // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes. bool stopAfterNext = false; SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; ASSERT_UNUSED(child, &attributes->context() == child); findPreviousAndNextAttributes(this, &attributes->context(), stopAfterNext, previous, next); if (previous) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context()); m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context()); if (next) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context()); break; } } #ifndef NDEBUG // Verify that m_layoutAttributes only differs by a maximum of one entry. for (size_t i = 0; i < size; ++i) ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes); #endif m_layoutAttributes = newLayoutAttributes; }
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 (!m_beingDestroyed && !documentBeingDestroyed() && child->isRubyText()) { RenderRubyBase* base = rubyBase(); RenderObject* rightNeighbour = nextSibling(); if (base && rightNeighbour && rightNeighbour->isRubyRun()) { // Ruby run without a base can happen only at the first run. RenderRubyRun* rightRun = static_cast<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); // The now empty ruby base will be removed below. } } } RenderBlock::removeChild(child); if (!m_beingDestroyed && !documentBeingDestroyed()) { // Check if our base (if any) is now empty. If so, destroy it. RenderBlock* base = rubyBase(); if (base && !base->firstChild()) { RenderBlock::removeChild(base); base->deleteLineBoxTree(); base->destroy(); } // If any of the above leaves the run empty, destroy it as well. if (isEmpty()) { parent()->removeChild(this); deleteLineBoxTree(); destroy(); } } }
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(); } } }
void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes) { if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) { ASSERT(affectedAttributes.isEmpty()); return; } // This is called immediately after subtreeChildWillBeDestroyed, once the RenderSVGInlineText::willBeDestroyed() method // passes on to the base class, which removes us from the render tree. At this point we can update the layout attributes. unsigned size = affectedAttributes.size(); for (unsigned i = 0; i < size; ++i) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context()); }
void RenderRegion::attachRegion() { if (documentBeingDestroyed()) return; // A region starts off invalid. setIsValid(false); if (!m_flowThread) return; // Only after adding the region to the thread, the region is marked to be valid. m_flowThread->addRegionToThread(this); }
void RenderSVGText::subtreeStyleDidChange() { if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; checkLayoutAttributesConsistency(this, m_layoutAttributes); // Only update the metrics cache, but not the text positioning element cache // nor the layout attributes cached in the leaf #text renderers. FontCachePurgePreventer fontCachePurgePreventer; for (RenderObject* descendant = firstChild(); descendant; descendant = descendant->nextInPreOrder(this)) { if (descendant->isSVGInlineText()) m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant)); } }
void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) { ASSERT(text); if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; checkLayoutAttributesConsistency(this, m_layoutAttributes); // Only update the metrics cache, but not the text positioning element cache // nor the layout attributes cached in the leaf #text renderers. for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { if (is<RenderSVGInlineText>(*descendant)) m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(downcast<RenderSVGInlineText>(*descendant)); } }
void RenderImage::notifyFinished(Resource* newImage) { if (!m_imageResource) return; if (documentBeingDestroyed()) return; invalidateBackgroundObscurationStatus(); if (newImage == m_imageResource->cachedImage()) { // tell any potential compositing layers // that the image is done and they can reference it directly. contentChanged(ImageChanged); } }
void RenderNamedFlowFragment::attachRegion() { RenderRegion::attachRegion(); if (documentBeingDestroyed() || !m_flowThread) return; // The region just got attached to the flow thread, lets check whether // it has region styling rules associated. checkRegionStyle(); if (!isValid()) return; m_hasAutoLogicalHeight = shouldHaveAutoLogicalHeight(); if (hasAutoLogicalHeight()) incrementAutoLogicalHeightCount(); }
void RenderRegion::attachRegion() { if (documentBeingDestroyed()) return; // A region starts off invalid. setIsValid(false); // Initialize the flow thread reference and create the flow thread object if needed. // The flow thread lifetime is influenced by the number of regions attached to it, // and we are attaching the region to the flow thread. installFlowThread(); if (!m_flowThread) return; // Only after adding the region to the thread, the region is marked to be valid. m_flowThread->addRegionToThread(this); }
void RenderQuote::detachQuote() { ASSERT(!m_next || m_next->m_isAttached); ASSERT(!m_previous || m_previous->m_isAttached); if (!m_isAttached) return; if (m_previous) m_previous->m_next = m_next; else view().setRenderQuoteHead(m_next); if (m_next) m_next->m_previous = m_previous; if (!documentBeingDestroyed()) { for (RenderQuote* quote = m_next; quote; quote = quote->m_next) quote->updateDepth(); } m_isAttached = false; m_next = 0; m_previous = 0; }
void RenderRegion::attachRegion() { if (documentBeingDestroyed()) return; // A region starts off invalid. setIsValid(false); // Initialize the flow thread reference and create the flow thread object if needed. // The flow thread lifetime is influenced by the number of regions attached to it, // and we are attaching the region to the flow thread. installFlowThread(); if (!m_flowThread) return; m_flowThread->addRegionToThread(this); // The region just got attached to the flow thread, lets check whether // it has region styling rules associated. checkRegionStyle(); }
RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool fullRemove) { ASSERT(oldChild->parent() == this); // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or // that a positioned child got yanked). We also repaint, so that the area exposed when the child // disappears gets repainted properly. if (!documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { oldChild->setNeedsLayoutAndPrefWidthsRecalc(); oldChild->repaint(); } // If we have a line box wrapper, delete it. oldChild->deleteLineBoxWrapper(); if (!documentBeingDestroyed() && fullRemove) { // if we remove visible child from an invisible parent, we don't know the layer visibility any more RenderLayer* layer = 0; if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { layer = enclosingLayer(); layer->dirtyVisibleContentStatus(); } // Keep our layer hierarchy updated. if (oldChild->firstChild() || oldChild->hasLayer()) { if (!layer) layer = enclosingLayer(); oldChild->removeLayers(layer); } // renumber ordered lists if (oldChild->isListItem()) updateListMarkerNumbers(oldChild->nextSibling()); if (oldChild->isPositioned() && childrenInline()) dirtyLinesFromChangedChild(oldChild); } // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The SelectionController should be responsible for this when it // is notified of DOM mutations. if (!documentBeingDestroyed() && oldChild->isSelectionBorder()) view()->clearSelection(); // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (m_firstChild == oldChild) m_firstChild = oldChild->nextSibling(); if (m_lastChild == oldChild) m_lastChild = oldChild->previousSibling(); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); if (AXObjectCache::accessibilityEnabled()) document()->axObjectCache()->childrenChanged(this); return oldChild; }