diff options
Diffstat (limited to 'Source/WebCore/rendering')
35 files changed, 566 insertions, 342 deletions
diff --git a/Source/WebCore/rendering/AutoTableLayout.cpp b/Source/WebCore/rendering/AutoTableLayout.cpp index 3b93a5118..27330f7b0 100644 --- a/Source/WebCore/rendering/AutoTableLayout.cpp +++ b/Source/WebCore/rendering/AutoTableLayout.cpp @@ -181,9 +181,27 @@ void AutoTableLayout::fullRecalc() recalcColumn(i); } +static bool shouldScaleColumnsForParent(const RenderTable& table) +{ + RenderBlock* containingBlock = table.containingBlock(); + while (containingBlock && !is<RenderView>(containingBlock)) { + // It doesn't matter if our table is auto or fixed: auto means we don't + // scale. Fixed doesn't care if we do or not because it doesn't depend + // on the cell contents' preferred widths. + if (is<RenderTableCell>(containingBlock)) + return false; + containingBlock = containingBlock->containingBlock(); + } + return true; +} + // FIXME: This needs to be adapted for vertical writing modes. -static bool shouldScaleColumns(RenderTable* table) +static bool shouldScaleColumnsForSelf(RenderTable* table) { + // Normally, scale all columns to satisfy this from CSS2.2: + // "A percentage value for a column width is relative to the table width. + // If the table has 'width: auto', a percentage represents a constraint on the column's width" + // A special case. If this table is not fixed width and contained inside // a cell, then don't bloat the maxwidth by examining percentage growth. bool scale = true; @@ -220,7 +238,7 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout maxWidth = 0; float maxPercent = 0; float maxNonPercent = 0; - bool scaleColumns = shouldScaleColumns(m_table); + bool scaleColumnsForSelf = shouldScaleColumnsForSelf(m_table); // We substitute 0 percent by (epsilon / percentScaleFactor) percent in two places below to avoid division by zero. // FIXME: Handle the 0% cases properly. @@ -230,7 +248,7 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout for (size_t i = 0; i < m_layoutStruct.size(); ++i) { minWidth += m_layoutStruct[i].effectiveMinLogicalWidth; maxWidth += m_layoutStruct[i].effectiveMaxLogicalWidth; - if (scaleColumns) { + if (scaleColumnsForSelf) { if (m_layoutStruct[i].effectiveLogicalWidth.isPercent()) { float percent = std::min(m_layoutStruct[i].effectiveLogicalWidth.percent(), remainingPercent); float logicalWidth = m_layoutStruct[i].effectiveMaxLogicalWidth * 100 / std::max(percent, epsilon); @@ -241,10 +259,12 @@ void AutoTableLayout::computeIntrinsicLogicalWidths(LayoutUnit& minWidth, Layout } } - if (scaleColumns) { + if (scaleColumnsForSelf) { maxNonPercent = maxNonPercent * 100 / std::max(remainingPercent, epsilon); - maxWidth = std::max(maxWidth, LayoutUnit(std::min<float>(maxNonPercent, tableMaxWidth))); - maxWidth = std::max(maxWidth, LayoutUnit(std::min<float>(maxPercent, tableMaxWidth))); + m_scaledWidthFromPercentColumns = LayoutUnit(std::min<float>(maxNonPercent, tableMaxWidth)); + m_scaledWidthFromPercentColumns = std::max(m_scaledWidthFromPercentColumns, LayoutUnit(std::min<float>(maxPercent, tableMaxWidth))); + if (m_scaledWidthFromPercentColumns > maxWidth && shouldScaleColumnsForParent(*m_table)) + maxWidth = m_scaledWidthFromPercentColumns; } maxWidth = std::max(maxWidth, LayoutUnit(spanMaxLogicalWidth)); diff --git a/Source/WebCore/rendering/AutoTableLayout.h b/Source/WebCore/rendering/AutoTableLayout.h index ce108ad90..f73f62cf8 100644 --- a/Source/WebCore/rendering/AutoTableLayout.h +++ b/Source/WebCore/rendering/AutoTableLayout.h @@ -36,9 +36,10 @@ public: explicit AutoTableLayout(RenderTable*); virtual ~AutoTableLayout(); - virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) override; - virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const override; - virtual void layout() override; + void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) override; + LayoutUnit scaledWidthFromPercentColumns() const override { return m_scaledWidthFromPercentColumns; } + void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const override; + void layout() override; private: void fullRecalc(); @@ -63,6 +64,7 @@ private: Vector<RenderTableCell*, 4> m_spanCells; bool m_hasPercent : 1; mutable bool m_effectiveLogicalWidthDirty : 1; + LayoutUnit m_scaledWidthFromPercentColumns; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/InlineIterator.h b/Source/WebCore/rendering/InlineIterator.h index 0c8fb3827..4dc5b4f21 100644 --- a/Source/WebCore/rendering/InlineIterator.h +++ b/Source/WebCore/rendering/InlineIterator.h @@ -492,7 +492,7 @@ static inline unsigned numberOfIsolateAncestors(const InlineIterator& iter) // of BidiResolver which knows nothing about RenderObjects. static inline void addPlaceholderRunForIsolatedInline(InlineBidiResolver& resolver, RenderObject& obj, unsigned pos, RenderElement& root) { - BidiRun* isolatedRun = new BidiRun(pos, 0, obj, resolver.context(), resolver.dir()); + BidiRun* isolatedRun = new BidiRun(pos, pos, obj, resolver.context(), resolver.dir()); resolver.runs().addRun(isolatedRun); // FIXME: isolatedRuns() could be a hash of object->run and then we could cheaply // ASSERT here that we didn't create multiple objects for the same inline. diff --git a/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h index aefe10738..cb48a3642 100644 --- a/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h +++ b/Source/WebCore/rendering/LogicalSelectionOffsetCaches.h @@ -38,7 +38,8 @@ public: void setBlock(RenderBlock* block, const LogicalSelectionOffsetCaches* cache, bool parentCacheHasFloatsOrFlowThreads = false) { m_block = block; - m_hasFloatsOrFlowThreads = parentCacheHasFloatsOrFlowThreads || m_hasFloatsOrFlowThreads || m_block->containsFloats() || m_block->flowThreadContainingBlock(); + bool blockHasFloatsOrFlowThreads = m_block ? (m_block->containsFloats() || m_block->flowThreadContainingBlock()) : false; + m_hasFloatsOrFlowThreads = parentCacheHasFloatsOrFlowThreads || m_hasFloatsOrFlowThreads || blockHasFloatsOrFlowThreads; m_cache = cache; m_cachedLogicalLeftSelectionOffset = false; m_cachedLogicalRightSelectionOffset = false; @@ -49,9 +50,9 @@ public: ASSERT(m_cache); if (m_hasFloatsOrFlowThreads || !m_cachedLogicalLeftSelectionOffset) { m_cachedLogicalLeftSelectionOffset = true; - m_logicalLeftSelectionOffset = m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache); + m_logicalLeftSelectionOffset = m_block ? m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0); } else - ASSERT(m_logicalLeftSelectionOffset == m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache)); + ASSERT(m_logicalLeftSelectionOffset == (m_block ? m_block->logicalLeftSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0))); return m_logicalLeftSelectionOffset; } @@ -60,9 +61,9 @@ public: ASSERT(m_cache); if (m_hasFloatsOrFlowThreads || !m_cachedLogicalRightSelectionOffset) { m_cachedLogicalRightSelectionOffset = true; - m_logicalRightSelectionOffset = m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache); + m_logicalRightSelectionOffset = m_block ? m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0); } else - ASSERT(m_logicalRightSelectionOffset == m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache)); + ASSERT(m_logicalRightSelectionOffset == (m_block ? m_block->logicalRightSelectionOffset(rootBlock, position, *m_cache) : LayoutUnit::fromPixel(0))); return m_logicalRightSelectionOffset; } diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 3ffdef97d..bf1a78a7f 100644 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -92,11 +92,136 @@ struct SameSizeAsRenderBlock : public RenderBox { COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); -static TrackedDescendantsMap* gPositionedDescendantsMap; -static TrackedDescendantsMap* gPercentHeightDescendantsMap; +typedef HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>> TrackedDescendantsMap; +typedef HashMap<const RenderBox*, std::unique_ptr<HashSet<const RenderBlock*>>> TrackedContainerMap; -static TrackedContainerMap* gPositionedContainerMap; -static TrackedContainerMap* gPercentHeightContainerMap; +static TrackedDescendantsMap* percentHeightDescendantsMap; +static TrackedContainerMap* percentHeightContainerMap; + +static void insertIntoTrackedRendererMaps(const RenderBlock& container, RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) { + percentHeightDescendantsMap = new TrackedDescendantsMap; + percentHeightContainerMap = new TrackedContainerMap; + } + + auto& descendantSet = percentHeightDescendantsMap->ensure(&container, [] { + return std::make_unique<TrackedRendererListHashSet>(); + }).iterator->value; + + bool added = descendantSet->add(&descendant).isNewEntry; + if (!added) { + ASSERT(percentHeightContainerMap->get(&descendant)); + ASSERT(percentHeightContainerMap->get(&descendant)->contains(&container)); + return; + } + + auto& containerSet = percentHeightContainerMap->ensure(&descendant, [] { + return std::make_unique<HashSet<const RenderBlock*>>(); + }).iterator->value; + + ASSERT(!containerSet->contains(&container)); + containerSet->add(&container); +} + +static void removeFromTrackedRendererMaps(RenderBox& descendant) +{ + if (!percentHeightDescendantsMap) + return; + + std::unique_ptr<HashSet<const RenderBlock*>> containerSet = percentHeightContainerMap->take(&descendant); + if (!containerSet) + return; + + for (auto* container : *containerSet) { + // FIXME: Disabling this assert temporarily until we fix the layout + // bugs associated with positioned objects not properly cleared from + // their ancestor chain before being moved. See webkit bug 93766. + // ASSERT(descendant->isDescendantOf(container)); + auto descendantsMapIterator = percentHeightDescendantsMap->find(container); + ASSERT(descendantsMapIterator != percentHeightDescendantsMap->end()); + if (descendantsMapIterator == percentHeightDescendantsMap->end()) + continue; + auto& descendantSet = descendantsMapIterator->value; + ASSERT(descendantSet->contains(&descendant)); + descendantSet->remove(&descendant); + if (descendantSet->isEmpty()) + percentHeightDescendantsMap->remove(descendantsMapIterator); + } +} + +class PositionedDescendantsMap { +public: + enum class MoveDescendantToEnd { No, Yes }; + void addDescendant(const RenderBlock& containingBlock, RenderBox& positionedDescendant, MoveDescendantToEnd moveDescendantToEnd) + { + // Protect against double insert where a descendant would end up with multiple containing blocks. + auto* previousContainingBlock = m_containerMap.get(&positionedDescendant); + if (previousContainingBlock && previousContainingBlock != &containingBlock) { + if (auto* descendants = m_descendantsMap.get(previousContainingBlock)) + descendants->remove(&positionedDescendant); + } + + auto& descendants = m_descendantsMap.ensure(&containingBlock, [] { + return std::make_unique<TrackedRendererListHashSet>(); + }).iterator->value; + + bool isNewEntry = moveDescendantToEnd == MoveDescendantToEnd::Yes ? descendants->appendOrMoveToLast(&positionedDescendant).isNewEntry + : descendants->add(&positionedDescendant).isNewEntry; + if (!isNewEntry) { + ASSERT(m_containerMap.contains(&positionedDescendant)); + return; + } + m_containerMap.set(&positionedDescendant, &containingBlock); + } + + void removeDescendant(const RenderBox& positionedDescendant) + { + auto* containingBlock = m_containerMap.take(&positionedDescendant); + if (!containingBlock) + return; + + auto descendantsIterator = m_descendantsMap.find(containingBlock); + ASSERT(descendantsIterator != m_descendantsMap.end()); + if (descendantsIterator == m_descendantsMap.end()) + return; + + auto& descendants = descendantsIterator->value; + ASSERT(descendants->contains(const_cast<RenderBox*>(&positionedDescendant))); + + descendants->remove(const_cast<RenderBox*>(&positionedDescendant)); + if (descendants->isEmpty()) + m_descendantsMap.remove(descendantsIterator); + } + + void removeContainingBlock(const RenderBlock& containingBlock) + { + auto descendants = m_descendantsMap.take(&containingBlock); + if (!descendants) + return; + + for (auto* renderer : *descendants) + m_containerMap.remove(renderer); + } + + TrackedRendererListHashSet* positionedRenderers(const RenderBlock& containingBlock) const + { + return m_descendantsMap.get(&containingBlock); + } + +private: + using DescendantsMap = HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>>; + using ContainerMap = HashMap<const RenderBox*, const RenderBlock*>; + + DescendantsMap m_descendantsMap; + ContainerMap m_containerMap; +}; + +static PositionedDescendantsMap& positionedDescendantsMap() +{ + static NeverDestroyed<PositionedDescendantsMap> mapForPositionedDescendants; + return mapForPositionedDescendants; +} typedef HashMap<RenderBlock*, std::unique_ptr<ListHashSet<RenderInline*>>> ContinuationOutlineTableMap; @@ -192,21 +317,24 @@ RenderBlock::RenderBlock(Document& document, Ref<RenderStyle>&& style, BaseTypeF { } -static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap) +static void removeBlockFromPercentageDescendantAndContainerMaps(RenderBlock* block) { - if (std::unique_ptr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) { - TrackedRendererListHashSet::iterator end = descendantSet->end(); - for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { - TrackedContainerMap::iterator it = containerMap->find(*descendant); - ASSERT(it != containerMap->end()); - if (it == containerMap->end()) - continue; - HashSet<RenderBlock*>* containerSet = it->value.get(); - ASSERT(containerSet->contains(block)); - containerSet->remove(block); - if (containerSet->isEmpty()) - containerMap->remove(it); - } + if (!percentHeightDescendantsMap) + return; + std::unique_ptr<TrackedRendererListHashSet> descendantSet = percentHeightDescendantsMap->take(block); + if (!descendantSet) + return; + + for (auto* descendant : *descendantSet) { + auto it = percentHeightContainerMap->find(descendant); + ASSERT(it != percentHeightContainerMap->end()); + if (it == percentHeightContainerMap->end()) + continue; + auto* containerSet = it->value.get(); + ASSERT(containerSet->contains(block)); + containerSet->remove(block); + if (containerSet->isEmpty()) + percentHeightContainerMap->remove(it); } } @@ -216,10 +344,8 @@ RenderBlock::~RenderBlock() if (gRareDataMap) gRareDataMap->remove(this); - if (gPercentHeightDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap); - if (gPositionedDescendantsMap) - removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap); + removeBlockFromPercentageDescendantAndContainerMaps(this); + positionedDescendantsMap().removeContainingBlock(*this); } void RenderBlock::willBeDestroyed() @@ -244,14 +370,20 @@ void RenderBlock::removePositionedObjectsIfNeeded(const RenderStyle& oldStyle, c if (oldStyle.position() == newStyle.position() && hadTransform == willHaveTransform) return; - // We are no longer a containing block. + // We are no longer the containing block for fixed descendants. + if (hadTransform && !willHaveTransform) { + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. + removePositionedObjects(nullptr, NewContainingBlock); + return; + } + + // We are no longer the containing block for absolute positioned descendants. if (newStyle.position() == StaticPosition && !willHaveTransform) { - // Clear our positioned objects list. Our absolutely positioned descendants will be - // inserted into our containing block's positioned objects list during layout. + // Our positioned descendants will be inserted into a new containing block's positioned objects list during the next layout. removePositionedObjects(nullptr, NewContainingBlock); return; } - + // We are a new containing block. if (oldStyle.position() == StaticPosition && !hadTransform) { // Remove our absolutely positioned descendants from their current containing block. @@ -1157,10 +1289,10 @@ void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, R void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants() { - if (!gPercentHeightDescendantsMap) + if (!percentHeightDescendantsMap) return; - TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this); + TrackedRendererListHashSet* descendants = percentHeightDescendantsMap->get(this); if (!descendants) return; @@ -1264,34 +1396,33 @@ bool RenderBlock::simplifiedLayout() return true; } -void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject& child) +void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderBox& positionedChild) { - if (child.style().position() != FixedPosition) + if (positionedChild.style().position() != FixedPosition) return; - bool hasStaticBlockPosition = child.style().hasStaticBlockPosition(isHorizontalWritingMode()); - bool hasStaticInlinePosition = child.style().hasStaticInlinePosition(isHorizontalWritingMode()); + bool hasStaticBlockPosition = positionedChild.style().hasStaticBlockPosition(isHorizontalWritingMode()); + bool hasStaticInlinePosition = positionedChild.style().hasStaticInlinePosition(isHorizontalWritingMode()); if (!hasStaticBlockPosition && !hasStaticInlinePosition) return; - auto o = child.parent(); - while (o && !is<RenderView>(*o) && o->style().position() != AbsolutePosition) - o = o->parent(); - if (o->style().position() != AbsolutePosition) + auto* parent = positionedChild.parent(); + while (parent && !is<RenderView>(*parent) && parent->style().position() != AbsolutePosition) + parent = parent->parent(); + if (!parent || parent->style().position() != AbsolutePosition) return; - auto& box = downcast<RenderBox>(child); if (hasStaticInlinePosition) { LogicalExtentComputedValues computedValues; - box.computeLogicalWidthInRegion(computedValues); + positionedChild.computeLogicalWidthInRegion(computedValues); LayoutUnit newLeft = computedValues.m_position; - if (newLeft != box.logicalLeft()) - box.setChildNeedsLayout(MarkOnlyThis); + if (newLeft != positionedChild.logicalLeft()) + positionedChild.setChildNeedsLayout(MarkOnlyThis); } else if (hasStaticBlockPosition) { - LayoutUnit oldTop = box.logicalTop(); - box.updateLogicalHeight(); - if (box.logicalTop() != oldTop) - box.setChildNeedsLayout(MarkOnlyThis); + LayoutUnit oldTop = positionedChild.logicalTop(); + positionedChild.updateLogicalHeight(); + if (positionedChild.logicalTop() != oldTop) + positionedChild.setChildNeedsLayout(MarkOnlyThis); } } @@ -2049,6 +2180,8 @@ LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock& rootBlock, Layou ASSERT(currentCache); auto info = currentCache->containingBlockInfo(*cb); cb = info.block(); + if (!cb) + break; currentCache = info.cache(); } return logicalLeft; @@ -2071,6 +2204,8 @@ LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock& rootBlock, Layo ASSERT(currentCache); auto info = currentCache->containingBlockInfo(*cb); cb = info.block(); + if (!cb) + break; currentCache = info.cache(); } return logicalRight; @@ -2108,148 +2243,79 @@ RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) con return beforeBlock; } -void RenderBlock::insertIntoTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap, bool forceNewEntry) -{ - if (!descendantsMap) { - descendantsMap = new TrackedDescendantsMap; - containerMap = new TrackedContainerMap; - } - - TrackedRendererListHashSet* descendantSet = descendantsMap->get(this); - if (!descendantSet) { - descendantSet = new TrackedRendererListHashSet; - descendantsMap->set(this, std::unique_ptr<TrackedRendererListHashSet>(descendantSet)); - } - - if (forceNewEntry) { - descendantSet->remove(&descendant); - containerMap->remove(&descendant); - } - - bool added = descendantSet->add(&descendant).isNewEntry; - if (!added) { - ASSERT(containerMap->get(&descendant)); - ASSERT(containerMap->get(&descendant)->contains(this)); - return; - } - - HashSet<RenderBlock*>* containerSet = containerMap->get(&descendant); - if (!containerSet) { - containerSet = new HashSet<RenderBlock*>; - containerMap->set(&descendant, std::unique_ptr<HashSet<RenderBlock*>>(containerSet)); - } - ASSERT(!containerSet->contains(this)); - containerSet->add(this); -} - -void RenderBlock::removeFromTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap) -{ - if (!descendantsMap) - return; - - std::unique_ptr<HashSet<RenderBlock*>> containerSet = containerMap->take(&descendant); - if (!containerSet) - return; - - for (auto it = containerSet->begin(), end = containerSet->end(); it != end; ++it) { - RenderBlock* container = *it; - - // FIXME: Disabling this assert temporarily until we fix the layout - // bugs associated with positioned objects not properly cleared from - // their ancestor chain before being moved. See webkit bug 93766. - // ASSERT(descendant->isDescendantOf(container)); - - TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container); - ASSERT(descendantsMapIterator != descendantsMap->end()); - if (descendantsMapIterator == descendantsMap->end()) - continue; - TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get(); - ASSERT(descendantSet->contains(&descendant)); - descendantSet->remove(&descendant); - if (descendantSet->isEmpty()) - descendantsMap->remove(descendantsMapIterator); - } -} - TrackedRendererListHashSet* RenderBlock::positionedObjects() const { - if (gPositionedDescendantsMap) - return gPositionedDescendantsMap->get(this); - return nullptr; + return positionedDescendantsMap().positionedRenderers(*this); } -void RenderBlock::insertPositionedObject(RenderBox& o) +void RenderBlock::insertPositionedObject(RenderBox& positioned) { ASSERT(!isAnonymousBlock()); - if (o.isRenderFlowThread()) + if (positioned.isRenderFlowThread()) return; - - insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap, isRenderView()); + + positionedDescendantsMap().addDescendant(*this, positioned, isRenderView() ? PositionedDescendantsMap::MoveDescendantToEnd::Yes + : PositionedDescendantsMap::MoveDescendantToEnd::No); } -void RenderBlock::removePositionedObject(RenderBox& o) +void RenderBlock::removePositionedObject(const RenderBox& rendererToRemove) { - removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap); + positionedDescendantsMap().removeDescendant(rendererToRemove); } -void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState) +void RenderBlock::removePositionedObjects(const RenderBlock* newContainingBlockCandidate, ContainingBlockState containingBlockState) { - TrackedRendererListHashSet* positionedDescendants = positionedObjects(); + auto* positionedDescendants = positionedObjects(); if (!positionedDescendants) return; - Vector<RenderBox*, 16> deadObjects; - - for (auto it = positionedDescendants->begin(), end = positionedDescendants->end(); it != end; ++it) { - RenderBox* r = *it; - if (!o || r->isDescendantOf(o)) { - if (containingBlockState == NewContainingBlock) - r->setChildNeedsLayout(MarkOnlyThis); - - // It is parent blocks job to add positioned child to positioned objects list of its containing block - // Parent layout needs to be invalidated to ensure this happens. - RenderElement* p = r->parent(); - while (p && !p->isRenderBlock()) - p = p->parent(); - if (p) - p->setChildNeedsLayout(); - - deadObjects.append(r); - } + Vector<RenderBox*, 16> renderersToRemove; + for (auto* renderer : *positionedDescendants) { + if (newContainingBlockCandidate && !renderer->isDescendantOf(newContainingBlockCandidate)) + continue; + renderersToRemove.append(renderer); + if (containingBlockState == NewContainingBlock) + renderer->setChildNeedsLayout(MarkOnlyThis); + // It is the parent block's job to add positioned children to positioned objects list of its containing block. + // Dirty the parent to ensure this happens. + auto* parent = renderer->parent(); + while (parent && !parent->isRenderBlock()) + parent = parent->parent(); + if (parent) + parent->setChildNeedsLayout(); } - - for (unsigned i = 0; i < deadObjects.size(); i++) - removePositionedObject(*deadObjects.at(i)); + for (auto* renderer : renderersToRemove) + removePositionedObject(*renderer); } void RenderBlock::addPercentHeightDescendant(RenderBox& descendant) { - insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); + insertIntoTrackedRendererMaps(*this, descendant); } void RenderBlock::removePercentHeightDescendant(RenderBox& descendant) { - removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); + removeFromTrackedRendererMaps(descendant); } TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const { - return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; + return percentHeightDescendantsMap ? percentHeightDescendantsMap->get(this) : nullptr; } bool RenderBlock::hasPercentHeightContainerMap() { - return gPercentHeightContainerMap; + return percentHeightContainerMap; } bool RenderBlock::hasPercentHeightDescendant(RenderBox& descendant) { - // We don't null check gPercentHeightContainerMap since the caller + // We don't null check percentHeightContainerMap since the caller // already ensures this and we need to call this function on every // descendant in clearPercentHeightDescendantsFrom(). - ASSERT(gPercentHeightContainerMap); - return gPercentHeightContainerMap->contains(&descendant); + ASSERT(percentHeightContainerMap); + return percentHeightContainerMap->contains(&descendant); } void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox& descendant) @@ -2268,7 +2334,7 @@ void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox& descendant) void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox& parent) { - ASSERT(gPercentHeightContainerMap); + ASSERT(percentHeightContainerMap); for (RenderObject* child = parent.firstChild(); child; child = child->nextInPreOrder(&parent)) { if (!is<RenderBox>(*child)) continue; @@ -3768,17 +3834,12 @@ RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const Rend #ifndef NDEBUG void RenderBlock::checkPositionedObjectsNeedLayout() { - if (!gPositionedDescendantsMap) - return; - - TrackedRendererListHashSet* positionedDescendantSet = positionedObjects(); - if (!positionedDescendantSet) + auto* positionedDescendants = positionedObjects(); + if (!positionedDescendants) return; - for (auto it = positionedDescendantSet->begin(), end = positionedDescendantSet->end(); it != end; ++it) { - RenderBox* currBox = *it; - ASSERT(!currBox->needsLayout()); - } + for (auto* renderer : *positionedDescendants) + ASSERT(!renderer->needsLayout()); } #endif diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index bb618e486..49468c586 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -42,8 +42,6 @@ struct BidiRun; struct PaintInfo; typedef WTF::ListHashSet<RenderBox*> TrackedRendererListHashSet; -typedef WTF::HashMap<const RenderBlock*, std::unique_ptr<TrackedRendererListHashSet>> TrackedDescendantsMap; -typedef WTF::HashMap<const RenderBox*, std::unique_ptr<HashSet<RenderBlock*>>> TrackedContainerMap; enum CaretType { CursorCaret, DragCaret }; enum ContainingBlockState { NewContainingBlock, SameContainingBlock }; @@ -83,8 +81,8 @@ public: virtual void invalidateLineLayoutPath() { } void insertPositionedObject(RenderBox&); - static void removePositionedObject(RenderBox&); - void removePositionedObjects(RenderBlock*, ContainingBlockState = SameContainingBlock); + static void removePositionedObject(const RenderBox&); + void removePositionedObjects(const RenderBlock*, ContainingBlockState = SameContainingBlock); TrackedRendererListHashSet* positionedObjects() const; bool hasPositionedObjects() const @@ -316,7 +314,7 @@ protected: void layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly = false); virtual void layoutPositionedObject(RenderBox&, bool relayoutChildren, bool fixedPositionObjectsOnly); - void markFixedPositionObjectForLayoutIfNeeded(RenderObject& child); + void markFixedPositionObjectForLayoutIfNeeded(RenderBox& child); LayoutUnit marginIntrinsicLogicalWidthForChild(RenderBox&) const; @@ -417,12 +415,6 @@ private: virtual bool isSelfCollapsingBlock() const override; virtual bool childrenPreventSelfCollapsing() const; - // FIXME-BLOCKFLOW: Remove virtualizaion when all callers have moved to RenderBlockFlow - virtual bool hasLines() const { return false; } - - void insertIntoTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*&, TrackedContainerMap*&, bool forceNewEntry = false); - static void removeFromTrackedRendererMaps(RenderBox& descendant, TrackedDescendantsMap*&, TrackedContainerMap*&); - void createFirstLetterRenderer(RenderElement* firstLetterBlock, RenderText* currentTextChild); void updateFirstLetterStyle(RenderElement* firstLetterBlock, RenderObject* firstLetterContainer); diff --git a/Source/WebCore/rendering/RenderBlockFlow.cpp b/Source/WebCore/rendering/RenderBlockFlow.cpp index 33bce4025..53ff0b6c7 100644 --- a/Source/WebCore/rendering/RenderBlockFlow.cpp +++ b/Source/WebCore/rendering/RenderBlockFlow.cpp @@ -1648,7 +1648,15 @@ static inline bool needsAppleMailPaginationQuirk(RootInlineBox& lineBox) return false; } - + +static void clearShouldBreakAtLineToAvoidWidowIfNeeded(RenderBlockFlow& blockFlow) +{ + if (!blockFlow.shouldBreakAtLineToAvoidWidow()) + return; + blockFlow.clearShouldBreakAtLineToAvoidWidow(); + blockFlow.setDidBreakAtLineToAvoidWidow(); +} + void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, bool& overflowsRegion, RenderFlowThread* flowThread) { // FIXME: Ignore anonymous inline blocks. Handle the delta already having been set because of @@ -1702,8 +1710,11 @@ void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, La logicalBottom = intMinForLayoutUnit; lineBox->computeReplacedAndTextLineTopAndBottom(logicalOffset, logicalBottom); lineHeight = logicalBottom - logicalOffset; - if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) - return; // Give up. We're genuinely too big even after excluding blank space and overflow. + if (logicalOffset == intMaxForLayoutUnit || lineHeight > pageLogicalHeight) { + // Give up. We're genuinely too big even after excluding blank space and overflow. + clearShouldBreakAtLineToAvoidWidowIfNeeded(*this); + return; + } pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); } @@ -1712,10 +1723,8 @@ void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, La int lineIndex = lineCount(lineBox); if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) { - if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) { - clearShouldBreakAtLineToAvoidWidow(); - setDidBreakAtLineToAvoidWidow(); - } + if (lineBreakToAvoidWidow() == lineIndex) + clearShouldBreakAtLineToAvoidWidowIfNeeded(*this); // If we have a non-uniform page height, then we have to shift further possibly. if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight)) return; @@ -3528,7 +3537,8 @@ bool RenderBlockFlow::relayoutForPagination(LayoutStateMaintainer& statePusher) bool RenderBlockFlow::hasLines() const { - ASSERT(childrenInline()); + if (!childrenInline()) + return false; if (auto simpleLineLayout = this->simpleLineLayout()) return simpleLineLayout->lineCount(); diff --git a/Source/WebCore/rendering/RenderBlockFlow.h b/Source/WebCore/rendering/RenderBlockFlow.h index 3b9d81268..84766c45b 100644 --- a/Source/WebCore/rendering/RenderBlockFlow.h +++ b/Source/WebCore/rendering/RenderBlockFlow.h @@ -345,8 +345,8 @@ public: RootInlineBox* firstRootBox() const { return downcast<RootInlineBox>(m_lineBoxes.firstLineBox()); } RootInlineBox* lastRootBox() const { return downcast<RootInlineBox>(m_lineBoxes.lastLineBox()); } - virtual bool hasLines() const override final; - virtual void invalidateLineLayoutPath() override final; + bool hasLines() const; + void invalidateLineLayoutPath() final; enum LineLayoutPath { UndeterminedPath = 0, SimpleLinesPath, LineBoxesPath, ForceLineBoxesPath }; LineLayoutPath lineLayoutPath() const { return static_cast<LineLayoutPath>(renderBlockFlowLineLayoutPath()); } diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 451de09c9..d67c38daa 100644 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -2250,6 +2250,10 @@ void RenderBlockFlow::marginCollapseLinesFromStart(LineLayoutState& layoutState, if (!stopLine->hasAnonymousInlineBlock()) return; + // We already handled top of block with startLine. + if (stopLine == firstRootBox()) + return; + // Re-run margin collapsing on the block sequence that stopLine is a part of. // First go backwards to get the entire sequence. RootInlineBox* prev = stopLine; diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index c437851c0..e4809d288 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -120,18 +120,12 @@ static bool skipBodyBackground(const RenderBox* bodyElementRenderer) RenderBox::RenderBox(Element& element, Ref<RenderStyle>&& style, BaseTypeFlags baseTypeFlags) : RenderBoxModelObject(element, WTFMove(style), baseTypeFlags) - , m_minPreferredLogicalWidth(-1) - , m_maxPreferredLogicalWidth(-1) - , m_inlineBoxWrapper(nullptr) { setIsBox(); } RenderBox::RenderBox(Document& document, Ref<RenderStyle>&& style, BaseTypeFlags baseTypeFlags) : RenderBoxModelObject(document, WTFMove(style), baseTypeFlags) - , m_minPreferredLogicalWidth(-1) - , m_maxPreferredLogicalWidth(-1) - , m_inlineBoxWrapper(nullptr) { setIsBox(); } @@ -516,17 +510,19 @@ void RenderBox::updateFromStyle() boxHasOverflowClip = false; } } - // Check for overflow clip. // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value. if (boxHasOverflowClip) { - if (!s_hadOverflowClip) - // Erase the overflow - repaint(); + if (!s_hadOverflowClip && hasRenderOverflow()) { + // Erase the overflow. + // Overflow changes have to result in immediate repaints of the entire layout overflow area because + // repaints issued by removal of descendants get clipped using the updated style when they shouldn't. + repaintRectangle(visualOverflowRect()); + repaintRectangle(layoutOverflowRect()); + } setHasOverflowClip(); } } - setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty()); setHasReflection(styleToUse.boxReflect()); } @@ -2121,13 +2117,14 @@ std::unique_ptr<InlineElementBox> RenderBox::createInlineBox() void RenderBox::dirtyLineBoxes(bool fullLayout) { - if (m_inlineBoxWrapper) { - if (fullLayout) { - delete m_inlineBoxWrapper; - m_inlineBoxWrapper = nullptr; - } else - m_inlineBoxWrapper->dirtyLineBoxes(); - } + if (!m_inlineBoxWrapper) + return; + + if (fullLayout) { + delete m_inlineBoxWrapper; + m_inlineBoxWrapper = nullptr; + } else + m_inlineBoxWrapper->dirtyLineBoxes(); } void RenderBox::positionLineBox(InlineElementBox& box) @@ -2163,12 +2160,13 @@ void RenderBox::positionLineBox(InlineElementBox& box) void RenderBox::deleteLineBoxWrapper() { - if (m_inlineBoxWrapper) { - if (!documentBeingDestroyed()) - m_inlineBoxWrapper->removeFromParent(); - delete m_inlineBoxWrapper; - m_inlineBoxWrapper = nullptr; - } + if (!m_inlineBoxWrapper) + return; + + if (!documentBeingDestroyed()) + m_inlineBoxWrapper->removeFromParent(); + delete m_inlineBoxWrapper; + m_inlineBoxWrapper = nullptr; } LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 508ba3d28..8e63a2c82 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -740,7 +740,7 @@ protected: LayoutUnit m_maxPreferredLogicalWidth; // For inline replaced elements, the inline box that owns us. - InlineElementBox* m_inlineBoxWrapper; + InlineElementBox* m_inlineBoxWrapper { nullptr }; // Our overflow information. RefPtr<RenderOverflow> m_overflow; diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 98e9f2d06..5b0a83de7 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -363,7 +363,7 @@ LayoutUnit RenderFlexibleBox::clientLogicalBottomAfterRepositioning() return std::max(clientLogicalBottom(), maxChildLogicalBottom); } -bool RenderFlexibleBox::hasOrthogonalFlow(RenderBox& child) const +bool RenderFlexibleBox::hasOrthogonalFlow(const RenderBox& child) const { // FIXME: If the child is a flexbox, then we need to check isHorizontalFlow. return isHorizontalFlow() != child.isHorizontalWritingMode(); @@ -450,14 +450,14 @@ LayoutUnit RenderFlexibleBox::mainAxisContentExtent(LayoutUnit contentLogicalHei return contentLogicalWidth(); } -Optional<LayoutUnit> RenderFlexibleBox::computeMainAxisExtentForChild(RenderBox& child, SizeType sizeType, const Length& size) +Optional<LayoutUnit> RenderFlexibleBox::computeMainAxisExtentForChild(const RenderBox& child, SizeType sizeType, const Length& size) { // FIXME: This is wrong for orthogonal flows. It should use the flexbox's writing-mode, not the child's in order // to figure out the logical height/width. if (isColumnFlow()) { // We don't have to check for "auto" here - computeContentLogicalHeight will just return Nullopt for that case anyway. if (size.isIntrinsic()) - child.layoutIfNeeded(); + const_cast<RenderBox&>(child).layoutIfNeeded(); // FIXME: Should not need to do a layout here. return child.computeContentLogicalHeight(sizeType, size, child.logicalHeight() - child.borderAndPaddingLogicalHeight()); } // FIXME: Figure out how this should work for regions and pass in the appropriate values. @@ -648,15 +648,14 @@ LayoutUnit RenderFlexibleBox::mainAxisBorderAndPaddingExtentForChild(RenderBox& { return isHorizontalFlow() ? child.horizontalBorderAndPaddingExtent() : child.verticalBorderAndPaddingExtent(); } - -bool RenderFlexibleBox::mainAxisExtentIsDefinite() const -{ - return isColumnFlow() ? hasDefiniteLogicalHeight() : hasDefiniteLogicalWidth(); -} - -bool RenderFlexibleBox::mainAxisLengthIsIndefinite(const Length& flexBasis) const + +bool RenderFlexibleBox::mainAxisLengthIsDefinite(const RenderBox& child, const Length& flexBasis) const { - return flexBasis.isAuto() || (flexBasis.isPercentOrCalculated() && !mainAxisExtentIsDefinite()); + if (flexBasis.isAuto()) + return false; + if (flexBasis.isPercentOrCalculated()) + return isColumnFlow() ? bool(child.computePercentageLogicalHeight(flexBasis)) : hasDefiniteLogicalWidth(); + return true; } LayoutUnit RenderFlexibleBox::mainAxisScrollbarExtentForChild(RenderBox& child) const @@ -855,7 +854,72 @@ void RenderFlexibleBox::prepareOrderIteratorAndMargins() } } -LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, LayoutUnit childSize) +bool RenderFlexibleBox::crossAxisLengthIsDefinite(const RenderBox& child, const Length& length) const +{ + if (length.isAuto()) + return false; + if (length.isPercentOrCalculated()) + return hasOrthogonalFlow(child) ? hasDefiniteLogicalWidth() : bool(child.computePercentageLogicalHeight(length)); + return length.isFixed(); +} + + +Optional<LayoutUnit> RenderFlexibleBox::computeMainSizeFromAspectRatioUsing(const RenderBox& child, Length crossSizeLength) const +{ + ASSERT(child.hasAspectRatio()); + ASSERT(child.intrinsicSize().height() > 0); + + Optional<LayoutUnit> crossSize; + if (crossSizeLength.isFixed()) + crossSize = LayoutUnit(crossSizeLength.value()); + else { + ASSERT(crossSizeLength.isPercentOrCalculated()); + crossSize = hasOrthogonalFlow(child) ? + adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(crossSizeLength, contentWidth())) : + child.computePercentageLogicalHeight(crossSizeLength); + } + + if (!crossSize) + return crossSize; + + const LayoutSize& childIntrinsicSize = child.intrinsicSize(); + double ratio = childIntrinsicSize.width().toFloat() / childIntrinsicSize.height().toFloat(); + if (isHorizontalFlow()) + return LayoutUnit(crossSize.value() * ratio); + return LayoutUnit(crossSize.value() / ratio); +} + +LayoutUnit RenderFlexibleBox::adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox& child, LayoutUnit childSize) +{ + Length crossMin = isHorizontalFlow() ? child.style().minHeight() : child.style().minWidth(); + Length crossMax = isHorizontalFlow() ? child.style().maxHeight() : child.style().maxWidth(); + + if (crossAxisLengthIsDefinite(child, crossMax)) { + Optional<LayoutUnit> maxValue = computeMainSizeFromAspectRatioUsing(child, crossMax); + if (maxValue) + childSize = std::min(maxValue.value(), childSize); + } + + if (crossAxisLengthIsDefinite(child, crossMin)) { + Optional<LayoutUnit> minValue = computeMainSizeFromAspectRatioUsing(child, crossMin); + if (minValue) + childSize = std::max(minValue.value(), childSize); + } + + return childSize; +} + +bool RenderFlexibleBox::useChildAspectRatio(const RenderBox& child) const +{ + if (!child.hasAspectRatio()) + return false; + if (!child.intrinsicSize().height()) + return false; + Length crossSize = isHorizontalFlow() ? child.style().height() : child.style().width(); + return crossAxisLengthIsDefinite(child, crossSize); +} + +LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(const RenderBox& child, LayoutUnit childSize) { Length max = isHorizontalFlow() ? child.style().maxWidth() : child.style().maxHeight(); Optional<LayoutUnit> maxExtent = Nullopt; @@ -863,26 +927,36 @@ LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox& child, Layo maxExtent = computeMainAxisExtentForChild(child, MaxSize, max); childSize = std::min(childSize, maxExtent.valueOr(childSize)); } - + Length min = isHorizontalFlow() ? child.style().minWidth() : child.style().minHeight(); if (min.isSpecifiedOrIntrinsic()) return std::max(childSize, computeMainAxisExtentForChild(child, MinSize, min).valueOr(childSize)); - - if (!isFlexibleBoxImpl() && min.isAuto() && mainAxisOverflowForChild(child) == OVISIBLE) { + + if (!isFlexibleBoxImpl() && min.isAuto() && mainAxisOverflowForChild(child) == OVISIBLE && !(isColumnFlow() && is<RenderFlexibleBox>(child))) { // This is the implementation of CSS flexbox section 4.5 which defines the minimum size of "pure" flex // items. For any other item the value should be 0, this also includes RenderFlexibleBox's derived clases // (RenderButton, RenderFullScreen...) because that's just an implementation detail. + // FIXME: For now we don't handle nested column flexboxes. Need to implement better intrinsic + // size handling from the flex box spec first (4.5). LayoutUnit contentSize = computeMainAxisExtentForChild(child, MinSize, Length(MinContent)).value(); ASSERT(contentSize >= 0); + if (child.hasAspectRatio() && child.intrinsicSize().height() > 0) + contentSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, contentSize); contentSize = std::min(contentSize, maxExtent.valueOr(contentSize)); - + Length mainSize = isHorizontalFlow() ? child.style().width() : child.style().height(); - if (!mainAxisLengthIsIndefinite(mainSize)) { + if (mainAxisLengthIsDefinite(child, mainSize)) { LayoutUnit resolvedMainSize = computeMainAxisExtentForChild(child, MainOrPreferredSize, mainSize).value(); ASSERT(resolvedMainSize >= 0); LayoutUnit specifiedSize = std::min(resolvedMainSize, maxExtent.valueOr(resolvedMainSize)); - return std::max(childSize, std::min(specifiedSize, contentSize)); + } else if (useChildAspectRatio(child)) { + Length crossSizeLength = isHorizontalFlow() ? child.style().height() : child.style().width(); + Optional<LayoutUnit> transferredSize = computeMainSizeFromAspectRatioUsing(child, crossSizeLength); + if (transferredSize) { + transferredSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, transferredSize.value()); + return std::max(childSize, std::min(transferredSize.value(), contentSize)); + } } return std::max(childSize, contentSize); } @@ -1085,7 +1159,7 @@ void RenderFlexibleBox::resetAutoMarginsAndLogicalTopInCrossAxis(RenderBox& chil child.updateLogicalHeight(); } -EOverflow RenderFlexibleBox::mainAxisOverflowForChild(RenderBox& child) const +EOverflow RenderFlexibleBox::mainAxisOverflowForChild(const RenderBox& child) const { if (isHorizontalFlow()) return child.style().overflowX(); diff --git a/Source/WebCore/rendering/RenderFlexibleBox.h b/Source/WebCore/rendering/RenderFlexibleBox.h index 9bae316aa..f2e5d1760 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.h +++ b/Source/WebCore/rendering/RenderFlexibleBox.h @@ -85,8 +85,8 @@ private: // Use an inline capacity of 8, since flexbox containers usually have less than 8 children. typedef Vector<LayoutRect, 8> ChildFrameRects; - virtual bool isFlexibleBox() const override final { return true; } - bool hasOrthogonalFlow(RenderBox& child) const; + bool isFlexibleBox() const final { return true; } + bool hasOrthogonalFlow(const RenderBox& child) const; bool isColumnFlow() const; bool isLeftToRightFlow() const; bool isMultiline() const; @@ -98,7 +98,7 @@ private: LayoutUnit mainAxisExtent() const; LayoutUnit crossAxisContentExtent() const; LayoutUnit mainAxisContentExtent(LayoutUnit contentLogicalHeight); - Optional<LayoutUnit> computeMainAxisExtentForChild(RenderBox& child, SizeType, const Length& size); + Optional<LayoutUnit> computeMainAxisExtentForChild(const RenderBox& child, SizeType, const Length& size); WritingMode transformedWritingMode() const; LayoutUnit flowAwareBorderStart() const; LayoutUnit flowAwareBorderEnd() const; @@ -122,7 +122,7 @@ private: LayoutUnit mainAxisBorderAndPaddingExtentForChild(RenderBox& child) const; LayoutUnit mainAxisScrollbarExtentForChild(RenderBox& child) const; LayoutUnit preferredMainAxisContentExtentForChild(RenderBox& child, bool hasInfiniteLineLength); - EOverflow mainAxisOverflowForChild(RenderBox&) const; + EOverflow mainAxisOverflowForChild(const RenderBox&) const; void layoutFlexItems(bool relayoutChildren, Vector<LineContext>&); LayoutUnit autoMarginOffsetInMainAxis(const OrderedFlexItemList&, LayoutUnit& availableFreeSpace); @@ -139,7 +139,8 @@ private: LayoutUnit computeChildMarginValue(const Length& margin); void prepareOrderIteratorAndMargins(); - LayoutUnit adjustChildSizeForMinAndMax(RenderBox&, LayoutUnit childSize); + LayoutUnit adjustChildSizeForMinAndMax(const RenderBox&, LayoutUnit childSize); + LayoutUnit adjustChildSizeForAspectRatioCrossAxisMinAndMax(const RenderBox&, LayoutUnit childSize); bool computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, double& totalFlexGrow, double& totalWeightedFlexShrink, LayoutUnit& minMaxAppliedMainAxisExtent, bool& hasInfiniteLineLength); bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, double& totalFlexGrow, double& totalWeightedFlexShrink, InflexibleFlexItemSize&, Vector<LayoutUnit>& childSizes, bool hasInfiniteLineLength); @@ -158,9 +159,11 @@ private: void flipForRightToLeftColumn(); void flipForWrapReverse(const Vector<LineContext>&, LayoutUnit crossAxisStartEdge); - bool mainAxisExtentIsDefinite() const; - bool mainAxisLengthIsIndefinite(const Length& flexBasis) const; - + bool mainAxisLengthIsDefinite(const RenderBox&, const Length&) const; + bool crossAxisLengthIsDefinite(const RenderBox&, const Length&) const; + bool useChildAspectRatio(const RenderBox&) const; + Optional<LayoutUnit> computeMainSizeFromAspectRatioUsing(const RenderBox& child, Length crossSizeLength) const; + virtual bool isFlexibleBoxImpl() const { return false; }; mutable OrderIterator m_orderIterator; diff --git a/Source/WebCore/rendering/RenderHTMLCanvas.cpp b/Source/WebCore/rendering/RenderHTMLCanvas.cpp index f2de75d52..199f903b4 100644 --- a/Source/WebCore/rendering/RenderHTMLCanvas.cpp +++ b/Source/WebCore/rendering/RenderHTMLCanvas.cpp @@ -101,18 +101,7 @@ void RenderHTMLCanvas::canvasSizeChanged() if (!parent()) return; - - if (!preferredLogicalWidthsDirty()) - setPreferredLogicalWidthsDirty(true); - - LayoutSize oldSize = size(); - updateLogicalWidth(); - updateLogicalHeight(); - if (oldSize == size()) - return; - - if (!selfNeedsLayout()) - setNeedsLayout(); + setNeedsLayoutIfNeededAfterIntrinsicSizeChange(); } } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index d8ee8150b..00d907829 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -294,29 +294,8 @@ void RenderImage::repaintOrMarkForLayout(ImageSizeChangeType imageSizeChange, co bool imageSourceHasChangedSize = oldIntrinsicSize != newIntrinsicSize || imageSizeChange != ImageSizeChangeNone; - if (imageSourceHasChangedSize) { - setPreferredLogicalWidthsDirty(true); - - // 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().isPercentOrCalculated() - || style().logicalMaxWidth().isPercentOrCalculated() - || style().logicalMinWidth().isPercentOrCalculated(); - - bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; - - if (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { - // FIXME: It's not clear that triggering a layout guarantees a repaint in all cases. - // But many callers do depend on this code causing a layout. - setNeedsLayout(); - return; - } - } + if (imageSourceHasChangedSize && setNeedsLayoutIfNeededAfterIntrinsicSizeChange()) + return; if (everHadLayout() && !selfNeedsLayout()) { // The inner content rectangle is calculated during layout, but may need an update now @@ -574,6 +553,11 @@ bool RenderImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, ObjectFit objectFit = style().objectFit(); if (objectFit != ObjectFitFill && objectFit != ObjectFitCover) return false; + + LengthPoint objectPosition = style().objectPosition(); + if (objectPosition != RenderStyle::initialObjectPosition()) + return false; + // Check for image with alpha. return imageResource().cachedImage() && imageResource().cachedImage()->currentFrameKnownToBeOpaque(this); } diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 3125c62f6..749099044 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -1206,7 +1206,7 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBoxInRegion(const RenderRegi LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { // Only first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints. - ASSERT(!view().layoutStateEnabled() || style().styleType() == FIRST_LETTER); + ASSERT(!view().layoutStateEnabled() || style().styleType() == FIRST_LETTER || hasSelfPaintingLayer()); if (!firstLineBoxIncludingCulling() && !continuation()) return LayoutRect(); @@ -1807,8 +1807,7 @@ void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) if (!container) container = this; - region.clip = region.bounds; - container->computeAbsoluteRepaintRect(region.clip); + region.clip = container->computeAbsoluteRepaintRect(region.bounds); if (region.clip.height() < 0) { region.clip.setHeight(0); region.clip.setWidth(0); diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index d0cba5316..dae97f749 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -1805,15 +1805,15 @@ void RenderLayer::beginTransparencyLayers(GraphicsContext& context, const LayerP context.clip(pixelSnappedClipRect); #if ENABLE(CSS_COMPOSITING) - // RenderSVGRoot takes care of its blend mode. - if (!renderer().isSVGRoot() && hasBlendMode()) + bool usesCompositeOperation = hasBlendMode() && !(renderer().isSVGRoot() && parent() && parent()->isRootLayer()); + if (usesCompositeOperation) context.setCompositeOperation(context.compositeOperation(), blendMode()); #endif context.beginTransparencyLayer(renderer().opacity()); #if ENABLE(CSS_COMPOSITING) - if (!renderer().isSVGRoot() && hasBlendMode()) + if (usesCompositeOperation) context.setCompositeOperation(context.compositeOperation(), BlendModeNormal); #endif @@ -6423,6 +6423,19 @@ void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObje } } +static bool mayCreateGraphicalGroup(const RenderElement& renderer) +{ + bool createsGraphicalGroup = renderer.hasClipPath() + || renderer.hasFilter() + || renderer.hasBackdropFilter() +#if ENABLE(CSS_COMPOSITING) + || renderer.hasBlendMode() +#endif + || renderer.isTransparent() + || renderer.hasMask(); + return createsGraphicalGroup || (renderer.style().willChange() && renderer.style().willChange()->canCreateGraphicalGroup()); +} + bool RenderLayer::shouldBeNormalFlowOnly() const { return (renderer().hasOverflowClip() @@ -6434,20 +6447,14 @@ bool RenderLayer::shouldBeNormalFlowOnly() const || renderer().isRenderIFrame() || (renderer().style().specifiesColumns() && !isRootLayer()) || renderer().isInFlowRenderFlowThread()) - && !renderer().isPositioned() && !renderer().hasTransformRelatedProperty() - && !renderer().hasClipPath() - && !renderer().hasFilter() - && !renderer().hasBackdropFilter() + && !renderer().isPositioned() + && !needsCompositedScrolling() + && !renderer().style().hasFlowFrom() #if PLATFORM(IOS) && !hasAcceleratedTouchScrolling() #endif -#if ENABLE(CSS_COMPOSITING) - && !renderer().hasBlendMode() -#endif - && !isTransparent() - && !needsCompositedScrolling() - && !renderer().style().hasFlowFrom(); + && !mayCreateGraphicalGroup(renderer()); } bool RenderLayer::shouldBeSelfPaintingLayer() const diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index edb4f3398..df2cd277d 100644 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -1924,8 +1924,7 @@ void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value()); region.type = styleRegion.type; - region.clip = region.bounds; - computeAbsoluteRepaintRect(region.clip); + region.clip = computeAbsoluteRepaintRect(region.bounds); if (region.clip.height() < 0) { region.clip.setHeight(0); region.clip.setWidth(0); diff --git a/Source/WebCore/rendering/RenderReplaced.cpp b/Source/WebCore/rendering/RenderReplaced.cpp index a818ad0fa..6b36b13e3 100644 --- a/Source/WebCore/rendering/RenderReplaced.cpp +++ b/Source/WebCore/rendering/RenderReplaced.cpp @@ -287,6 +287,31 @@ bool RenderReplaced::hasReplacedLogicalHeight() const return false; } +bool RenderReplaced::setNeedsLayoutIfNeededAfterIntrinsicSizeChange() +{ + setPreferredLogicalWidthsDirty(true); + + // 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().isPercentOrCalculated() + || style().logicalMaxWidth().isPercentOrCalculated() + || style().logicalMinWidth().isPercentOrCalculated(); + + bool layoutSizeDependsOnIntrinsicSize = style().aspectRatioType() == AspectRatioFromIntrinsic; + + if (!imageSizeIsConstrained || containingBlockNeedsToRecomputePreferredSize || layoutSizeDependsOnIntrinsicSize) { + setNeedsLayout(); + return true; + } + + return false; +} + void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio) const { FloatSize intrinsicSize; @@ -338,8 +363,6 @@ LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) return contentRect; ObjectFit objectFit = style().objectFit(); - if (objectFit == ObjectFitFill) - return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { @@ -354,13 +377,14 @@ LayoutRect RenderReplaced::replacedContentRect(const LayoutSize& intrinsicSize) finalRect.setSize(intrinsicSize); break; case ObjectFitFill: - ASSERT_NOT_REACHED(); + break; } - // FIXME: This is where object-position should be taken into account, but since it's not - // implemented yet, assume the initial value of "50% 50%". - LayoutUnit xOffset = (contentRect.width() - finalRect.width()) / 2; - LayoutUnit yOffset = (contentRect.height() - finalRect.height()) / 2; + LengthPoint objectPosition = style().objectPosition(); + + LayoutUnit xOffset = minimumValueForLength(objectPosition.x(), contentRect.width() - finalRect.width()); + LayoutUnit yOffset = minimumValueForLength(objectPosition.y(), contentRect.height() - finalRect.height()); + finalRect.move(xOffset, yOffset); return finalRect; diff --git a/Source/WebCore/rendering/RenderReplaced.h b/Source/WebCore/rendering/RenderReplaced.h index 9f7dfc571..72dbb81d1 100644 --- a/Source/WebCore/rendering/RenderReplaced.h +++ b/Source/WebCore/rendering/RenderReplaced.h @@ -37,6 +37,7 @@ public: bool hasReplacedLogicalWidth() const; bool hasReplacedLogicalHeight() const; + bool setNeedsLayoutIfNeededAfterIntrinsicSizeChange(); protected: RenderReplaced(Element&, Ref<RenderStyle>&&); diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index 05325314a..b3be2de98 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -300,6 +300,13 @@ void RenderTable::updateLogicalWidth() // Ensure we aren't bigger than our available width. setLogicalWidth(std::min(availableContentLogicalWidth, maxPreferredLogicalWidth())); + LayoutUnit maxWidth = maxPreferredLogicalWidth(); + // scaledWidthFromPercentColumns depends on m_layoutStruct in TableLayoutAlgorithmAuto, which + // maxPreferredLogicalWidth fills in. So scaledWidthFromPercentColumns has to be called after + // maxPreferredLogicalWidth. + LayoutUnit scaledWidth = m_tableLayout->scaledWidthFromPercentColumns() + bordersPaddingAndSpacingInRowDirection(); + maxWidth = std::max(scaledWidth, maxWidth); + setLogicalWidth(std::min(availableContentLogicalWidth, maxWidth)); } // Ensure we aren't smaller than our min preferred width. diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index efd90c18c..35e5e0b88 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -404,6 +404,13 @@ LayoutUnit RenderTableCell::cellBaselinePosition() const return firstLineBaseline().valueOr(borderAndPaddingBefore() + contentLogicalHeight()); } +static inline void markCellDirtyWhenCollapsedBorderChanges(RenderTableCell* cell) +{ + if (!cell) + return; + cell->setNeedsLayoutAndPrefWidthsRecalc(); +} + void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { ASSERT(style().display() == TABLE_CELL); @@ -422,8 +429,15 @@ void RenderTableCell::styleDidChange(StyleDifference diff, const RenderStyle* ol // If border was changed, notify table. RenderTable* table = this->table(); - if (table && oldStyle && oldStyle->border() != style().border()) + if (table && oldStyle && oldStyle->border() != style().border()) { table->invalidateCollapsedBorders(this); + if (table->collapseBorders() && diff == StyleDifferenceLayout) { + markCellDirtyWhenCollapsedBorderChanges(table->cellBelow(this)); + markCellDirtyWhenCollapsedBorderChanges(table->cellAbove(this)); + markCellDirtyWhenCollapsedBorderChanges(table->cellBefore(this)); + markCellDirtyWhenCollapsedBorderChanges(table->cellAfter(this)); + } + } } // The following rules apply for resolving conflicts and figuring out which border diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h index bd69f09e3..17a0171a0 100644 --- a/Source/WebCore/rendering/RenderTableCell.h +++ b/Source/WebCore/rendering/RenderTableCell.h @@ -284,6 +284,8 @@ inline LayoutUnit RenderTableCell::logicalHeightForRowSizing() const { // FIXME: This function does too much work, and is very hot during table layout! LayoutUnit adjustedLogicalHeight = logicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter()); + if (!style().logicalHeight().isSpecified()) + return adjustedLogicalHeight; LayoutUnit styleLogicalHeight = valueForLength(style().logicalHeight(), 0); // In strict mode, box-sizing: content-box do the right thing and actually add in the border and padding. // Call computedCSSPadding* directly to avoid including implicitPadding. diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 1907657e9..7f9100b6e 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -251,6 +251,15 @@ void RenderTableSection::addCell(RenderTableCell* cell, RenderTableRow* row) cell->setCol(table()->effColToCol(col)); } +static LayoutUnit resolveLogicalHeightForRow(const Length& rowLogicalHeight) +{ + if (rowLogicalHeight.isFixed()) + return rowLogicalHeight.value(); + if (rowLogicalHeight.isCalculated()) + return rowLogicalHeight.nonNanCalculatedValue(0); + return 0; +} + LayoutUnit RenderTableSection::calcRowLogicalHeight() { #ifndef NDEBUG @@ -278,7 +287,7 @@ LayoutUnit RenderTableSection::calcRowLogicalHeight() LayoutUnit baselineDescent = 0; // Our base size is the biggest logical height from our cells' styles (excluding row spanning cells). - m_rowPos[r + 1] = std::max(m_rowPos[r] + minimumValueForLength(m_grid[r].logicalHeight, 0), LayoutUnit::fromPixel(0)); + m_rowPos[r + 1] = std::max(m_rowPos[r] + resolveLogicalHeightForRow(m_grid[r].logicalHeight), LayoutUnit::fromPixel(0)); Row& row = m_grid[r].row; unsigned totalCols = row.size(); @@ -372,6 +381,7 @@ void RenderTableSection::layout() ASSERT(!needsCellRecalc()); ASSERT(!table()->needsSectionRecalc()); + m_forceSlowPaintPathWithOverflowingCell = false; // addChild may over-grow m_grid but we don't want to throw away the memory too early as addChild // can be called in a loop (e.g during parsing). Doing it now ensures we have a stable-enough structure. m_grid.shrinkToFit(); diff --git a/Source/WebCore/rendering/TableLayout.h b/Source/WebCore/rendering/TableLayout.h index 23169aa65..6c0b32d24 100644 --- a/Source/WebCore/rendering/TableLayout.h +++ b/Source/WebCore/rendering/TableLayout.h @@ -21,6 +21,7 @@ #ifndef TableLayout_h #define TableLayout_h +#include "LayoutUnit.h" #include <wtf/FastMalloc.h> #include <wtf/Noncopyable.h> @@ -39,6 +40,7 @@ public: virtual ~TableLayout() { } virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) = 0; + virtual LayoutUnit scaledWidthFromPercentColumns() const { return LayoutUnit(0); } virtual void applyPreferredLogicalWidthQuirks(LayoutUnit& minWidth, LayoutUnit& maxWidth) const = 0; virtual void layout() = 0; diff --git a/Source/WebCore/rendering/line/BreakingContext.h b/Source/WebCore/rendering/line/BreakingContext.h index c1f947689..799d2c063 100644 --- a/Source/WebCore/rendering/line/BreakingContext.h +++ b/Source/WebCore/rendering/line/BreakingContext.h @@ -559,9 +559,9 @@ inline void BreakingContext::handleReplaced() m_ignoringSpaces = true; } if (downcast<RenderListMarker>(*m_current.renderer()).isInside()) - m_width.addUncommittedReplacedWidth(replacedLogicalWidth); + m_width.addUncommittedWidth(replacedLogicalWidth); } else - m_width.addUncommittedReplacedWidth(replacedLogicalWidth); + m_width.addUncommittedWidth(replacedLogicalWidth); if (is<RenderRubyRun>(*m_current.renderer())) { m_width.applyOverhang(downcast<RenderRubyRun>(m_current.renderer()), m_lastObject, m_nextObject); downcast<RenderRubyRun>(m_current.renderer())->updatePriorContextFromCachedBreakIterator(m_renderTextInfo.lineBreakIterator); @@ -747,7 +747,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool float charWidth = 0; bool breakNBSP = m_autoWrap && m_currentStyle->nbspMode() == SPACE; // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word, - // which is only possible if the word is the first thing on the line, that is, if |w| is zero. + // which is only possible if the word is the first thing on the line. bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.hasCommitted()) || m_currWS == PRE); bool midWordBreak = false; bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap; diff --git a/Source/WebCore/rendering/line/LineWidth.cpp b/Source/WebCore/rendering/line/LineWidth.cpp index f3b12b3ef..71e05cb23 100644 --- a/Source/WebCore/rendering/line/LineWidth.cpp +++ b/Source/WebCore/rendering/line/LineWidth.cpp @@ -37,14 +37,6 @@ namespace WebCore { LineWidth::LineWidth(RenderBlockFlow& block, bool isFirstLine, IndentTextOrNot shouldIndentText) : m_block(block) - , m_uncommittedWidth(0) - , m_committedWidth(0) - , m_overhangWidth(0) - , m_trailingWhitespaceWidth(0) - , m_trailingCollapsedWhitespaceWidth(0) - , m_left(0) - , m_right(0) - , m_availableWidth(0) , m_isFirstLine(isFirstLine) , m_shouldIndentText(shouldIndentText) { @@ -136,10 +128,7 @@ void LineWidth::commit() { m_committedWidth += m_uncommittedWidth; m_uncommittedWidth = 0; - if (m_hasUncommittedReplaced) { - m_hasCommittedReplaced = true; - m_hasUncommittedReplaced = false; - } + m_hasCommitted = true; } void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer) diff --git a/Source/WebCore/rendering/line/LineWidth.h b/Source/WebCore/rendering/line/LineWidth.h index 949d2c392..370b3a0f8 100644 --- a/Source/WebCore/rendering/line/LineWidth.h +++ b/Source/WebCore/rendering/line/LineWidth.h @@ -59,7 +59,7 @@ public: float availableWidth() const { return m_availableWidth; } float logicalLeftOffset() const { return m_left; } - bool hasCommitted() const { return m_committedWidth > 0 || m_hasCommittedReplaced; } + bool hasCommitted() const { return m_hasCommitted; } void updateAvailableWidth(LayoutUnit minimumHeight = 0); void shrinkAvailableWidthForNewFloatIfNeeded(const FloatingObject&); @@ -67,11 +67,6 @@ public: { m_uncommittedWidth += delta; } - void addUncommittedReplacedWidth(float delta) - { - addUncommittedWidth(delta); - m_hasUncommittedReplaced = true; - } void commit(); void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer); void fitBelowFloats(bool isFirstLine = false); @@ -87,17 +82,16 @@ private: #endif RenderBlockFlow& m_block; - float m_uncommittedWidth; - float m_committedWidth; - float m_overhangWidth; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang. - float m_trailingWhitespaceWidth; - float m_trailingCollapsedWhitespaceWidth; - float m_left; - float m_right; - float m_availableWidth; - bool m_isFirstLine; - bool m_hasUncommittedReplaced { false }; - bool m_hasCommittedReplaced { false }; + float m_uncommittedWidth { 0 }; + float m_committedWidth { 0 }; + float m_overhangWidth { 0 }; // The amount by which |m_availableWidth| has been inflated to account for possible contraction due to ruby overhang. + float m_trailingWhitespaceWidth { 0 }; + float m_trailingCollapsedWhitespaceWidth { 0 }; + float m_left { 0 }; + float m_right { 0 }; + float m_availableWidth { 0 }; + bool m_isFirstLine { true }; + bool m_hasCommitted { false }; IndentTextOrNot m_shouldIndentText; }; diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index ebd4c9142..39c43ee15 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -811,6 +811,7 @@ bool RenderStyle::changeRequiresRepaint(const RenderStyle& other, unsigned& chan || rareNonInheritedData->userDrag != other.rareNonInheritedData->userDrag || rareNonInheritedData->m_borderFit != other.rareNonInheritedData->m_borderFit || rareNonInheritedData->m_objectFit != other.rareNonInheritedData->m_objectFit + || rareNonInheritedData->m_objectPosition != other.rareNonInheritedData->m_objectPosition || rareInheritedData->m_imageRendering != other.rareInheritedData->m_imageRendering) return true; diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 559df8182..7f84a0754 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -40,6 +40,7 @@ #include "Length.h" #include "LengthBox.h" #include "LengthFunctions.h" +#include "LengthPoint.h" #include "LengthSize.h" #include "LineClampValue.h" #include "NinePieceImage.h" @@ -1035,8 +1036,9 @@ public: TextOrientation textOrientation() const { return static_cast<TextOrientation>(rareInheritedData->m_textOrientation); } ObjectFit objectFit() const { return static_cast<ObjectFit>(rareNonInheritedData->m_objectFit); } - - // Return true if any transform related property (currently transform, transformStyle3D or perspective) + LengthPoint objectPosition() const { return rareNonInheritedData->m_objectPosition; } + + // Return true if any transform related property (currently transform, transformStyle3D or perspective) // indicates that we are transforming bool hasTransformRelatedProperty() const { return hasTransform() || preserves3D() || hasPerspective(); } @@ -1606,6 +1608,7 @@ public: bool setTextOrientation(TextOrientation); void setObjectFit(ObjectFit fit) { SET_VAR(rareNonInheritedData, m_objectFit, fit); } + void setObjectPosition(const LengthPoint& position) { SET_VAR(rareNonInheritedData, m_objectPosition, position); } void setRubyPosition(RubyPosition position) { SET_VAR(rareInheritedData, m_rubyPosition, position); } @@ -1896,6 +1899,7 @@ public: static TextOrientation initialTextOrientation() { return TextOrientation:: Mixed; } static ObjectFit initialObjectFit() { return ObjectFitFill; } + static LengthPoint initialObjectPosition() { return LengthPoint(Length(50.0f, Percent), Length(50.0f, Percent)); } static EEmptyCell initialEmptyCells() { return SHOW; } static EListStylePosition initialListStylePosition() { return OUTSIDE; } static EListStyleType initialListStyleType() { return Disc; } diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp index 24ae59cf2..120bd5f5a 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -63,6 +63,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() #endif , m_willChange(RenderStyle::initialWillChange()) , m_mask(FillLayer(MaskFillLayer)) + , m_objectPosition(RenderStyle::initialObjectPosition()) #if ENABLE(CSS_SHAPES) , m_shapeOutside(RenderStyle::initialShapeOutside()) , m_shapeMargin(RenderStyle::initialShapeMargin()) @@ -149,6 +150,7 @@ inline StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonIn , m_mask(o.m_mask) , m_maskBoxImage(o.m_maskBoxImage) , m_pageSize(o.m_pageSize) + , m_objectPosition(o.m_objectPosition) #if ENABLE(CSS_SHAPES) , m_shapeOutside(o.m_shapeOutside) , m_shapeMargin(o.m_shapeMargin) @@ -253,6 +255,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_mask == o.m_mask && m_maskBoxImage == o.m_maskBoxImage && m_pageSize == o.m_pageSize + && m_objectPosition == o.m_objectPosition #if ENABLE(CSS_SHAPES) && arePointingToEqualData(m_shapeOutside, o.m_shapeOutside) && m_shapeMargin == o.m_shapeMargin diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h index 9b1b2ad53..069b92878 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -32,6 +32,7 @@ #include "CursorData.h" #include "DataRef.h" #include "FillLayer.h" +#include "LengthPoint.h" #include "LineClampValue.h" #include "NinePieceImage.h" #include "ShapeValue.h" @@ -154,6 +155,7 @@ public: NinePieceImage m_maskBoxImage; LengthSize m_pageSize; + LengthPoint m_objectPosition; #if ENABLE(CSS_SHAPES) RefPtr<ShapeValue> m_shapeOutside; diff --git a/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp b/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp index 8d8858f84..854c3e25f 100644 --- a/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp +++ b/Source/WebCore/rendering/style/StyleScrollSnapPoints.cpp @@ -31,8 +31,8 @@ namespace WebCore { ScrollSnapPoints::ScrollSnapPoints() - : repeatOffset(100, Percent) - , hasRepeat(true) + : repeatOffset(0, Fixed) + , hasRepeat(false) , usesElements(false) { } diff --git a/Source/WebCore/rendering/style/WillChangeData.cpp b/Source/WebCore/rendering/style/WillChangeData.cpp index 77d4aa871..cff2e7cd3 100644 --- a/Source/WebCore/rendering/style/WillChangeData.cpp +++ b/Source/WebCore/rendering/style/WillChangeData.cpp @@ -99,6 +99,30 @@ static bool propertyCreatesStackingContext(CSSPropertyID property) } } +static bool propertyCreatesGraphicalGroup(CSSPropertyID property) +{ + switch (property) { + case CSSPropertyClipPath: + case CSSPropertyWebkitClipPath: + case CSSPropertyMask: + case CSSPropertyOpacity: +#if ENABLE(CSS_COMPOSITING) + case CSSPropertyMixBlendMode: + case CSSPropertyIsolation: +#endif + case CSSPropertyFilter: +#if ENABLE(FILTERS_LEVEL_2) + case CSSPropertyWebkitBackdropFilter: +#endif + case CSSPropertyWebkitMask: + case CSSPropertyWebkitMaskImage: + case CSSPropertyWebkitMaskBoxImage: + return true; + default: + return false; + } +} + static bool propertyTriggersCompositing(CSSPropertyID property) { switch (property) { @@ -137,6 +161,8 @@ void WillChangeData::addFeature(Feature feature, CSSPropertyID propertyID) m_canTriggerCompositingOnInline |= propertyTriggersCompositing(propertyID); m_canTriggerCompositing |= m_canTriggerCompositingOnInline | propertyTriggersCompositingOnBoxesOnly(propertyID); + + m_canCreateGraphicalGroup |= propertyCreatesGraphicalGroup(propertyID); } WillChangeData::FeaturePropertyPair WillChangeData::featureAt(size_t index) const diff --git a/Source/WebCore/rendering/style/WillChangeData.h b/Source/WebCore/rendering/style/WillChangeData.h index 49e76089d..6bab28da6 100644 --- a/Source/WebCore/rendering/style/WillChangeData.h +++ b/Source/WebCore/rendering/style/WillChangeData.h @@ -57,6 +57,7 @@ public: bool canCreateStackingContext() const { return m_canCreateStackingContext; } bool canTriggerCompositing() const { return m_canTriggerCompositing; } bool canTriggerCompositingOnInline() const { return m_canTriggerCompositingOnInline; } + bool canCreateGraphicalGroup() const { return m_canCreateGraphicalGroup; } enum Feature { ScrollPosition, @@ -124,6 +125,7 @@ private: bool m_canCreateStackingContext { false }; bool m_canTriggerCompositing { false }; bool m_canTriggerCompositingOnInline { false }; + bool m_canCreateGraphicalGroup { false }; }; |