@@ -1449,9 +1449,25 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
1449
1449
bool tryBalance = StyleText ()->mTextWrap == StyleTextWrap::Balance &&
1450
1450
!GetPrevContinuation ();
1451
1451
1452
- // Target number of lines in the block while balancing; negative if no
1453
- // balancing is being done.
1454
- int32_t balanceTarget = -1 ;
1452
+ // Struct used to hold the "target" number of lines or clamp position to
1453
+ // maintain when doing text-wrap: balance.
1454
+ struct BalanceTarget {
1455
+ // If line-clamp is in effect, mContent and mOffset indicate the starting
1456
+ // position of the first line after the clamp limit. If line-clamp is not
1457
+ // in use, mContent is null and mOffset is the total number of lines that
1458
+ // the block must contain.
1459
+ nsIContent* mContent = nullptr ;
1460
+ int32_t mOffset = -1 ;
1461
+
1462
+ bool operator ==(const BalanceTarget& aOther) const {
1463
+ return mContent == aOther.mContent && mOffset == aOther.mOffset ;
1464
+ }
1465
+ bool operator !=(const BalanceTarget& aOther) const {
1466
+ return !(*this == aOther);
1467
+ }
1468
+ };
1469
+
1470
+ BalanceTarget balanceTarget;
1455
1471
1456
1472
// Helpers for text-wrap: balance implementation:
1457
1473
@@ -1467,6 +1483,24 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
1467
1483
return n;
1468
1484
};
1469
1485
1486
+ // Return a BalanceTarget record representing the position at which line-clamp
1487
+ // will take effect for the current line list. Only to be used when there are
1488
+ // enough lines that the clamp will apply.
1489
+ auto getClampPosition = [&](uint32_t aClampCount) -> BalanceTarget {
1490
+ MOZ_ASSERT (aClampCount < mLines .size ());
1491
+ auto iter = mLines .begin ();
1492
+ for (uint32_t i = 0 ; i < aClampCount; i++) {
1493
+ ++iter;
1494
+ }
1495
+ nsIContent* content = iter->mFirstChild ->GetContent ();
1496
+ int32_t offset = 0 ;
1497
+ if (content && iter->mFirstChild ->IsTextFrame ()) {
1498
+ auto * textFrame = static_cast (iter->mFirstChild );
1499
+ offset = textFrame->GetContentOffset ();
1500
+ }
1501
+ return BalanceTarget{content, offset};
1502
+ };
1503
+
1470
1504
// "balancing" is implemented by shortening the effective inline-size of the
1471
1505
// lines, so that content will tend to be pushed down to fill later lines of
1472
1506
// the block. `balanceInset` is the current amount of "inset" to apply, and
@@ -1495,30 +1529,57 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
1495
1529
if (!reflowStatus.IsFullyComplete ()) {
1496
1530
break ;
1497
1531
}
1498
- balanceTarget =
1532
+ balanceTarget. mOffset =
1499
1533
countLinesUpTo (StaticPrefs::layout_css_text_wrap_balance_limit ());
1500
- if (balanceTarget < 2 ) {
1534
+ if (balanceTarget. mOffset < 2 ) {
1501
1535
// If there are less than 2 lines, or the number exceeds the limit,
1502
1536
// no balancing is needed; just break from the balance loop.
1503
1537
break ;
1504
1538
}
1505
1539
// Initialize the amount of inset to try, and the iteration step size.
1506
- balanceStep = aReflowInput.ComputedISize () / balanceTarget;
1540
+ balanceStep = aReflowInput.ComputedISize () / balanceTarget. mOffset ;
1507
1541
trialState.ResetForBalance (balanceStep);
1508
1542
balanceStep /= 2 ;
1509
1543
1544
+ // If -webkit-line-clamp is in effect, then we need to maintain the
1545
+ // content location at which clamping occurs, rather than the total
1546
+ // number of lines in the block.
1547
+ if (StaticPrefs::layout_css_text_wrap_balance_after_clamp_enabled () &&
1548
+ IsLineClampRoot (this )) {
1549
+ uint32_t lineClampCount = aReflowInput.mStyleDisplay ->mWebkitLineClamp ;
1550
+ if (uint32_t (balanceTarget.mOffset ) > lineClampCount) {
1551
+ auto t = getClampPosition (lineClampCount);
1552
+ if (t.mContent ) {
1553
+ balanceTarget = t;
1554
+ }
1555
+ }
1556
+ }
1557
+
1510
1558
// Restore initial floatManager state for a new trial with updated inset.
1511
1559
aReflowInput.mFloatManager ->PopState (&floatManagerState);
1512
1560
continue ;
1513
1561
}
1514
1562
1563
+ // Helper to determine whether the current trial succeeded (i.e. was able
1564
+ // to fit the content into the expected number of lines).
1565
+ auto trialSucceeded = [&]() -> bool {
1566
+ if (!reflowStatus.IsFullyComplete ()) {
1567
+ return false ;
1568
+ }
1569
+ if (balanceTarget.mContent ) {
1570
+ auto t = getClampPosition (aReflowInput.mStyleDisplay ->mWebkitLineClamp );
1571
+ return t == balanceTarget;
1572
+ }
1573
+ int32_t numLines =
1574
+ countLinesUpTo (StaticPrefs::layout_css_text_wrap_balance_limit ());
1575
+ return numLines == balanceTarget.mOffset ;
1576
+ };
1577
+
1515
1578
// If we're in the process of a balance operation, check whether we've
1516
1579
// inset by too much and either increase or reduce the inset for the next
1517
1580
// iteration.
1518
1581
if (balanceStep > 0 ) {
1519
- int32_t numLines =
1520
- countLinesUpTo (StaticPrefs::layout_css_text_wrap_balance_limit ());
1521
- if (reflowStatus.IsFullyComplete () && numLines == balanceTarget) {
1582
+ if (trialSucceeded ()) {
1522
1583
trialState.ResetForBalance (balanceStep);
1523
1584
} else {
1524
1585
trialState.ResetForBalance (-balanceStep);
@@ -1531,10 +1592,8 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
1531
1592
1532
1593
// If we were attempting to balance, check whether the final iteration was
1533
1594
// successful, and if not, back up by one step.
1534
- if (balanceTarget >= 0 ) {
1535
- int32_t numLines =
1536
- countLinesUpTo (StaticPrefs::layout_css_text_wrap_balance_limit ());
1537
- if (reflowStatus.IsFullyComplete () && numLines == balanceTarget) {
1595
+ if (balanceTarget.mOffset >= 0 ) {
1596
+ if (trialSucceeded ()) {
1538
1597
break ;
1539
1598
}
1540
1599
trialState.ResetForBalance (-1 );
0 commit comments