| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2007 David Smith (catfish.man@gmail.com) | 4 * (C) 2007 David Smith (catfish.man@gmail.com) |
| 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
All rights reserved. | 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
All rights reserved. |
| 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
| 7 * | 7 * |
| 8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
| 9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
| 10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 using namespace HTMLNames; | 79 using namespace HTMLNames; |
| 80 | 80 |
| 81 struct SameSizeAsLayoutBlock : public LayoutBox { | 81 struct SameSizeAsLayoutBlock : public LayoutBox { |
| 82 LayoutObjectChildList children; | 82 LayoutObjectChildList children; |
| 83 LineBoxList lineBoxes; | 83 LineBoxList lineBoxes; |
| 84 uint32_t bitfields; | 84 uint32_t bitfields; |
| 85 }; | 85 }; |
| 86 | 86 |
| 87 static_assert(sizeof(LayoutBlock) == sizeof(SameSizeAsLayoutBlock), "LayoutBlock
should stay small"); | 87 static_assert(sizeof(LayoutBlock) == sizeof(SameSizeAsLayoutBlock), "LayoutBlock
should stay small"); |
| 88 | 88 |
| 89 typedef WTF::HashMap<const LayoutBox*, OwnPtr<ColumnInfo>> ColumnInfoMap; | |
| 90 static ColumnInfoMap* gColumnInfoMap = 0; | |
| 91 | |
| 92 static TrackedDescendantsMap* gPositionedDescendantsMap = 0; | 89 static TrackedDescendantsMap* gPositionedDescendantsMap = 0; |
| 93 static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0; | 90 static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0; |
| 94 | 91 |
| 95 static TrackedContainerMap* gPositionedContainerMap = 0; | 92 static TrackedContainerMap* gPositionedContainerMap = 0; |
| 96 static TrackedContainerMap* gPercentHeightContainerMap = 0; | 93 static TrackedContainerMap* gPercentHeightContainerMap = 0; |
| 97 | 94 |
| 98 typedef WTF::HashSet<LayoutBlock*> DelayedUpdateScrollInfoSet; | 95 typedef WTF::HashSet<LayoutBlock*> DelayedUpdateScrollInfoSet; |
| 99 static int gDelayUpdateScrollInfo = 0; | 96 static int gDelayUpdateScrollInfo = 0; |
| 100 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; | 97 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; |
| 101 | 98 |
| 102 static bool gColumnFlowSplitEnabled = true; | |
| 103 | |
| 104 // This class helps dispatching the 'overflow' event on layout change. overflow
can be set on LayoutBoxes, yet the existing code | 99 // This class helps dispatching the 'overflow' event on layout change. overflow
can be set on LayoutBoxes, yet the existing code |
| 105 // only works on LayoutBlocks. If this changes, this class should be shared with
other LayoutBoxes. | 100 // only works on LayoutBlocks. If this changes, this class should be shared with
other LayoutBoxes. |
| 106 class OverflowEventDispatcher { | 101 class OverflowEventDispatcher { |
| 107 WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher); | 102 WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher); |
| 108 public: | 103 public: |
| 109 OverflowEventDispatcher(const LayoutBlock* block) | 104 OverflowEventDispatcher(const LayoutBlock* block) |
| 110 : m_block(block) | 105 : m_block(block) |
| 111 , m_hadHorizontalLayoutOverflow(false) | 106 , m_hadHorizontalLayoutOverflow(false) |
| 112 , m_hadVerticalLayoutOverflow(false) | 107 , m_hadVerticalLayoutOverflow(false) |
| 113 { | 108 { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 appendImageIfNotNull(images, blockStyle.boxReflect()->mask().image()); | 197 appendImageIfNotNull(images, blockStyle.boxReflect()->mask().image()); |
| 203 appendImageIfNotNull(images, blockStyle.listStyleImage()); | 198 appendImageIfNotNull(images, blockStyle.listStyleImage()); |
| 204 appendImageIfNotNull(images, blockStyle.borderImageSource()); | 199 appendImageIfNotNull(images, blockStyle.borderImageSource()); |
| 205 appendImageIfNotNull(images, blockStyle.maskBoxImageSource()); | 200 appendImageIfNotNull(images, blockStyle.maskBoxImageSource()); |
| 206 if (blockStyle.shapeOutside()) | 201 if (blockStyle.shapeOutside()) |
| 207 appendImageIfNotNull(images, blockStyle.shapeOutside()->image()); | 202 appendImageIfNotNull(images, blockStyle.shapeOutside()->image()); |
| 208 } | 203 } |
| 209 | 204 |
| 210 void LayoutBlock::removeFromGlobalMaps() | 205 void LayoutBlock::removeFromGlobalMaps() |
| 211 { | 206 { |
| 212 if (hasColumns()) | |
| 213 gColumnInfoMap->take(this); | |
| 214 if (gPercentHeightDescendantsMap) | 207 if (gPercentHeightDescendantsMap) |
| 215 removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendant
sMap, gPercentHeightContainerMap); | 208 removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendant
sMap, gPercentHeightContainerMap); |
| 216 if (gPositionedDescendantsMap) | 209 if (gPositionedDescendantsMap) |
| 217 removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMa
p, gPositionedContainerMap); | 210 removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMa
p, gPositionedContainerMap); |
| 218 } | 211 } |
| 219 | 212 |
| 220 LayoutBlock::~LayoutBlock() | 213 LayoutBlock::~LayoutBlock() |
| 221 { | 214 { |
| 222 removeFromGlobalMaps(); | 215 removeFromGlobalMaps(); |
| 223 } | 216 } |
| (...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 837 | 830 |
| 838 ASSERT(beforeChild->parent() == this); | 831 ASSERT(beforeChild->parent() == this); |
| 839 if (beforeChild->parent() != this) { | 832 if (beforeChild->parent() != this) { |
| 840 // We should never reach here. If we do, we need to use the | 833 // We should never reach here. If we do, we need to use the |
| 841 // safe fallback to use the topmost beforeChild container. | 834 // safe fallback to use the topmost beforeChild container. |
| 842 beforeChild = beforeChildContainer; | 835 beforeChild = beforeChildContainer; |
| 843 } | 836 } |
| 844 } | 837 } |
| 845 } | 838 } |
| 846 | 839 |
| 847 // Check for a spanning element in columns. | |
| 848 if (gColumnFlowSplitEnabled && !RuntimeEnabledFeatures::regionBasedColumnsEn
abled()) { | |
| 849 LayoutBlockFlow* columnsBlockAncestor = columnsBlockForSpanningElement(n
ewChild); | |
| 850 if (columnsBlockAncestor) { | |
| 851 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled
, false); | |
| 852 // We are placing a column-span element inside a block. | |
| 853 LayoutBlockFlow* newBox = createAnonymousColumnSpanBlock(); | |
| 854 | |
| 855 if (columnsBlockAncestor != this && !isLayoutFlowThread()) { | |
| 856 // We are nested inside a multi-column element and are being spl
it by the span. We have to break up | |
| 857 // our block into continuations. | |
| 858 LayoutBoxModelObject* oldContinuation = continuation(); | |
| 859 | |
| 860 // When we split an anonymous block, there's no need to do any c
ontinuation hookup, | |
| 861 // since we haven't actually split a real element. | |
| 862 if (!isAnonymousBlock()) | |
| 863 setContinuation(newBox); | |
| 864 | |
| 865 splitFlow(beforeChild, newBox, newChild, oldContinuation); | |
| 866 return; | |
| 867 } | |
| 868 | |
| 869 // We have to perform a split of this block's children. This involve
s creating an anonymous block box to hold | |
| 870 // the column-spanning |newChild|. We take all of the children from
before |newChild| and put them into | |
| 871 // one anonymous columns block, and all of the children after |newCh
ild| go into another anonymous block. | |
| 872 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild); | |
| 873 return; | |
| 874 } | |
| 875 } | |
| 876 | |
| 877 bool madeBoxesNonInline = false; | 840 bool madeBoxesNonInline = false; |
| 878 | 841 |
| 879 // A block has to either have all of its children inline, or all of its chil
dren as blocks. | 842 // A block has to either have all of its children inline, or all of its chil
dren as blocks. |
| 880 // So, if our children are currently inline and a block child has to be inse
rted, we move all our | 843 // So, if our children are currently inline and a block child has to be inse
rted, we move all our |
| 881 // inline children into anonymous block boxes. | 844 // inline children into anonymous block boxes. |
| 882 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutO
fFlowPositioned()) { | 845 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutO
fFlowPositioned()) { |
| 883 // This is a block with inline content. Wrap the inline content in anony
mous blocks. | 846 // This is a block with inline content. Wrap the inline content in anony
mous blocks. |
| 884 makeChildrenNonInline(beforeChild); | 847 makeChildrenNonInline(beforeChild); |
| 885 madeBoxesNonInline = true; | 848 madeBoxesNonInline = true; |
| 886 | 849 |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 | 1109 |
| 1147 void LayoutBlock::removeChild(LayoutObject* oldChild) | 1110 void LayoutBlock::removeChild(LayoutObject* oldChild) |
| 1148 { | 1111 { |
| 1149 // No need to waste time in merging or removing empty anonymous blocks. | 1112 // No need to waste time in merging or removing empty anonymous blocks. |
| 1150 // We can just bail out if our document is getting destroyed. | 1113 // We can just bail out if our document is getting destroyed. |
| 1151 if (documentBeingDestroyed()) { | 1114 if (documentBeingDestroyed()) { |
| 1152 LayoutBox::removeChild(oldChild); | 1115 LayoutBox::removeChild(oldChild); |
| 1153 return; | 1116 return; |
| 1154 } | 1117 } |
| 1155 | 1118 |
| 1156 // This protects against column split flows when anonymous blocks are gettin
g merged. | |
| 1157 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false)
; | |
| 1158 | |
| 1159 // If this child is a block, and if our previous and next siblings are | 1119 // If this child is a block, and if our previous and next siblings are |
| 1160 // both anonymous blocks with inline content, then we can go ahead and | 1120 // both anonymous blocks with inline content, then we can go ahead and |
| 1161 // fold the inline content back together. | 1121 // fold the inline content back together. |
| 1162 LayoutObject* prev = oldChild->previousSibling(); | 1122 LayoutObject* prev = oldChild->previousSibling(); |
| 1163 LayoutObject* next = oldChild->nextSibling(); | 1123 LayoutObject* next = oldChild->nextSibling(); |
| 1164 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, p
rev, next); | 1124 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, p
rev, next); |
| 1165 if (canMergeAnonymousBlocks && prev && next) { | 1125 if (canMergeAnonymousBlocks && prev && next) { |
| 1166 prev->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutIn
validationReason::AnonymousBlockChange); | 1126 prev->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutIn
validationReason::AnonymousBlockChange); |
| 1167 LayoutBlockFlow* nextBlock = toLayoutBlockFlow(next); | 1127 LayoutBlockFlow* nextBlock = toLayoutBlockFlow(next); |
| 1168 LayoutBlockFlow* prevBlock = toLayoutBlockFlow(prev); | 1128 LayoutBlockFlow* prevBlock = toLayoutBlockFlow(prev); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1425 // If we use border-box sizing, have percentage padding, and our parent has
changed width then the width available to our children has changed even | 1385 // If we use border-box sizing, have percentage padding, and our parent has
changed width then the width available to our children has changed even |
| 1426 // though our own width has remained the same. | 1386 // though our own width has remained the same. |
| 1427 widthAvailableToChildrenHasChanged |= style()->boxSizing() == BORDER_BOX &&
needsPreferredWidthsRecalculation() && view()->layoutState()->containingBlockLog
icalWidthChanged(); | 1387 widthAvailableToChildrenHasChanged |= style()->boxSizing() == BORDER_BOX &&
needsPreferredWidthsRecalculation() && view()->layoutState()->containingBlockLog
icalWidthChanged(); |
| 1428 | 1388 |
| 1429 return widthAvailableToChildrenHasChanged; | 1389 return widthAvailableToChildrenHasChanged; |
| 1430 } | 1390 } |
| 1431 | 1391 |
| 1432 bool LayoutBlock::updateLogicalWidthAndColumnWidth() | 1392 bool LayoutBlock::updateLogicalWidthAndColumnWidth() |
| 1433 { | 1393 { |
| 1434 LayoutUnit oldWidth = logicalWidth(); | 1394 LayoutUnit oldWidth = logicalWidth(); |
| 1435 LayoutUnit oldColumnWidth = desiredColumnWidth(); | |
| 1436 | |
| 1437 updateLogicalWidth(); | 1395 updateLogicalWidth(); |
| 1438 calcColumnWidth(); | 1396 return oldWidth != logicalWidth() || widthAvailableToChildrenHasChanged(); |
| 1439 | |
| 1440 return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth()
|| widthAvailableToChildrenHasChanged(); | |
| 1441 } | 1397 } |
| 1442 | 1398 |
| 1443 void LayoutBlock::layoutBlock(bool) | 1399 void LayoutBlock::layoutBlock(bool) |
| 1444 { | 1400 { |
| 1445 ASSERT_NOT_REACHED(); | 1401 ASSERT_NOT_REACHED(); |
| 1446 clearNeedsLayout(); | 1402 clearNeedsLayout(); |
| 1447 } | 1403 } |
| 1448 | 1404 |
| 1449 void LayoutBlock::addOverflowFromChildren() | 1405 void LayoutBlock::addOverflowFromChildren() |
| 1450 { | 1406 { |
| 1451 if (!hasColumns()) { | 1407 if (childrenInline()) |
| 1452 if (childrenInline()) | 1408 toLayoutBlockFlow(this)->addOverflowFromInlineChildren(); |
| 1453 toLayoutBlockFlow(this)->addOverflowFromInlineChildren(); | 1409 else |
| 1454 else | 1410 addOverflowFromBlockChildren(); |
| 1455 addOverflowFromBlockChildren(); | |
| 1456 } else { | |
| 1457 ColumnInfo* colInfo = columnInfo(); | |
| 1458 if (columnCount(colInfo)) { | |
| 1459 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1
); | |
| 1460 addLayoutOverflow(lastRect); | |
| 1461 addContentsVisualOverflow(lastRect); | |
| 1462 } | |
| 1463 } | |
| 1464 } | 1411 } |
| 1465 | 1412 |
| 1466 void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool) | 1413 void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool) |
| 1467 { | 1414 { |
| 1468 m_overflow.clear(); | 1415 m_overflow.clear(); |
| 1469 | 1416 |
| 1470 // Add overflow from children. | 1417 // Add overflow from children. |
| 1471 addOverflowFromChildren(); | 1418 addOverflowFromChildren(); |
| 1472 | 1419 |
| 1473 // Add in the overflow from positioned objects. | 1420 // Add in the overflow from positioned objects. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1521 | 1468 |
| 1522 IntRect inflatedRect = pixelSnappedBorderBoxRect(); | 1469 IntRect inflatedRect = pixelSnappedBorderBoxRect(); |
| 1523 LayoutTheme::theme().adjustPaintInvalidationRect(this, inflatedRect); | 1470 LayoutTheme::theme().adjustPaintInvalidationRect(this, inflatedRect); |
| 1524 addVisualOverflow(LayoutRect(inflatedRect)); | 1471 addVisualOverflow(LayoutRect(inflatedRect)); |
| 1525 } | 1472 } |
| 1526 | 1473 |
| 1527 bool LayoutBlock::createsNewFormattingContext() const | 1474 bool LayoutBlock::createsNewFormattingContext() const |
| 1528 { | 1475 { |
| 1529 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() ||
hasOverflowClip() || isFlexItemIncludingDeprecated() | 1476 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() ||
hasOverflowClip() || isFlexItemIncludingDeprecated() |
| 1530 || style()->specifiesColumns() || isLayoutFlowThread() || isTableCell()
|| isTableCaption() || isFieldset() || isWritingModeRoot() | 1477 || style()->specifiesColumns() || isLayoutFlowThread() || isTableCell()
|| isTableCaption() || isFieldset() || isWritingModeRoot() |
| 1531 || isDocumentElement() || (RuntimeEnabledFeatures::regionBasedColumnsEna
bled() ? isColumnSpanAll() : style()->columnSpan()) || isGridItem(); | 1478 || isDocumentElement() || isColumnSpanAll() || isGridItem(); |
| 1532 } | 1479 } |
| 1533 | 1480 |
| 1534 void LayoutBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, L
ayoutBox& child) | 1481 void LayoutBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, L
ayoutBox& child) |
| 1535 { | 1482 { |
| 1536 // FIXME: Technically percentage height objects only need a relayout if thei
r percentage isn't going to be turned into | 1483 // FIXME: Technically percentage height objects only need a relayout if thei
r percentage isn't going to be turned into |
| 1537 // an auto value. Add a method to determine this, so that we can avoid the r
elayout. | 1484 // an auto value. Add a method to determine this, so that we can avoid the r
elayout. |
| 1538 bool hasRelativeLogicalHeight = child.hasRelativeLogicalHeight() | 1485 bool hasRelativeLogicalHeight = child.hasRelativeLogicalHeight() |
| 1539 || (child.isAnonymous() && this->hasRelativeLogicalHeight()) | 1486 || (child.isAnonymous() && this->hasRelativeLogicalHeight()) |
| 1540 || child.stretchesToViewport(); | 1487 || child.stretchesToViewport(); |
| 1541 if (relayoutChildren || (hasRelativeLogicalHeight && !isLayoutView())) | 1488 if (relayoutChildren || (hasRelativeLogicalHeight && !isLayoutView())) |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1697 bool isHorizontal = style->isHorizontalWritingMode(); | 1644 bool isHorizontal = style->isHorizontalWritingMode(); |
| 1698 return style->isDisplayInlineType() ? style->hasStaticInlinePosition(isHoriz
ontal) : style->hasStaticBlockPosition(isHorizontal); | 1645 return style->isDisplayInlineType() ? style->hasStaticInlinePosition(isHoriz
ontal) : style->hasStaticBlockPosition(isHorizontal); |
| 1699 } | 1646 } |
| 1700 | 1647 |
| 1701 void LayoutBlock::layoutPositionedObjects(bool relayoutChildren, PositionedLayou
tBehavior info) | 1648 void LayoutBlock::layoutPositionedObjects(bool relayoutChildren, PositionedLayou
tBehavior info) |
| 1702 { | 1649 { |
| 1703 TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects(); | 1650 TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects(); |
| 1704 if (!positionedDescendants) | 1651 if (!positionedDescendants) |
| 1705 return; | 1652 return; |
| 1706 | 1653 |
| 1707 if (hasColumns()) | |
| 1708 view()->layoutState()->clearPaginationInformation(); // Positioned objec
ts are not part of the column flow, so they don't paginate with the columns. | |
| 1709 | |
| 1710 for (auto* positionedObject : *positionedDescendants) { | 1654 for (auto* positionedObject : *positionedDescendants) { |
| 1711 positionedObject->setMayNeedPaintInvalidation(); | 1655 positionedObject->setMayNeedPaintInvalidation(); |
| 1712 | 1656 |
| 1713 SubtreeLayoutScope layoutScope(*positionedObject); | 1657 SubtreeLayoutScope layoutScope(*positionedObject); |
| 1714 // A fixed position element with an absolute positioned ancestor has no
way of knowing if the latter has changed position. So | 1658 // A fixed position element with an absolute positioned ancestor has no
way of knowing if the latter has changed position. So |
| 1715 // if this is a fixed position element, mark it for layout if it has an
abspos ancestor and needs to move with that ancestor, i.e. | 1659 // if this is a fixed position element, mark it for layout if it has an
abspos ancestor and needs to move with that ancestor, i.e. |
| 1716 // it has static position. | 1660 // it has static position. |
| 1717 markFixedPositionObjectForLayoutIfNeeded(positionedObject, layoutScope); | 1661 markFixedPositionObjectForLayoutIfNeeded(positionedObject, layoutScope); |
| 1718 if (info == LayoutOnlyFixedPositionedObjects) { | 1662 if (info == LayoutOnlyFixedPositionedObjects) { |
| 1719 positionedObject->layoutIfNeeded(); | 1663 positionedObject->layoutIfNeeded(); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1746 // to investigate why it does not trigger the correct invalidations in t
hat case. crbug.com/350756 | 1690 // to investigate why it does not trigger the correct invalidations in t
hat case. crbug.com/350756 |
| 1747 if (info == ForcedLayoutAfterContainingBlockMoved) | 1691 if (info == ForcedLayoutAfterContainingBlockMoved) |
| 1748 positionedObject->setNeedsLayout(LayoutInvalidationReason::AncestorM
oved, MarkOnlyThis); | 1692 positionedObject->setNeedsLayout(LayoutInvalidationReason::AncestorM
oved, MarkOnlyThis); |
| 1749 | 1693 |
| 1750 positionedObject->layoutIfNeeded(); | 1694 positionedObject->layoutIfNeeded(); |
| 1751 | 1695 |
| 1752 // Lay out again if our estimate was wrong. | 1696 // Lay out again if our estimate was wrong. |
| 1753 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(*po
sitionedObject) != oldLogicalTop) | 1697 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(*po
sitionedObject) != oldLogicalTop) |
| 1754 positionedObject->forceChildLayout(); | 1698 positionedObject->forceChildLayout(); |
| 1755 } | 1699 } |
| 1756 | |
| 1757 if (hasColumns()) | |
| 1758 view()->layoutState()->setColumnInfo(columnInfo()); // FIXME: Kind of gr
oss. We just put this back into the layout state so that pop() will work. | |
| 1759 } | 1700 } |
| 1760 | 1701 |
| 1761 void LayoutBlock::markPositionedObjectsForLayout() | 1702 void LayoutBlock::markPositionedObjectsForLayout() |
| 1762 { | 1703 { |
| 1763 if (TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects()
) { | 1704 if (TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects()
) { |
| 1764 for (auto* descendant : *positionedDescendants) | 1705 for (auto* descendant : *positionedDescendants) |
| 1765 descendant->setChildNeedsLayout(); | 1706 descendant->setChildNeedsLayout(); |
| 1766 } | 1707 } |
| 1767 } | 1708 } |
| 1768 | 1709 |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2213 else | 2154 else |
| 2214 checkChildren = locationInContainer.intersects(clipRect); | 2155 checkChildren = locationInContainer.intersects(clipRect); |
| 2215 } | 2156 } |
| 2216 } | 2157 } |
| 2217 if (checkChildren) { | 2158 if (checkChildren) { |
| 2218 // Hit test descendants first. | 2159 // Hit test descendants first. |
| 2219 LayoutSize scrolledOffset(localOffset); | 2160 LayoutSize scrolledOffset(localOffset); |
| 2220 if (hasOverflowClip()) | 2161 if (hasOverflowClip()) |
| 2221 scrolledOffset -= scrolledContentOffset(); | 2162 scrolledOffset -= scrolledContentOffset(); |
| 2222 | 2163 |
| 2223 // Hit test contents if we don't have columns. | 2164 // Hit test contents |
| 2224 if (!hasColumns()) { | 2165 if (hitTestContents(result, locationInContainer, toLayoutPoint(scrolledO
ffset), hitTestAction)) { |
| 2225 if (hitTestContents(result, locationInContainer, toLayoutPoint(scrol
ledOffset), hitTestAction)) { | |
| 2226 updateHitTestResult(result, flipForWritingMode(locationInContain
er.point() - localOffset)); | |
| 2227 return true; | |
| 2228 } | |
| 2229 if (hitTestAction == HitTestFloat && hitTestFloats(result, locationI
nContainer, toLayoutPoint(scrolledOffset))) | |
| 2230 return true; | |
| 2231 } else if (hitTestColumns(result, locationInContainer, toLayoutPoint(scr
olledOffset), hitTestAction)) { | |
| 2232 updateHitTestResult(result, flipForWritingMode(locationInContainer.p
oint() - localOffset)); | 2166 updateHitTestResult(result, flipForWritingMode(locationInContainer.p
oint() - localOffset)); |
| 2233 return true; | 2167 return true; |
| 2234 } | 2168 } |
| 2169 if (hitTestAction == HitTestFloat && hitTestFloats(result, locationInCon
tainer, toLayoutPoint(scrolledOffset))) |
| 2170 return true; |
| 2235 } | 2171 } |
| 2236 | 2172 |
| 2237 // Check if the point is outside radii. | 2173 // Check if the point is outside radii. |
| 2238 if (style()->hasBorderRadius()) { | 2174 if (style()->hasBorderRadius()) { |
| 2239 LayoutRect borderRect = borderBoxRect(); | 2175 LayoutRect borderRect = borderBoxRect(); |
| 2240 borderRect.moveBy(adjustedLocation); | 2176 borderRect.moveBy(adjustedLocation); |
| 2241 FloatRoundedRect border = style()->getRoundedBorderFor(borderRect); | 2177 FloatRoundedRect border = style()->getRoundedBorderFor(borderRect); |
| 2242 if (!locationInContainer.intersects(border)) | 2178 if (!locationInContainer.intersects(border)) |
| 2243 return false; | 2179 return false; |
| 2244 } | 2180 } |
| 2245 | 2181 |
| 2246 // Now hit test our background | 2182 // Now hit test our background |
| 2247 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChild
BlockBackground) { | 2183 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChild
BlockBackground) { |
| 2248 LayoutRect boundsRect(adjustedLocation, size()); | 2184 LayoutRect boundsRect(adjustedLocation, size()); |
| 2249 if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContai
ner.intersects(boundsRect)) { | 2185 if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContai
ner.intersects(boundsRect)) { |
| 2250 updateHitTestResult(result, flipForWritingMode(locationInContainer.p
oint() - localOffset)); | 2186 updateHitTestResult(result, flipForWritingMode(locationInContainer.p
oint() - localOffset)); |
| 2251 if (!result.addNodeToListBasedTestResult(nodeForHitTest(), locationI
nContainer, boundsRect)) | 2187 if (!result.addNodeToListBasedTestResult(nodeForHitTest(), locationI
nContainer, boundsRect)) |
| 2252 return true; | 2188 return true; |
| 2253 } | 2189 } |
| 2254 } | 2190 } |
| 2255 | 2191 |
| 2256 return false; | 2192 return false; |
| 2257 } | 2193 } |
| 2258 | 2194 |
| 2259 class ColumnRectIterator { | |
| 2260 WTF_MAKE_NONCOPYABLE(ColumnRectIterator); | |
| 2261 public: | |
| 2262 ColumnRectIterator(const LayoutBlock& block) | |
| 2263 : m_block(block) | |
| 2264 , m_colInfo(block.columnInfo()) | |
| 2265 , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1) | |
| 2266 , m_isHorizontal(block.isHorizontalWritingMode()) | |
| 2267 , m_logicalLeft(block.logicalLeftOffsetForContent()) | |
| 2268 { | |
| 2269 int colCount = m_colInfo->columnCount(); | |
| 2270 m_colIndex = colCount - 1; | |
| 2271 m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direct
ion; | |
| 2272 update(); | |
| 2273 } | |
| 2274 | |
| 2275 void advance() | |
| 2276 { | |
| 2277 ASSERT(hasMore()); | |
| 2278 m_colIndex--; | |
| 2279 update(); | |
| 2280 } | |
| 2281 | |
| 2282 LayoutRect columnRect() const { return m_colRect; } | |
| 2283 bool hasMore() const { return m_colIndex >= 0; } | |
| 2284 | |
| 2285 void adjust(LayoutSize& offset) const | |
| 2286 { | |
| 2287 LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_c
olRect.y()) - m_logicalLeft; | |
| 2288 offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogic
alTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset); | |
| 2289 if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) { | |
| 2290 if (m_isHorizontal) | |
| 2291 offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.p
addingTop()); | |
| 2292 else | |
| 2293 offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.pad
dingLeft(), 0); | |
| 2294 } | |
| 2295 } | |
| 2296 | |
| 2297 private: | |
| 2298 void update() | |
| 2299 { | |
| 2300 if (m_colIndex < 0) | |
| 2301 return; | |
| 2302 | |
| 2303 m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_c
olIndex); | |
| 2304 m_block.flipForWritingMode(m_colRect); | |
| 2305 m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRe
ct.width()) * m_direction; | |
| 2306 } | |
| 2307 | |
| 2308 const LayoutBlock& m_block; | |
| 2309 const ColumnInfo* const m_colInfo; | |
| 2310 const int m_direction; | |
| 2311 const bool m_isHorizontal; | |
| 2312 const LayoutUnit m_logicalLeft; | |
| 2313 int m_colIndex; | |
| 2314 LayoutUnit m_currLogicalTopOffset; | |
| 2315 LayoutRect m_colRect; | |
| 2316 }; | |
| 2317 | |
| 2318 bool LayoutBlock::hitTestColumns(HitTestResult& result, const HitTestLocation& l
ocationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestA
ction) | |
| 2319 { | |
| 2320 // We need to do multiple passes, breaking up our hit testing into strips. | |
| 2321 if (!hasColumns()) | |
| 2322 return false; | |
| 2323 | |
| 2324 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) { | |
| 2325 LayoutRect hitRect = LayoutRect(locationInContainer.boundingBox()); | |
| 2326 LayoutRect colRect = it.columnRect(); | |
| 2327 colRect.moveBy(accumulatedOffset); | |
| 2328 if (locationInContainer.intersects(colRect)) { | |
| 2329 // The point is inside this column. | |
| 2330 // Adjust accumulatedOffset to change where we hit test. | |
| 2331 LayoutSize offset; | |
| 2332 it.adjust(offset); | |
| 2333 LayoutPoint finalLocation = accumulatedOffset + offset; | |
| 2334 if (!result.isRectBasedTest() || colRect.contains(hitRect)) | |
| 2335 return hitTestContents(result, locationInContainer, finalLocatio
n, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(result, loc
ationInContainer, finalLocation)); | |
| 2336 | |
| 2337 hitTestContents(result, locationInContainer, finalLocation, hitTestA
ction); | |
| 2338 } | |
| 2339 } | |
| 2340 | |
| 2341 return false; | |
| 2342 } | |
| 2343 | |
| 2344 void LayoutBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& loc
ationInContainer) const | |
| 2345 { | |
| 2346 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) { | |
| 2347 LayoutRect colRect = it.columnRect(); | |
| 2348 if (colRect.contains(locationInContainer)) { | |
| 2349 it.adjust(offset); | |
| 2350 return; | |
| 2351 } | |
| 2352 } | |
| 2353 } | |
| 2354 | |
| 2355 bool LayoutBlock::hitTestContents(HitTestResult& result, const HitTestLocation&
locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTest
Action) | 2195 bool LayoutBlock::hitTestContents(HitTestResult& result, const HitTestLocation&
locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTest
Action) |
| 2356 { | 2196 { |
| 2357 if (childrenInline() && !isTable()) { | 2197 if (childrenInline() && !isTable()) { |
| 2358 // We have to hit-test our line boxes. | 2198 // We have to hit-test our line boxes. |
| 2359 if (m_lineBoxes.hitTest(this, result, locationInContainer, accumulatedOf
fset, hitTestAction)) | 2199 if (m_lineBoxes.hitTest(this, result, locationInContainer, accumulatedOf
fset, hitTestAction)) |
| 2360 return true; | 2200 return true; |
| 2361 } else { | 2201 } else { |
| 2362 // Hit test our children. | 2202 // Hit test our children. |
| 2363 HitTestAction childHitTest = hitTestAction; | 2203 HitTestAction childHitTest = hitTestAction; |
| 2364 if (hitTestAction == HitTestChildBlockBackgrounds) | 2204 if (hitTestAction == HitTestChildBlockBackgrounds) |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2578 return LayoutBox::positionForPoint(point); | 2418 return LayoutBox::positionForPoint(point); |
| 2579 } | 2419 } |
| 2580 | 2420 |
| 2581 void LayoutBlock::offsetForContents(LayoutPoint& offset) const | 2421 void LayoutBlock::offsetForContents(LayoutPoint& offset) const |
| 2582 { | 2422 { |
| 2583 offset = flipForWritingMode(offset); | 2423 offset = flipForWritingMode(offset); |
| 2584 | 2424 |
| 2585 if (hasOverflowClip()) | 2425 if (hasOverflowClip()) |
| 2586 offset += LayoutSize(scrolledContentOffset()); | 2426 offset += LayoutSize(scrolledContentOffset()); |
| 2587 | 2427 |
| 2588 if (hasColumns()) | |
| 2589 adjustPointToColumnContents(offset); | |
| 2590 | |
| 2591 offset = flipForWritingMode(offset); | 2428 offset = flipForWritingMode(offset); |
| 2592 } | 2429 } |
| 2593 | 2430 |
| 2594 LayoutUnit LayoutBlock::availableLogicalWidth() const | |
| 2595 { | |
| 2596 // If we have multiple columns, then the available logical width is reduced
to our column width. | |
| 2597 if (hasColumns()) | |
| 2598 return desiredColumnWidth(); | |
| 2599 return LayoutBox::availableLogicalWidth(); | |
| 2600 } | |
| 2601 | |
| 2602 int LayoutBlock::columnGap() const | 2431 int LayoutBlock::columnGap() const |
| 2603 { | 2432 { |
| 2604 if (style()->hasNormalColumnGap()) | 2433 if (style()->hasNormalColumnGap()) |
| 2605 return style()->fontDescription().computedPixelSize(); // "1em" is recom
mended as the normal gap setting. Matches <p> margins. | 2434 return style()->fontDescription().computedPixelSize(); // "1em" is recom
mended as the normal gap setting. Matches <p> margins. |
| 2606 return static_cast<int>(style()->columnGap()); | 2435 return static_cast<int>(style()->columnGap()); |
| 2607 } | 2436 } |
| 2608 | 2437 |
| 2609 void LayoutBlock::calcColumnWidth() | |
| 2610 { | |
| 2611 if (RuntimeEnabledFeatures::regionBasedColumnsEnabled()) | |
| 2612 return; | |
| 2613 | |
| 2614 // Calculate our column width and column count. | |
| 2615 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibli
ng4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 | |
| 2616 unsigned desiredColumnCount = 1; | |
| 2617 LayoutUnit desiredColumnWidth = contentLogicalWidth(); | |
| 2618 | |
| 2619 // For now, we don't support multi-column layouts when printing, since we ha
ve to do a lot of work for proper pagination. | |
| 2620 if (document().paginated() || !style()->specifiesColumns()) { | |
| 2621 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); | |
| 2622 return; | |
| 2623 } | |
| 2624 | |
| 2625 LayoutUnit availWidth = desiredColumnWidth; | |
| 2626 LayoutUnit colGap = columnGap(); | |
| 2627 LayoutUnit colWidth = std::max<LayoutUnit>(1, LayoutUnit(style()->columnWidt
h())); | |
| 2628 int colCount = std::max<int>(1, style()->columnCount()); | |
| 2629 | |
| 2630 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) { | |
| 2631 desiredColumnCount = colCount; | |
| 2632 desiredColumnWidth = std::max<LayoutUnit>(0, (availWidth - ((desiredColu
mnCount - 1) * colGap)) / desiredColumnCount); | |
| 2633 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount())
{ | |
| 2634 desiredColumnCount = std::max<LayoutUnit>(1, (availWidth + colGap) / (co
lWidth + colGap)); | |
| 2635 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colG
ap; | |
| 2636 } else { | |
| 2637 desiredColumnCount = std::max<LayoutUnit>(std::min<LayoutUnit>(colCount,
(availWidth + colGap) / (colWidth + colGap)), 1); | |
| 2638 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colG
ap; | |
| 2639 } | |
| 2640 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); | |
| 2641 } | |
| 2642 | |
| 2643 bool LayoutBlock::requiresColumns(int desiredColumnCount) const | |
| 2644 { | |
| 2645 // Paged overflow is treated as multicol here, unless this element was the o
ne that got its | |
| 2646 // overflow propagated to the viewport. | |
| 2647 bool isPaginated = style()->isOverflowPaged() && node() != document().viewpo
rtDefiningElement(); | |
| 2648 | |
| 2649 return firstChild() | |
| 2650 && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || isPagin
ated) | |
| 2651 && !firstChild()->isAnonymousColumnsBlock() | |
| 2652 && !firstChild()->isAnonymousColumnSpanBlock() && !isFlexibleBoxIncludin
gDeprecated(); | |
| 2653 } | |
| 2654 | |
| 2655 void LayoutBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width) | |
| 2656 { | |
| 2657 bool destroyColumns = !requiresColumns(count); | |
| 2658 if (destroyColumns) { | |
| 2659 if (hasColumns()) { | |
| 2660 gColumnInfoMap->take(this); | |
| 2661 setHasColumns(false); | |
| 2662 } | |
| 2663 } else { | |
| 2664 ColumnInfo* info; | |
| 2665 if (hasColumns()) { | |
| 2666 info = gColumnInfoMap->get(this); | |
| 2667 } else { | |
| 2668 if (!gColumnInfoMap) | |
| 2669 gColumnInfoMap = new ColumnInfoMap; | |
| 2670 info = new ColumnInfo; | |
| 2671 gColumnInfoMap->add(this, adoptPtr(info)); | |
| 2672 setHasColumns(true); | |
| 2673 } | |
| 2674 info->setDesiredColumnWidth(width); | |
| 2675 if (style()->isOverflowPaged()) { | |
| 2676 info->setDesiredColumnCount(1); | |
| 2677 info->setProgressionAxis(style()->hasInlinePaginationAxis() ? Column
Info::InlineAxis : ColumnInfo::BlockAxis); | |
| 2678 } else { | |
| 2679 info->setDesiredColumnCount(count); | |
| 2680 info->setProgressionAxis(ColumnInfo::InlineAxis); | |
| 2681 } | |
| 2682 } | |
| 2683 } | |
| 2684 | |
| 2685 LayoutUnit LayoutBlock::desiredColumnWidth() const | |
| 2686 { | |
| 2687 if (!hasColumns()) | |
| 2688 return contentLogicalWidth(); | |
| 2689 return gColumnInfoMap->get(this)->desiredColumnWidth(); | |
| 2690 } | |
| 2691 | |
| 2692 ColumnInfo* LayoutBlock::columnInfo() const | |
| 2693 { | |
| 2694 if (!hasColumns()) | |
| 2695 return 0; | |
| 2696 return gColumnInfoMap->get(this); | |
| 2697 } | |
| 2698 | |
| 2699 unsigned LayoutBlock::columnCount(ColumnInfo* colInfo) const | |
| 2700 { | |
| 2701 ASSERT(hasColumns()); | |
| 2702 ASSERT(gColumnInfoMap->get(this) == colInfo); | |
| 2703 return colInfo->columnCount(); | |
| 2704 } | |
| 2705 | |
| 2706 LayoutRect LayoutBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const | |
| 2707 { | |
| 2708 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo); | |
| 2709 | |
| 2710 // Compute the appropriate rect based off our information. | |
| 2711 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth(); | |
| 2712 LayoutUnit colLogicalHeight = colInfo->columnHeight(); | |
| 2713 LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); | |
| 2714 LayoutUnit colLogicalLeft = logicalLeftOffsetForContent(); | |
| 2715 LayoutUnit colGap = columnGap(); | |
| 2716 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { | |
| 2717 if (style()->isLeftToRightDirection()) | |
| 2718 colLogicalLeft += index * (colLogicalWidth + colGap); | |
| 2719 else | |
| 2720 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index *
(colLogicalWidth + colGap); | |
| 2721 } else { | |
| 2722 colLogicalTop += index * (colLogicalHeight + colGap); | |
| 2723 } | |
| 2724 | |
| 2725 if (isHorizontalWritingMode()) | |
| 2726 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLog
icalHeight); | |
| 2727 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogica
lWidth); | |
| 2728 } | |
| 2729 | |
| 2730 void LayoutBlock::adjustPointToColumnContents(LayoutPoint& point) const | |
| 2731 { | |
| 2732 // Just bail if we have no columns. | |
| 2733 if (!hasColumns()) | |
| 2734 return; | |
| 2735 | |
| 2736 ColumnInfo* colInfo = columnInfo(); | |
| 2737 if (!columnCount(colInfo)) | |
| 2738 return; | |
| 2739 | |
| 2740 // Determine which columns we intersect. | |
| 2741 LayoutUnit colGap = columnGap(); | |
| 2742 LayoutUnit halfColGap = colGap / 2; | |
| 2743 LayoutPoint columnPoint(columnRectAt(colInfo, 0).location()); | |
| 2744 LayoutUnit logicalOffset = 0; | |
| 2745 for (unsigned i = 0; i < colInfo->columnCount(); i++) { | |
| 2746 // Add in half the column gap to the left and right of the rect. | |
| 2747 LayoutRect colRect = columnRectAt(colInfo, i); | |
| 2748 flipForWritingMode(colRect); | |
| 2749 if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnIn
fo::InlineAxis)) { | |
| 2750 LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), c
olRect.width() + colGap, colRect.height()); | |
| 2751 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRec
t.maxX()) { | |
| 2752 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { | |
| 2753 // FIXME: The clamping that follows is not completely right
for right-to-left | |
| 2754 // content. | |
| 2755 if (point.y() < gapAndColumnRect.y()) { | |
| 2756 // Clamp everything above the column to its top left. | |
| 2757 point = gapAndColumnRect.location(); | |
| 2758 } else if (point.y() >= gapAndColumnRect.maxY()) { | |
| 2759 // Clamp everything below the column to the next column'
s top left. If there is | |
| 2760 // no next column, this still maps to just after this co
lumn. | |
| 2761 point = gapAndColumnRect.location(); | |
| 2762 point.move(0, gapAndColumnRect.height()); | |
| 2763 } | |
| 2764 } else { | |
| 2765 if (point.x() < colRect.x()) | |
| 2766 point.setX(colRect.x()); | |
| 2767 else if (point.x() >= colRect.maxX()) | |
| 2768 point.setX(colRect.maxX() - 1); | |
| 2769 } | |
| 2770 | |
| 2771 // We're inside the column. Translate the x and y into our colu
mn coordinate space. | |
| 2772 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
| 2773 point.move(columnPoint.x() - colRect.x(), (!style()->isFlipp
edBlocksWritingMode() ? logicalOffset : -logicalOffset)); | |
| 2774 else | |
| 2775 point.move((!style()->isFlippedBlocksWritingMode() ? logical
Offset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0); | |
| 2776 return; | |
| 2777 } | |
| 2778 | |
| 2779 // Move to the next position. | |
| 2780 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxi
s ? colRect.height() : colRect.width(); | |
| 2781 } else { | |
| 2782 LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, c
olRect.width(), colRect.height() + colGap); | |
| 2783 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRec
t.maxY()) { | |
| 2784 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { | |
| 2785 // FIXME: The clamping that follows is not completely right
for right-to-left | |
| 2786 // content. | |
| 2787 if (point.x() < gapAndColumnRect.x()) { | |
| 2788 // Clamp everything above the column to its top left. | |
| 2789 point = gapAndColumnRect.location(); | |
| 2790 } else if (point.x() >= gapAndColumnRect.maxX()) { | |
| 2791 // Clamp everything below the column to the next column'
s top left. If there is | |
| 2792 // no next column, this still maps to just after this co
lumn. | |
| 2793 point = gapAndColumnRect.location(); | |
| 2794 point.move(gapAndColumnRect.width(), 0); | |
| 2795 } | |
| 2796 } else { | |
| 2797 if (point.y() < colRect.y()) | |
| 2798 point.setY(colRect.y()); | |
| 2799 else if (point.y() >= colRect.maxY()) | |
| 2800 point.setY(colRect.maxY() - 1); | |
| 2801 } | |
| 2802 | |
| 2803 // We're inside the column. Translate the x and y into our colu
mn coordinate space. | |
| 2804 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
| 2805 point.move((!style()->isFlippedBlocksWritingMode() ? logical
Offset : -logicalOffset), columnPoint.y() - colRect.y()); | |
| 2806 else | |
| 2807 point.move(0, (!style()->isFlippedBlocksWritingMode() ? logi
calOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop()); | |
| 2808 return; | |
| 2809 } | |
| 2810 | |
| 2811 // Move to the next position. | |
| 2812 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxi
s ? colRect.width() : colRect.height(); | |
| 2813 } | |
| 2814 } | |
| 2815 } | |
| 2816 | |
| 2817 void LayoutBlock::adjustRectForColumns(LayoutRect& r) const | |
| 2818 { | |
| 2819 // Just bail if we have no columns. | |
| 2820 if (!hasColumns()) | |
| 2821 return; | |
| 2822 | |
| 2823 ColumnInfo* colInfo = columnInfo(); | |
| 2824 | |
| 2825 // Determine which columns we intersect. | |
| 2826 unsigned colCount = columnCount(colInfo); | |
| 2827 if (!colCount) | |
| 2828 return; | |
| 2829 | |
| 2830 // Begin with a result rect that is empty. | |
| 2831 LayoutRect result; | |
| 2832 | |
| 2833 bool isHorizontal = isHorizontalWritingMode(); | |
| 2834 LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore(); | |
| 2835 LayoutUnit colHeight = colInfo->columnHeight(); | |
| 2836 if (!colHeight) | |
| 2837 return; | |
| 2838 | |
| 2839 LayoutUnit startOffset = std::max(isHorizontal ? r.y() : r.x(), beforeBorder
Padding); | |
| 2840 LayoutUnit endOffset = std::max(std::min<LayoutUnit>(isHorizontal ? r.maxY()
: r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding); | |
| 2841 | |
| 2842 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibli
ng4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 | |
| 2843 unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight; | |
| 2844 unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight; | |
| 2845 | |
| 2846 if (startColumn == endColumn) { | |
| 2847 // The rect is fully contained within one column. Adjust for our offsets | |
| 2848 // and issue paint invalidations only that portion. | |
| 2849 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(); | |
| 2850 LayoutRect colRect = columnRectAt(colInfo, startColumn); | |
| 2851 LayoutRect paintInvalidationRect = r; | |
| 2852 | |
| 2853 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { | |
| 2854 if (isHorizontal) | |
| 2855 paintInvalidationRect.move(colRect.x() - logicalLeftOffset, - st
atic_cast<int>(startColumn) * colHeight); | |
| 2856 else | |
| 2857 paintInvalidationRect.move(- static_cast<int>(startColumn) * col
Height, colRect.y() - logicalLeftOffset); | |
| 2858 } else { | |
| 2859 if (isHorizontal) | |
| 2860 paintInvalidationRect.move(0, colRect.y() - startColumn * colHei
ght - beforeBorderPadding); | |
| 2861 else | |
| 2862 paintInvalidationRect.move(colRect.x() - startColumn * colHeight
- beforeBorderPadding, 0); | |
| 2863 } | |
| 2864 paintInvalidationRect.intersect(colRect); | |
| 2865 result.unite(paintInvalidationRect); | |
| 2866 } else { | |
| 2867 // We span multiple columns. We can just unite the start and end column
to get the final | |
| 2868 // paint invalidation rect. | |
| 2869 result.unite(columnRectAt(colInfo, startColumn)); | |
| 2870 result.unite(columnRectAt(colInfo, endColumn)); | |
| 2871 } | |
| 2872 | |
| 2873 r = result; | |
| 2874 } | |
| 2875 | |
| 2876 LayoutPoint LayoutBlock::flipForWritingModeIncludingColumns(const LayoutPoint& p
oint) const | |
| 2877 { | |
| 2878 ASSERT(hasColumns()); | |
| 2879 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) | |
| 2880 return point; | |
| 2881 ColumnInfo* colInfo = columnInfo(); | |
| 2882 LayoutUnit columnLogicalHeight = colInfo->columnHeight(); | |
| 2883 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + column
Count(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollba
rLogicalHeight(); | |
| 2884 if (isHorizontalWritingMode()) | |
| 2885 return LayoutPoint(point.x(), expandedLogicalHeight - point.y()); | |
| 2886 return LayoutPoint(expandedLogicalHeight - point.x(), point.y()); | |
| 2887 } | |
| 2888 | |
| 2889 void LayoutBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect
) const | |
| 2890 { | |
| 2891 ASSERT(hasColumns()); | |
| 2892 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) | |
| 2893 return; | |
| 2894 | |
| 2895 ColumnInfo* colInfo = columnInfo(); | |
| 2896 LayoutUnit columnLogicalHeight = colInfo->columnHeight(); | |
| 2897 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + column
Count(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollba
rLogicalHeight(); | |
| 2898 | |
| 2899 if (isHorizontalWritingMode()) | |
| 2900 rect.setY(expandedLogicalHeight - rect.maxY()); | |
| 2901 else | |
| 2902 rect.setX(expandedLogicalHeight - rect.maxX()); | |
| 2903 } | |
| 2904 | |
| 2905 LayoutSize LayoutBlock::columnOffset(const LayoutPoint& point) const | |
| 2906 { | |
| 2907 if (!hasColumns()) | |
| 2908 return LayoutSize(); | |
| 2909 | |
| 2910 ColumnInfo* colInfo = columnInfo(); | |
| 2911 | |
| 2912 LayoutUnit logicalLeft = logicalLeftOffsetForContent(); | |
| 2913 unsigned colCount = columnCount(colInfo); | |
| 2914 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth(); | |
| 2915 LayoutUnit colLogicalHeight = colInfo->columnHeight(); | |
| 2916 | |
| 2917 for (unsigned i = 0; i < colCount; ++i) { | |
| 2918 // Compute the edges for a given column in the block progression directi
on. | |
| 2919 LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingB
efore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight); | |
| 2920 if (!isHorizontalWritingMode()) | |
| 2921 sliceRect = sliceRect.transposedRect(); | |
| 2922 | |
| 2923 LayoutUnit logicalOffset = i * colLogicalHeight; | |
| 2924 | |
| 2925 // Now we're in the same coordinate space as the point. See if it is in
side the rectangle. | |
| 2926 if (isHorizontalWritingMode()) { | |
| 2927 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) { | |
| 2928 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
| 2929 return LayoutSize(columnRectAt(colInfo, i).x() - logicalLeft
, -logicalOffset); | |
| 2930 return LayoutSize(0, columnRectAt(colInfo, i).y() - logicalOffse
t - borderBefore() - paddingBefore()); | |
| 2931 } | |
| 2932 } else { | |
| 2933 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) { | |
| 2934 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
| 2935 return LayoutSize(-logicalOffset, columnRectAt(colInfo, i).y
() - logicalLeft); | |
| 2936 return LayoutSize(columnRectAt(colInfo, i).x() - logicalOffset -
borderBefore() - paddingBefore(), 0); | |
| 2937 } | |
| 2938 } | |
| 2939 } | |
| 2940 | |
| 2941 return LayoutSize(); | |
| 2942 } | |
| 2943 | |
| 2944 void LayoutBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Lay
outUnit& maxLogicalWidth) const | 2438 void LayoutBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, Lay
outUnit& maxLogicalWidth) const |
| 2945 { | 2439 { |
| 2946 if (childrenInline()) { | 2440 if (childrenInline()) { |
| 2947 // FIXME: Remove this const_cast. | 2441 // FIXME: Remove this const_cast. |
| 2948 toLayoutBlockFlow(const_cast<LayoutBlock*>(this))->computeInlinePreferre
dLogicalWidths(minLogicalWidth, maxLogicalWidth); | 2442 toLayoutBlockFlow(const_cast<LayoutBlock*>(this))->computeInlinePreferre
dLogicalWidths(minLogicalWidth, maxLogicalWidth); |
| 2949 } else { | 2443 } else { |
| 2950 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); | 2444 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); |
| 2951 } | 2445 } |
| 2952 | 2446 |
| 2953 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth); | 2447 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth); |
| 2954 | 2448 |
| 2955 // The flow thread based multicol implementation will do this adjustment on
the flow thread, and | |
| 2956 // not here on the multicol container, so that spanners won't incorrectly be
treated as column | |
| 2957 // content (and have spanners' preferred widths multiplied by the number of
columns, etc.). | |
| 2958 if (style()->specifiesColumns() && !RuntimeEnabledFeatures::regionBasedColum
nsEnabled()) | |
| 2959 adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth)
; | |
| 2960 | |
| 2961 if (isTableCell()) { | 2449 if (isTableCell()) { |
| 2962 Length tableCellWidth = toLayoutTableCell(this)->styleOrColLogicalWidth(
); | 2450 Length tableCellWidth = toLayoutTableCell(this)->styleOrColLogicalWidth(
); |
| 2963 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0) | 2451 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0) |
| 2964 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalW
idthForBoxSizing(tableCellWidth.value())); | 2452 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalW
idthForBoxSizing(tableCellWidth.value())); |
| 2965 } | 2453 } |
| 2966 | 2454 |
| 2967 int scrollbarWidth = intrinsicScrollbarLogicalWidth(); | 2455 int scrollbarWidth = intrinsicScrollbarLogicalWidth(); |
| 2968 maxLogicalWidth += scrollbarWidth; | 2456 maxLogicalWidth += scrollbarWidth; |
| 2969 minLogicalWidth += scrollbarWidth; | 2457 minLogicalWidth += scrollbarWidth; |
| 2970 } | 2458 } |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3001 m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil(); | 2489 m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil(); |
| 3002 } | 2490 } |
| 3003 | 2491 |
| 3004 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth(); | 2492 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth(); |
| 3005 m_minPreferredLogicalWidth += borderAndPadding; | 2493 m_minPreferredLogicalWidth += borderAndPadding; |
| 3006 m_maxPreferredLogicalWidth += borderAndPadding; | 2494 m_maxPreferredLogicalWidth += borderAndPadding; |
| 3007 | 2495 |
| 3008 clearPreferredLogicalWidthsDirty(); | 2496 clearPreferredLogicalWidthsDirty(); |
| 3009 } | 2497 } |
| 3010 | 2498 |
| 3011 void LayoutBlock::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalW
idth, LayoutUnit& maxLogicalWidth) const | |
| 3012 { | |
| 3013 ASSERT(!RuntimeEnabledFeatures::regionBasedColumnsEnabled()); | |
| 3014 if (!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()) { | |
| 3015 // The min/max intrinsic widths calculated really tell how much space el
ements need when | |
| 3016 // laid out inside the columns. In order to eventually end up with the d
esired column width, | |
| 3017 // we need to convert them to values pertaining to the multicol containe
r. | |
| 3018 int columnCount = style()->hasAutoColumnCount() ? 1 : style()->columnCou
nt(); | |
| 3019 LayoutUnit columnWidth; | |
| 3020 LayoutUnit gapExtra = (columnCount - 1) * columnGap(); | |
| 3021 if (style()->hasAutoColumnWidth()) { | |
| 3022 minLogicalWidth = minLogicalWidth * columnCount + gapExtra; | |
| 3023 } else { | |
| 3024 columnWidth = style()->columnWidth(); | |
| 3025 minLogicalWidth = std::min(minLogicalWidth, columnWidth); | |
| 3026 } | |
| 3027 // FIXME: If column-count is auto here, we should resolve it to calculat
e the maximum | |
| 3028 // intrinsic width, instead of pretending that it's 1. The only way to d
o that is by | |
| 3029 // performing a layout pass, but this is not an appropriate time or plac
e for layout. The | |
| 3030 // good news is that if height is unconstrained and there are no explici
t breaks, the | |
| 3031 // resolved column-count really should be 1. | |
| 3032 maxLogicalWidth = std::max(maxLogicalWidth, columnWidth) * columnCount +
gapExtra; | |
| 3033 } | |
| 3034 } | |
| 3035 | |
| 3036 void LayoutBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth
, LayoutUnit& maxLogicalWidth) const | 2499 void LayoutBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth
, LayoutUnit& maxLogicalWidth) const |
| 3037 { | 2500 { |
| 3038 const ComputedStyle& styleToUse = styleRef(); | 2501 const ComputedStyle& styleToUse = styleRef(); |
| 3039 bool nowrap = styleToUse.whiteSpace() == NOWRAP; | 2502 bool nowrap = styleToUse.whiteSpace() == NOWRAP; |
| 3040 | 2503 |
| 3041 LayoutObject* child = firstChild(); | 2504 LayoutObject* child = firstChild(); |
| 3042 LayoutBlock* containingBlock = this->containingBlock(); | 2505 LayoutBlock* containingBlock = this->containingBlock(); |
| 3043 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0; | 2506 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0; |
| 3044 while (child) { | 2507 while (child) { |
| 3045 // Positioned children don't affect the min/max width. Spanners only aff
ect the min/max | 2508 // Positioned children don't affect the min/max width. Spanners only aff
ect the min/max |
| (...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3644 void LayoutBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) | 3107 void LayoutBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) |
| 3645 { | 3108 { |
| 3646 if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) | 3109 if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) |
| 3647 flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spa
ceShortage); | 3110 flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spa
ceShortage); |
| 3648 } | 3111 } |
| 3649 | 3112 |
| 3650 void LayoutBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeigh
t) | 3113 void LayoutBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeigh
t) |
| 3651 { | 3114 { |
| 3652 if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) | 3115 if (LayoutFlowThread* flowThread = flowThreadContainingBlock()) |
| 3653 flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() +
offset, minHeight); | 3116 flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() +
offset, minHeight); |
| 3654 else if (ColumnInfo* colInfo = view()->layoutState()->columnInfo()) | |
| 3655 colInfo->updateMinimumColumnHeight(minHeight); | |
| 3656 } | 3117 } |
| 3657 | 3118 |
| 3658 LayoutUnit LayoutBlock::collapsedMarginBeforeForChild(const LayoutBox& child) co
nst | 3119 LayoutUnit LayoutBlock::collapsedMarginBeforeForChild(const LayoutBox& child) co
nst |
| 3659 { | 3120 { |
| 3660 // If the child has the same directionality as we do, then we can just retur
n its | 3121 // If the child has the same directionality as we do, then we can just retur
n its |
| 3661 // collapsed margin. | 3122 // collapsed margin. |
| 3662 if (!child.isWritingModeRoot()) | 3123 if (!child.isWritingModeRoot()) |
| 3663 return child.collapsedMarginBefore(); | 3124 return child.collapsedMarginBefore(); |
| 3664 | 3125 |
| 3665 // The child has a different directionality. If the child is parallel, then
it's just | 3126 // The child has a different directionality. If the child is parallel, then
it's just |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3921 void LayoutBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* m
arkedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const Layout
Object* obj) const | 3382 void LayoutBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* m
arkedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const Layout
Object* obj) const |
| 3922 { | 3383 { |
| 3923 showLayoutObject(); | 3384 showLayoutObject(); |
| 3924 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRoot
Box()) | 3385 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRoot
Box()) |
| 3925 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLa
bel2, obj, 1); | 3386 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLa
bel2, obj, 1); |
| 3926 } | 3387 } |
| 3927 | 3388 |
| 3928 #endif | 3389 #endif |
| 3929 | 3390 |
| 3930 } // namespace blink | 3391 } // namespace blink |
| OLD | NEW |