зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1731541 - When line-clamp is in effect, make text-wrap:balance consider only the lines up to the clamp limit. r=emilio
This corresponds to how Chrome behaves, and passes the test they included in WPT. It's unclear to me whether this behavior actually follows from the current spec (see https://github.com/w3c/csswg-drafts/issues/9310), but it seems to be the desired result. (I've put it behind a (default-enabled) pref for now, so that it's possible to experiment with the two possible interpretations, but we can remove the pref once the spec question is clarified/confirmed.) This patch also disables balancing for fragmented/overflowing blocks, as that will not currently work well. We may want to address that as a followup issue (though it won't matter to the primary balance use-cases such as titles). Depends on D188139 Differential Revision: https://phabricator.services.mozilla.com/D188220
This commit is contained in:
Родитель
526dc74d07
Коммит
a3e6067540
|
@ -1449,9 +1449,25 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
|||
bool tryBalance = StyleText()->mTextWrap == StyleTextWrap::Balance &&
|
||||
!GetPrevContinuation();
|
||||
|
||||
// Target number of lines in the block while balancing; negative if no
|
||||
// balancing is being done.
|
||||
int32_t balanceTarget = -1;
|
||||
// Struct used to hold the "target" number of lines or clamp position to
|
||||
// maintain when doing text-wrap: balance.
|
||||
struct BalanceTarget {
|
||||
// If line-clamp is in effect, mContent and mOffset indicate the starting
|
||||
// position of the first line after the clamp limit. If line-clamp is not
|
||||
// in use, mContent is null and mOffset is the total number of lines that
|
||||
// the block must contain.
|
||||
nsIContent* mContent = nullptr;
|
||||
int32_t mOffset = -1;
|
||||
|
||||
bool operator==(const BalanceTarget& aOther) const {
|
||||
return mContent == aOther.mContent && mOffset == aOther.mOffset;
|
||||
}
|
||||
bool operator!=(const BalanceTarget& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
BalanceTarget balanceTarget;
|
||||
|
||||
// Helpers for text-wrap: balance implementation:
|
||||
|
||||
|
@ -1467,6 +1483,24 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
|||
return n;
|
||||
};
|
||||
|
||||
// Return a BalanceTarget record representing the position at which line-clamp
|
||||
// will take effect for the current line list. Only to be used when there are
|
||||
// enough lines that the clamp will apply.
|
||||
auto getClampPosition = [&](uint32_t aClampCount) -> BalanceTarget {
|
||||
MOZ_ASSERT(aClampCount < mLines.size());
|
||||
auto iter = mLines.begin();
|
||||
for (uint32_t i = 0; i < aClampCount; i++) {
|
||||
++iter;
|
||||
}
|
||||
nsIContent* content = iter->mFirstChild->GetContent();
|
||||
int32_t offset = 0;
|
||||
if (content && iter->mFirstChild->IsTextFrame()) {
|
||||
auto* textFrame = static_cast<nsTextFrame*>(iter->mFirstChild);
|
||||
offset = textFrame->GetContentOffset();
|
||||
}
|
||||
return BalanceTarget{content, offset};
|
||||
};
|
||||
|
||||
// "balancing" is implemented by shortening the effective inline-size of the
|
||||
// lines, so that content will tend to be pushed down to fill later lines of
|
||||
// the block. `balanceInset` is the current amount of "inset" to apply, and
|
||||
|
@ -1495,30 +1529,57 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
|||
if (!reflowStatus.IsFullyComplete()) {
|
||||
break;
|
||||
}
|
||||
balanceTarget =
|
||||
balanceTarget.mOffset =
|
||||
countLinesUpTo(StaticPrefs::layout_css_text_wrap_balance_limit());
|
||||
if (balanceTarget < 2) {
|
||||
if (balanceTarget.mOffset < 2) {
|
||||
// If there are less than 2 lines, or the number exceeds the limit,
|
||||
// no balancing is needed; just break from the balance loop.
|
||||
break;
|
||||
}
|
||||
// Initialize the amount of inset to try, and the iteration step size.
|
||||
balanceStep = aReflowInput.ComputedISize() / balanceTarget;
|
||||
balanceStep = aReflowInput.ComputedISize() / balanceTarget.mOffset;
|
||||
trialState.ResetForBalance(balanceStep);
|
||||
balanceStep /= 2;
|
||||
|
||||
// If -webkit-line-clamp is in effect, then we need to maintain the
|
||||
// content location at which clamping occurs, rather than the total
|
||||
// number of lines in the block.
|
||||
if (StaticPrefs::layout_css_text_wrap_balance_after_clamp_enabled() &&
|
||||
IsLineClampRoot(this)) {
|
||||
uint32_t lineClampCount = aReflowInput.mStyleDisplay->mWebkitLineClamp;
|
||||
if (uint32_t(balanceTarget.mOffset) > lineClampCount) {
|
||||
auto t = getClampPosition(lineClampCount);
|
||||
if (t.mContent) {
|
||||
balanceTarget = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Restore initial floatManager state for a new trial with updated inset.
|
||||
aReflowInput.mFloatManager->PopState(&floatManagerState);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Helper to determine whether the current trial succeeded (i.e. was able
|
||||
// to fit the content into the expected number of lines).
|
||||
auto trialSucceeded = [&]() -> bool {
|
||||
if (!reflowStatus.IsFullyComplete()) {
|
||||
return false;
|
||||
}
|
||||
if (balanceTarget.mContent) {
|
||||
auto t = getClampPosition(aReflowInput.mStyleDisplay->mWebkitLineClamp);
|
||||
return t == balanceTarget;
|
||||
}
|
||||
int32_t numLines =
|
||||
countLinesUpTo(StaticPrefs::layout_css_text_wrap_balance_limit());
|
||||
return numLines == balanceTarget.mOffset;
|
||||
};
|
||||
|
||||
// If we're in the process of a balance operation, check whether we've
|
||||
// inset by too much and either increase or reduce the inset for the next
|
||||
// iteration.
|
||||
if (balanceStep > 0) {
|
||||
int32_t numLines =
|
||||
countLinesUpTo(StaticPrefs::layout_css_text_wrap_balance_limit());
|
||||
if (reflowStatus.IsFullyComplete() && numLines == balanceTarget) {
|
||||
if (trialSucceeded()) {
|
||||
trialState.ResetForBalance(balanceStep);
|
||||
} else {
|
||||
trialState.ResetForBalance(-balanceStep);
|
||||
|
@ -1531,10 +1592,8 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
|
|||
|
||||
// If we were attempting to balance, check whether the final iteration was
|
||||
// successful, and if not, back up by one step.
|
||||
if (balanceTarget >= 0) {
|
||||
int32_t numLines =
|
||||
countLinesUpTo(StaticPrefs::layout_css_text_wrap_balance_limit());
|
||||
if (reflowStatus.IsFullyComplete() && numLines == balanceTarget) {
|
||||
if (balanceTarget.mOffset >= 0) {
|
||||
if (trialSucceeded()) {
|
||||
break;
|
||||
}
|
||||
trialState.ResetForBalance(-1);
|
||||
|
|
|
@ -8783,6 +8783,11 @@
|
|||
value: 10
|
||||
mirror: always
|
||||
|
||||
- name: layout.css.text-wrap-balance-after-clamp.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Support for the css Zoom property.
|
||||
- name: layout.css.zoom.enabled
|
||||
type: RelaxedAtomicBool
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[text-wrap-balance-line-clamp-001.html]
|
||||
expected: FAIL
|
Загрузка…
Ссылка в новой задаче