зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1712703 - Record the "hangable" advance of trailing whitespace in a textframe property, and use this in nsLineLayout to adjust inline positioning. r=dholbert
Differential Revision: https://phabricator.services.mozilla.com/D174728
This commit is contained in:
Родитель
c59eae6aaf
Коммит
1c77c30705
|
@ -3024,6 +3024,36 @@ void nsLineLayout::ExpandInlineRubyBoxes(PerSpanData* aSpan) {
|
|||
}
|
||||
}
|
||||
|
||||
nscoord nsLineLayout::GetHangFrom(const PerSpanData* aSpan, bool aLineIsRTL) {
|
||||
const PerFrameData* pfd = aSpan->mLastFrame;
|
||||
nscoord result = 0;
|
||||
while (pfd) {
|
||||
if (const PerSpanData* childSpan = pfd->mSpan) {
|
||||
return GetHangFrom(childSpan, aLineIsRTL);
|
||||
}
|
||||
if (pfd->mIsTextFrame) {
|
||||
const auto* lastText = static_cast<const nsTextFrame*>(pfd->mFrame);
|
||||
result = lastText->GetHangableISize();
|
||||
// If the hangable space will be at the start edge of the line, due to
|
||||
// its bidi direction being against the line direction, we flag this by
|
||||
// negating the advance.
|
||||
if (lastText->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft() !=
|
||||
aLineIsRTL) {
|
||||
result = -result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (!pfd->mSkipWhenTrimmingWhitespace) {
|
||||
// If we hit a frame on the end that's not text and not a placeholder or
|
||||
// <br>, then there is no trailing whitespace to hang. Stop the search.
|
||||
return result;
|
||||
}
|
||||
// Scan back for a preceding frame whose whitespace we can hang.
|
||||
pfd = pfd->mPrev;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Align inline frames within the line according to the CSS text-align
|
||||
// property.
|
||||
void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
|
||||
|
@ -3049,8 +3079,14 @@ void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
|
|||
StyleTextAlign textAlign =
|
||||
aIsLastLine ? mStyleText->TextAlignForLastLine() : mStyleText->mTextAlign;
|
||||
|
||||
// Check if there's trailing whitespace we need to "hang" at line-wrap.
|
||||
nscoord hang = 0;
|
||||
if (aLine->IsLineWrapped()) {
|
||||
hang = GetHangFrom(mRootSpan, lineWM.IsBidiRTL());
|
||||
}
|
||||
|
||||
bool isSVG = LineContainerFrame()->IsInSVGTextSubtree();
|
||||
bool doTextAlign = remainingISize > 0;
|
||||
bool doTextAlign = remainingISize > 0 || hang != 0;
|
||||
|
||||
int32_t additionalGaps = 0;
|
||||
if (!isSVG &&
|
||||
|
@ -3107,31 +3143,40 @@ void nsLineLayout::TextAlignLine(nsLineBox* aLine, bool aIsLastLine) {
|
|||
|
||||
case StyleTextAlign::Start:
|
||||
case StyleTextAlign::Char:
|
||||
// default alignment is to start edge so do nothing.
|
||||
// Default alignment is to start edge so do nothing, except to apply
|
||||
// any "reverse-hang" amount resulting from reversed-direction trailing
|
||||
// space.
|
||||
// Char is for tables so treat as start if we find it in block layout.
|
||||
if (hang < 0) {
|
||||
dx = hang;
|
||||
}
|
||||
break;
|
||||
|
||||
case StyleTextAlign::Left:
|
||||
case StyleTextAlign::MozLeft:
|
||||
if (lineWM.IsBidiRTL()) {
|
||||
dx = remainingISize;
|
||||
dx = remainingISize + (hang > 0 ? hang : 0);
|
||||
} else if (hang < 0) {
|
||||
dx = hang;
|
||||
}
|
||||
break;
|
||||
|
||||
case StyleTextAlign::Right:
|
||||
case StyleTextAlign::MozRight:
|
||||
if (lineWM.IsBidiLTR()) {
|
||||
dx = remainingISize;
|
||||
dx = remainingISize + (hang > 0 ? hang : 0);
|
||||
} else if (hang < 0) {
|
||||
dx = hang;
|
||||
}
|
||||
break;
|
||||
|
||||
case StyleTextAlign::End:
|
||||
dx = remainingISize;
|
||||
dx = remainingISize + (hang > 0 ? hang : 0);
|
||||
break;
|
||||
|
||||
case StyleTextAlign::Center:
|
||||
case StyleTextAlign::MozCenter:
|
||||
dx = remainingISize / 2;
|
||||
dx = (remainingISize + hang) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -524,6 +524,10 @@ class nsLineLayout {
|
|||
.GetPhysicalSize(mRootSpan->mWritingMode);
|
||||
}
|
||||
|
||||
// Get the advance of any trailing hangable whitespace. If the whitespace
|
||||
// has directionality opposite to the line, the result is negated.
|
||||
nscoord GetHangFrom(const PerSpanData* aSpan, bool aLineIsRTL);
|
||||
|
||||
gfxBreakPriority mLastOptionalBreakPriority;
|
||||
int32_t mLastOptionalBreakFrameOffset;
|
||||
int32_t mForceBreakFrameOffset;
|
||||
|
|
|
@ -197,6 +197,8 @@ NS_DECLARE_FRAME_PROPERTY_RELEASABLE(UninflatedTextRunProperty, gfxTextRun)
|
|||
|
||||
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(FontSizeInflationProperty, float)
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(HangableWhitespaceProperty, nscoord)
|
||||
|
||||
struct nsTextFrame::PaintTextSelectionParams : nsTextFrame::PaintTextParams {
|
||||
Point textBaselinePt;
|
||||
PropertyProvider* provider = nullptr;
|
||||
|
@ -8148,6 +8150,25 @@ void nsTextFrame::SetFontSizeInflation(float aInflation) {
|
|||
SetProperty(FontSizeInflationProperty(), aInflation);
|
||||
}
|
||||
|
||||
void nsTextFrame::SetHangableISize(nscoord aISize) {
|
||||
MOZ_ASSERT(aISize >= 0, "unexpected negative hangable advance");
|
||||
if (aISize <= 0) {
|
||||
if (mHasHangableWS) {
|
||||
RemoveProperty(HangableWhitespaceProperty());
|
||||
}
|
||||
mHasHangableWS = false;
|
||||
return;
|
||||
}
|
||||
SetProperty(HangableWhitespaceProperty(), aISize);
|
||||
mHasHangableWS = true;
|
||||
}
|
||||
|
||||
nscoord nsTextFrame::GetHangableISize() const {
|
||||
MOZ_ASSERT(mHasHangableWS == HasProperty(HangableWhitespaceProperty()),
|
||||
"flag/property mismatch!");
|
||||
return mHasHangableWS ? GetProperty(HangableWhitespaceProperty()) : 0;
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
void nsTextFrame::MarkIntrinsicISizesDirty() {
|
||||
ClearTextRuns();
|
||||
|
@ -9242,16 +9263,23 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
|||
textMetrics.mAdvanceWidth -= trimmableWidth;
|
||||
trimmableWidth = 0.0;
|
||||
}
|
||||
SetHangableISize(0);
|
||||
} else if (whitespaceCanHang) {
|
||||
// Figure out how much will hang.
|
||||
// XXX This probably needs to be passed down and handled by nsLineLayout
|
||||
// rather than here, e.g. for bug 1712703 and 1253840.
|
||||
// Figure out how much whitespace will hang if at end-of-line.
|
||||
gfxFloat hang =
|
||||
std::min(std::max(0.0, textMetrics.mAdvanceWidth - availWidth),
|
||||
trimmableWidth);
|
||||
SetHangableISize(NSToCoordRound(trimmableWidth - hang));
|
||||
textMetrics.mAdvanceWidth -= hang;
|
||||
trimmableWidth = 0.0;
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE("How did trimmableWidth get set?!");
|
||||
SetHangableISize(0);
|
||||
trimmableWidth = 0.0;
|
||||
}
|
||||
} else {
|
||||
// Remove any stale frame property.
|
||||
SetHangableISize(0);
|
||||
}
|
||||
|
||||
if (!brokeText && lastBreak >= 0) {
|
||||
|
|
|
@ -771,6 +771,9 @@ class nsTextFrame : public nsIFrame {
|
|||
// (To be used only on the first textframe in the chain.)
|
||||
nsTextFrame* FindContinuationForOffset(int32_t aOffset);
|
||||
|
||||
void SetHangableISize(nscoord aISize);
|
||||
nscoord GetHangableISize() const;
|
||||
|
||||
protected:
|
||||
virtual ~nsTextFrame();
|
||||
|
||||
|
@ -808,6 +811,11 @@ class nsTextFrame : public nsIFrame {
|
|||
// Whether a cached continuations array is present.
|
||||
bool mHasContinuationsProperty = false;
|
||||
|
||||
// Whether a HangableWhitespace property is present. This could have been a
|
||||
// frame state bit, but they are currently full. Because we have a uint8_t
|
||||
// and a bool just above, there's a hole here that we can use.
|
||||
bool mHasHangableWS = false;
|
||||
|
||||
/**
|
||||
* Return true if the frame is part of a Selection.
|
||||
* Helper method to implement the public IsSelected() API.
|
||||
|
|
Загрузка…
Ссылка в новой задаче