bool RenderFlowThread::logicalWidthChangedInRegions(const RenderBlock* block, LayoutUnit offsetFromLogicalTopOfFirstPage) { if (!hasRegions() || block == this) // Not necessary, since if any region changes, we do a full pagination relayout anyway. return false; RenderRegion* startRegion; RenderRegion* endRegion; getRegionRangeForBox(block, startRegion, endRegion); // If the block doesn't have a startRegion (and implicitly a region range) it's safe to assume the width in regions has changed (e.g. the region chain was invalidated). if (!startRegion) return true; for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; ASSERT(!region->needsLayout()); OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block); if (!oldInfo) continue; LayoutUnit oldLogicalWidth = oldInfo->logicalWidth(); RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region, offsetFromLogicalTopOfFirstPage); if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) return true; if (region == endRegion) break; } return false; }
bool RenderFlowThread::logicalWidthChangedInRegions(const RenderBlock* block, LayoutUnit offsetFromLogicalTopOfFirstPage) { if (!hasRegions() || block == this) // Not necessary, since if any region changes, we do a full pagination relayout anyway. return false; RenderRegion* startRegion; RenderRegion* endRegion; getRegionRangeForBox(block, startRegion, endRegion); for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) continue; ASSERT(!region->needsLayout()); OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block); if (!oldInfo) continue; LayoutUnit oldLogicalWidth = oldInfo->logicalWidth(); RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region, offsetFromLogicalTopOfFirstPage); if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) return true; if (region == endRegion) break; } return false; }
void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box) { if (!hasRegions()) return; RenderRegion* startRegion; RenderRegion* endRegion; getRegionRangeForBox(box, startRegion, endRegion); for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; region->removeRenderBoxRegionInfo(box); if (region == endRegion) break; } #ifndef NDEBUG // We have to make sure we did not leave any RenderBoxRegionInfo attached. for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; ASSERT(!region->renderBoxRegionInfo(box)); } #endif m_regionRangeMap.remove(box); }
void RenderFlowThread::removeRenderBoxRegionInfo(RenderBox* box) { if (!hasRegions()) return; // If the region chain was invalidated the next layout will clear the box information from all the regions. if (m_regionsInvalidated) { ASSERT(selfNeedsLayout()); return; } RenderRegion* startRegion; RenderRegion* endRegion; getRegionRangeForBox(box, startRegion, endRegion); for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; region->removeRenderBoxRegionInfo(box); if (region == endRegion) break; } #ifndef NDEBUG // We have to make sure we did not leave any RenderBoxRegionInfo attached. for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; ASSERT(!region->renderBoxRegionInfo(box)); } #endif m_regionRangeMap.remove(box); }
bool RenderFlowThread::objectInFlowRegion(const RenderObject* object, const RenderRegion* region) const { ASSERT(object); ASSERT(region); if (!object->inRenderFlowThread()) return false; if (object->enclosingRenderFlowThread() != this) return false; if (!m_regionList.contains(const_cast<RenderRegion*>(region))) return false; RenderBox* enclosingBox = object->enclosingBox(); RenderRegion* enclosingBoxStartRegion = 0; RenderRegion* enclosingBoxEndRegion = 0; getRegionRangeForBox(enclosingBox, enclosingBoxStartRegion, enclosingBoxEndRegion); if (!regionInRange(region, enclosingBoxStartRegion, enclosingBoxEndRegion)) return false; if (object->isBox()) return true; LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true); if (!objectABBRect.width()) objectABBRect.setWidth(1); if (!objectABBRect.height()) objectABBRect.setHeight(1); if (objectABBRect.intersects(region->absoluteBoundingBoxRect(true))) return true; if (region == lastRegion()) { // If the object does not intersect any of the enclosing box regions // then the object is in last region. for (RenderRegionList::const_iterator it = m_regionList.find(enclosingBoxStartRegion); it != m_regionList.end(); ++it) { const RenderRegion* currRegion = *it; if (!region->isValid()) continue; if (currRegion == region) break; if (objectABBRect.intersects(currRegion->absoluteBoundingBoxRect(true))) return false; } return true; } return false; }
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; }
bool RenderFlowThread::logicalWidthChangedInRegions(const RenderBlock* block, LayoutUnit offsetFromLogicalTopOfFirstPage) { if (!hasRegions()) return false; RenderRegion* startRegion; RenderRegion* endRegion; getRegionRangeForBox(block, startRegion, endRegion); // When the region chain is invalidated the box information is discarded so we must assume the width has changed. if (m_pageLogicalSizeChanged && !startRegion) return true; // Not necessary for the flow thread, since we already computed the correct info for it. if (block == this) return false; for (RenderRegionList::iterator iter = m_regionList.find(startRegion); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; ASSERT(!region->needsLayout() || region->isRenderRegionSet()); OwnPtr<RenderBoxRegionInfo> oldInfo = region->takeRenderBoxRegionInfo(block); if (!oldInfo) continue; LayoutUnit oldLogicalWidth = oldInfo->logicalWidth(); RenderBoxRegionInfo* newInfo = block->renderBoxRegionInfo(region, offsetFromLogicalTopOfFirstPage); if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) return true; if (region == endRegion) break; } return false; }
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; }