void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject* newFloat) { LayoutUnit height = m_block.logicalHeight(); if (height < m_block.logicalTopForFloat(newFloat) || height >= m_block.logicalBottomForFloat(newFloat)) return; #if ENABLE(CSS_SHAPES) // When floats with shape outside are stacked, the floats are positioned based on the margin box of the float, // not the shape's contour. Since we computed the width based on the shape contour when we added the float, // when we add a subsequent float on the same line, we need to undo the shape delta in order to position // based on the margin box. In order to do this, we need to walk back through the floating object list to find // the first previous float that is on the same side as our newFloat. ShapeOutsideInfo* previousShapeOutsideInfo = 0; const FloatingObjectSet& floatingObjectSet = m_block.m_floatingObjects->set(); auto it = floatingObjectSet.end(); auto begin = floatingObjectSet.begin(); LayoutUnit lineHeight = m_block.lineHeight(m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); for (--it; it != begin; --it) { FloatingObject* previousFloat = it->get(); if (previousFloat != newFloat && previousFloat->type() == newFloat->type()) { previousShapeOutsideInfo = previousFloat->renderer().shapeOutsideInfo(); if (previousShapeOutsideInfo) previousShapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, previousFloat, m_block.logicalHeight(), lineHeight); break; } } ShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer().shapeOutsideInfo(); if (shapeOutsideInfo) shapeOutsideInfo->updateDeltasForContainingBlockLine(&m_block, newFloat, m_block.logicalHeight(), lineHeight); #endif if (newFloat->type() == FloatingObject::FloatLeft) { float newLeft = m_block.logicalRightForFloat(newFloat); #if ENABLE(CSS_SHAPES) if (previousShapeOutsideInfo) newLeft -= previousShapeOutsideInfo->rightMarginBoxDelta(); if (shapeOutsideInfo) newLeft += shapeOutsideInfo->rightMarginBoxDelta(); #endif if (shouldIndentText() && m_block.style()->isLeftToRightDirection()) newLeft += floorToInt(m_block.textIndentOffset()); m_left = std::max<float>(m_left, newLeft); } else { float newRight = m_block.logicalLeftForFloat(newFloat); #if ENABLE(CSS_SHAPES) if (previousShapeOutsideInfo) newRight -= previousShapeOutsideInfo->leftMarginBoxDelta(); if (shapeOutsideInfo) newRight += shapeOutsideInfo->leftMarginBoxDelta(); #endif if (shouldIndentText() && !m_block.style()->isLeftToRightDirection()) newRight -= floorToInt(m_block.textIndentOffset()); m_right = std::min<float>(m_right, newRight); } computeAvailableWidthFromLeftAndRight(); }
void LineWidth::fitBelowFloats(bool isFirstLine) { ASSERT(!m_committedWidth); ASSERT(!fitsOnLine()); LayoutUnit floatLogicalBottom; LayoutUnit lastFloatLogicalBottom = m_block.logicalHeight(); float newLineWidth = m_availableWidth; float newLineLeft = m_left; float newLineRight = m_right; FloatingObject* lastFloatFromPreviousLine = (m_block.containsFloats() ? m_block.m_floatingObjects->set().last().get() : 0); if (lastFloatFromPreviousLine && lastFloatFromPreviousLine->renderer()->shapeOutsideInfo()) return wrapNextToShapeOutside(isFirstLine); while (true) { floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lastFloatLogicalBottom, ShapeOutsideFloatShapeOffset); if (floatLogicalBottom <= lastFloatLogicalBottom) break; newLineWidth = availableWidthAtOffset(m_block, floatLogicalBottom, shouldIndentText(), newLineLeft, newLineRight); lastFloatLogicalBottom = floatLogicalBottom; if (newLineWidth >= m_uncommittedWidth) break; } updateLineDimension(lastFloatLogicalBottom, newLineWidth, newLineLeft, newLineRight); }
void LineWidth::fitBelowFloats(bool isFirstLine) { ASSERT(!m_committedWidth); ASSERT(!fitsOnLine()); m_block.positionNewFloats(m_block.logicalHeight(), this); LayoutUnit floatLogicalBottom; LayoutUnit lastFloatLogicalBottom = m_block.logicalHeight(); LayoutUnit newLineWidth = m_availableWidth; LayoutUnit newLineLeft = m_left; LayoutUnit newLineRight = m_right; FloatingObject* lastFloatFromPreviousLine = m_block.lastFloatFromPreviousLine(); if (lastFloatFromPreviousLine && lastFloatFromPreviousLine->layoutObject()->shapeOutsideInfo()) return wrapNextToShapeOutside(isFirstLine); while (true) { floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lastFloatLogicalBottom); if (floatLogicalBottom <= lastFloatLogicalBottom) break; newLineWidth = availableWidthAtOffset( m_block, floatLogicalBottom, indentText(), newLineLeft, newLineRight); lastFloatLogicalBottom = floatLogicalBottom; if (newLineWidth >= m_uncommittedWidth) break; } updateLineDimension(lastFloatLogicalBottom, LayoutUnit(newLineWidth), newLineLeft, newLineRight); }
FloatingObject* FloatingObjects::add(PassOwnPtr<FloatingObject> floatingObject) { FloatingObject* newObject = floatingObject.leakPtr(); increaseObjectsCount(newObject->type()); m_set.add(adoptPtr(newObject)); if (newObject->isPlaced()) addPlacedObject(*newObject); markLowestFloatLogicalBottomCacheAsDirty(); return newObject; }
FloatingObject* FloatingObjects::add( std::unique_ptr<FloatingObject> floatingObject) { FloatingObject* newObject = floatingObject.release(); increaseObjectsCount(newObject->getType()); m_set.add(WTF::wrapUnique(newObject)); if (newObject->isPlaced()) addPlacedObject(*newObject); markLowestFloatLogicalBottomCacheAsDirty(); return newObject; }
inline FloatingObjectInterval FloatingObjects::intervalForFloatingObject( FloatingObject& floatingObject) { if (m_horizontalWritingMode) return FloatingObjectInterval(floatingObject.frameRect().y(), floatingObject.frameRect().maxY(), &floatingObject); return FloatingObjectInterval(floatingObject.frameRect().x(), floatingObject.frameRect().maxX(), &floatingObject); }
void FloatingObjects::addPlacedObject(FloatingObject& floatingObject) { ASSERT(!floatingObject.isInPlacedTree()); floatingObject.setIsPlaced(true); if (m_placedFloatsTree.isInitialized()) m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); #if ENABLE(ASSERT) floatingObject.setIsInPlacedTree(true); #endif markLowestFloatLogicalBottomCacheAsDirty(); }
void FloatingObjects::computePlacedFloatsTree() { ASSERT(!m_placedFloatsTree.isInitialized()); if (m_set.isEmpty()) return; m_placedFloatsTree.initIfNeeded(m_renderer->view().intervalArena()); for (auto it = m_set.begin(), end = m_set.end(); it != end; ++it) { FloatingObject* floatingObject = it->get(); if (floatingObject->isPlaced()) m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); } }
void FloatingObjects::computePlacedFloatsTree() { ASSERT(!m_placedFloatsTree); if (m_set.isEmpty()) return; m_placedFloatsTree = std::make_unique<FloatingObjectTree>(); for (auto it = m_set.begin(), end = m_set.end(); it != end; ++it) { FloatingObject* floatingObject = it->get(); if (floatingObject->isPlaced()) m_placedFloatsTree->add(intervalForFloatingObject(floatingObject)); } }
void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded( const FloatingObject& newFloat) { LayoutUnit height = m_block.logicalHeight(); if (height < m_block.logicalTopForFloat(newFloat) || height >= m_block.logicalBottomForFloat(newFloat)) return; ShapeOutsideDeltas shapeDeltas; if (ShapeOutsideInfo* shapeOutsideInfo = newFloat.layoutObject()->shapeOutsideInfo()) { LayoutUnit lineHeight = m_block.lineHeight( m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); shapeDeltas = shapeOutsideInfo->computeDeltasForContainingBlockLine( m_block, newFloat, m_block.logicalHeight(), lineHeight); } if (newFloat.getType() == FloatingObject::FloatLeft) { LayoutUnit newLeft = m_block.logicalRightForFloat(newFloat); if (shapeDeltas.isValid()) { if (shapeDeltas.lineOverlapsShape()) { newLeft += shapeDeltas.rightMarginBoxDelta(); } else { // Per the CSS Shapes spec, If the line doesn't overlap the shape, then // ignore this shape for this line. newLeft = m_left; } } if (indentText() == IndentText && m_block.style()->isLeftToRightDirection()) newLeft += floorToInt(m_block.textIndentOffset()); m_left = std::max(m_left, newLeft); } else { LayoutUnit newRight = m_block.logicalLeftForFloat(newFloat); if (shapeDeltas.isValid()) { if (shapeDeltas.lineOverlapsShape()) { newRight += shapeDeltas.leftMarginBoxDelta(); } else { // Per the CSS Shapes spec, If the line doesn't overlap the shape, then // ignore this shape for this line. newRight = m_right; } } if (indentText() == IndentText && !m_block.style()->isLeftToRightDirection()) newRight -= floorToInt(m_block.textIndentOffset()); m_right = std::min(m_right, newRight); } computeAvailableWidthFromLeftAndRight(); }
void FloatingObjects::removePlacedObject(FloatingObject& floatingObject) { ASSERT(floatingObject.isPlaced() && floatingObject.isInPlacedTree()); if (m_placedFloatsTree.isInitialized()) { bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject)); ASSERT_UNUSED(removed, removed); } floatingObject.setIsPlaced(false); #if ENABLE(ASSERT) floatingObject.setIsInPlacedTree(false); #endif markLowestFloatLogicalBottomCacheAsDirty(); }
void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(const FloatingObject& newFloat) { if (!newFloatShrinksLine(newFloat, m_block, m_isFirstLine)) return; #if ENABLE(CSS_SHAPES) ShapeOutsideDeltas shapeDeltas; if (ShapeOutsideInfo* shapeOutsideInfo = newFloat.renderer().shapeOutsideInfo()) { LayoutUnit lineHeight = m_block.lineHeight(m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); shapeDeltas = shapeOutsideInfo->computeDeltasForContainingBlockLine(m_block, newFloat, m_block.logicalHeight(), lineHeight); } #endif if (newFloat.type() == FloatingObject::FloatLeft) { float newLeft = m_block.logicalRightForFloat(newFloat); if (shouldIndentText() == IndentText && m_block.style().isLeftToRightDirection()) newLeft += floorToInt(m_block.textIndentOffset()); #if ENABLE(CSS_SHAPES) if (shapeDeltas.isValid()) { if (shapeDeltas.lineOverlapsShape()) newLeft += shapeDeltas.rightMarginBoxDelta(); else // If the line doesn't overlap the shape, then we need to act as if this float didn't exist. newLeft = m_left; } #endif m_left = std::max<float>(m_left, newLeft); } else { float newRight = m_block.logicalLeftForFloat(newFloat); if (shouldIndentText() == IndentText && !m_block.style().isLeftToRightDirection()) newRight -= floorToInt(m_block.textIndentOffset()); #if ENABLE(CSS_SHAPES) if (shapeDeltas.isValid()) { if (shapeDeltas.lineOverlapsShape()) newRight += shapeDeltas.leftMarginBoxDelta(); else // If the line doesn't overlap the shape, then we need to act as if this float didn't exist. newRight = m_right; } #endif m_right = std::min<float>(m_right, newRight); } computeAvailableWidthFromLeftAndRight(); }
static bool newFloatShrinksLine(const FloatingObject& newFloat, const RenderBlockFlow& block, bool isFirstLine) { LayoutUnit blockOffset = block.logicalHeight(); if (blockOffset >= block.logicalTopForFloat(newFloat) && blockOffset < block.logicalBottomForFloat(newFloat)) return true; // initial-letter float always shrinks the first line. const auto& style = newFloat.renderer().style(); if (isFirstLine && style.styleType() == FIRST_LETTER && !style.initialLetter().isEmpty()) return true; return false; }
inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject& floatingObject) { LayoutUnit logicalLeft = m_layoutObject->logicalLeftForFloat(floatingObject); if (ShapeOutsideInfo* shapeOutside = floatingObject.layoutObject()->shapeOutsideInfo()) { ShapeOutsideDeltas shapeDeltas = shapeOutside->computeDeltasForContainingBlockLine(LineLayoutBlockFlow(const_cast<LayoutBlockFlow*>(m_layoutObject)), floatingObject, m_lineTop, m_lineBottom - m_lineTop); if (!shapeDeltas.lineOverlapsShape()) return false; logicalLeft += shapeDeltas.leftMarginBoxDelta(); } if (logicalLeft < m_offset) { m_offset = logicalLeft; return true; } return false; }
inline bool ComputeFloatOffsetForLineLayoutAdapter<FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject& floatingObject) { LayoutUnit logicalRight = m_renderer.logicalRightForFloat(floatingObject); if (ShapeOutsideInfo* shapeOutside = floatingObject.renderer().shapeOutsideInfo()) { ShapeOutsideDeltas shapeDeltas = shapeOutside->computeDeltasForContainingBlockLine(m_renderer, floatingObject, m_lineTop, m_lineBottom - m_lineTop); if (!shapeDeltas.lineOverlapsShape()) return false; logicalRight += shapeDeltas.rightMarginBoxDelta(); } if (logicalRight > m_offset) { m_offset = logicalRight; return true; } return false; }
inline FloatingObjectInterval FloatingObjects::intervalForFloatingObject(FloatingObject& floatingObject) { if (m_horizontalWritingMode) return FloatingObjectInterval(floatingObject.frameRect().pixelSnappedY(), floatingObject.frameRect().pixelSnappedMaxY(), &floatingObject); return FloatingObjectInterval(floatingObject.frameRect().pixelSnappedX(), floatingObject.frameRect().pixelSnappedMaxX(), &floatingObject); }