void RenderNamedFlowThread::checkInvalidRegions() { Vector<RenderNamedFlowFragment*> newValidFragments; for (auto& region : m_invalidRegionList) { RenderNamedFlowFragment* namedFlowFragment = toRenderNamedFlowFragment(region); // The only reason a region would be invalid is because it has a parent flow thread. ASSERT(!namedFlowFragment->isValid() && namedFlowFragment->parentNamedFlowThread()); if (namedFlowFragment->parentNamedFlowThread()->dependsOn(this)) continue; newValidFragments.append(namedFlowFragment); } for (auto& namedFlowFragment : newValidFragments) { m_invalidRegionList.remove(namedFlowFragment); namedFlowFragment->parentNamedFlowThread()->m_observerThreadsSet.remove(this); addFragmentToNamedFlowThread(namedFlowFragment); } if (!newValidFragments.isEmpty()) invalidateRegions(); if (m_observerThreadsSet.isEmpty()) return; // Notify all the flow threads that were dependent on this flow. // Create a copy of the list first. That's because observers might change the list when calling checkInvalidRegions. Vector<RenderNamedFlowThread*> observers; copyToVector(m_observerThreadsSet, observers); for (auto& flowThread : observers) flowThread->checkInvalidRegions(); }
LayoutRect RenderRegion::rectFlowPortionForBox(const RenderBox* box, const LayoutRect& rect) const { RenderRegion* startRegion = 0; RenderRegion* endRegion = 0; m_flowThread->getRegionRangeForBox(box, startRegion, endRegion); LayoutRect mappedRect = m_flowThread->mapFromLocalToFlowThread(box, rect); if (flowThread()->isHorizontalWritingMode()) { if (this != startRegion) mappedRect.shiftYEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.y())); if (this != endRegion) mappedRect.setHeight(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.y(), mappedRect.height()))); } else { if (this != startRegion) mappedRect.shiftXEdgeTo(std::max<LayoutUnit>(logicalTopForFlowThreadContent(), mappedRect.x())); if (this != endRegion) mappedRect.setWidth(std::max<LayoutUnit>(0, std::min<LayoutUnit>(logicalBottomForFlowThreadContent() - mappedRect.x(), mappedRect.width()))); } if (shouldClipFlowThreadContent()) { LayoutRect portionRect; if (isRenderNamedFlowFragment()) portionRect = toRenderNamedFlowFragment(this)->flowThreadPortionRectForClipping(this == startRegion, this == endRegion); else portionRect = flowThreadPortionRect(); mappedRect.intersect(portionRect); } return mappedRect.isEmpty() ? mappedRect : m_flowThread->mapFromFlowThreadToLocal(box, mappedRect); }
void RenderNamedFlowThread::clearRenderObjectCustomStyle(const RenderObject* object) { // Clear the styles for the object in the regions. // FIXME: Region styling is not computed only for the region range of the object so this is why we need to walk the whole chain. for (auto& region : m_regionList) toRenderNamedFlowFragment(region)->clearObjectStyleInRegion(object); }
void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion) { ASSERT(renderRegion); RenderNamedFlowFragment* renderNamedFlowFragment = toRenderNamedFlowFragment(renderRegion); if (renderNamedFlowFragment->parentNamedFlowThread()) { if (!renderNamedFlowFragment->isValid()) { ASSERT(m_invalidRegionList.contains(renderNamedFlowFragment)); m_invalidRegionList.remove(renderNamedFlowFragment); renderNamedFlowFragment->parentNamedFlowThread()->m_observerThreadsSet.remove(this); // No need to invalidate the regions rectangles. The removed region // was not taken into account. Just return here. return; } removeDependencyOnFlowThread(renderNamedFlowFragment->parentNamedFlowThread()); } ASSERT(m_regionList.contains(renderNamedFlowFragment)); bool wasFirst = m_regionList.first() == renderNamedFlowFragment; m_regionList.remove(renderNamedFlowFragment); if (canBeDestroyed()) setMarkForDestruction(); if (!m_regionList.isEmpty() && wasFirst) updateWritingMode(); invalidateRegions(); }
// Check if the content is flown into at least a region with region styling rules. void RenderNamedFlowThread::checkRegionsWithStyling() { bool hasRegionsWithStyling = false; for (const auto& region : m_regionList) { if (toRenderNamedFlowFragment(region)->hasCustomRegionStyle()) { hasRegionsWithStyling = true; break; } } m_hasRegionsWithStyling = hasRegionsWithStyling; }
void RenderNamedFlowThread::updateWritingMode() { RenderNamedFlowFragment* firstFragment = toRenderNamedFlowFragment(m_regionList.first()); if (!firstFragment) return; if (style().writingMode() == firstFragment->style().writingMode()) return; // The first region defines the principal writing mode for the entire flow. auto newStyle = RenderStyle::clone(&style()); newStyle.get().setWritingMode(firstFragment->style().writingMode()); setStyle(WTF::move(newStyle)); }
RenderNamedFlowFragment* RenderNamedFlowThread::fragmentFromAbsolutePointAndBox(const IntPoint& absolutePoint, const RenderBox& flowedBox) { RenderRegion* startRegion = nullptr; RenderRegion* endRegion = nullptr; if (!getRegionRangeForBox(&flowedBox, startRegion, endRegion)) return nullptr; for (auto iter = m_regionList.find(startRegion), end = m_regionList.end(); iter != end; ++iter) { RenderNamedFlowFragment* fragment = toRenderNamedFlowFragment(*iter); RenderBlockFlow& fragmentContainer = fragment->fragmentContainer(); IntRect fragmentAbsoluteRect(roundedIntPoint(fragmentContainer.localToAbsolute()), roundedIntSize(fragmentContainer.paddingBoxRect().size())); if (fragmentAbsoluteRect.contains(absolutePoint)) return fragment; if (fragment == endRegion) break; } return nullptr; }
void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion) { ASSERT(renderRegion); ASSERT(!renderRegion->isValid()); RenderNamedFlowFragment* renderNamedFlowFragment = toRenderNamedFlowFragment(renderRegion); resetMarkForDestruction(); if (renderNamedFlowFragment->parentNamedFlowThread() && renderNamedFlowFragment->parentNamedFlowThread()->dependsOn(this)) { // The order of invalid regions is irrelevant. m_invalidRegionList.add(renderNamedFlowFragment); // Register ourself to get a notification when the state changes. renderNamedFlowFragment->parentNamedFlowThread()->m_observerThreadsSet.add(this); return; } addFragmentToNamedFlowThread(renderNamedFlowFragment); invalidateRegions(); }
// This helper function adds a region to a list preserving the order property of the list. static void addFragmentToList(RenderRegionList& regionList, RenderNamedFlowFragment* renderNamedFlowFragment) { if (regionList.isEmpty()) regionList.add(renderNamedFlowFragment); else { // Find the first region "greater" than renderNamedFlowFragment. auto it = regionList.begin(); while (it != regionList.end() && !compareRenderNamedFlowFragments(renderNamedFlowFragment, toRenderNamedFlowFragment(*it))) ++it; regionList.insertBefore(it, renderNamedFlowFragment); } }