Skip to content

Commit a39015e

Browse files
committed
Bug 1604327 - Handle text-combine-upright when the text comes from multiple generated-content items (e.g. a counter value plus literal text). r=TYLin
Differential Revision: https://phabricator.services.mozilla.com/D259332
1 parent f0d1651 commit a39015e

File tree

3 files changed

+123
-32
lines changed

3 files changed

+123
-32
lines changed

layout/generic/nsTextFrame.cpp

Lines changed: 110 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4752,11 +4752,27 @@ nsresult nsTextFrame::CharacterDataChanged(
47524752
return NS_OK;
47534753
}
47544754

4755-
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(TextCombineScaleFactorProperty, float)
4755+
struct TextCombineData {
4756+
// Measured advance of the text before any text-combine scaling is applied.
4757+
nscoord mNaturalWidth = 0;
4758+
// Inline offset to place this text within the 1-em block of the upright-
4759+
// combined cell.
4760+
nscoord mOffset = 0;
4761+
// Inline scaling factor to apply (always <= 1.0, as the text may be
4762+
// compressed but is never expanded to fit the 1-em cell).
4763+
float mScale = 1.0f;
4764+
};
4765+
4766+
NS_DECLARE_FRAME_PROPERTY_DELETABLE(TextCombineDataProperty, TextCombineData)
4767+
4768+
float nsTextFrame::GetTextCombineScale() const {
4769+
const auto* data = GetProperty(TextCombineDataProperty());
4770+
return data ? data->mScale : 1.0f;
4771+
}
47564772

4757-
float nsTextFrame::GetTextCombineScaleFactor(nsTextFrame* aFrame) {
4758-
float factor = aFrame->GetProperty(TextCombineScaleFactorProperty());
4759-
return factor ? factor : 1.0f;
4773+
std::pair<nscoord, float> nsTextFrame::GetTextCombineOffsetAndScale() const {
4774+
const auto* data = GetProperty(TextCombineDataProperty());
4775+
return data ? std::pair(data->mOffset, data->mScale) : std::pair(0, 1.0f);
47604776
}
47614777

47624778
void nsTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
@@ -6352,9 +6368,13 @@ bool nsTextFrame::PaintTextWithSelectionColors(
63526368
nscoord(aParams.framePt.y + offs), GetSize().width,
63536369
nscoord(advance));
63546370
} else {
6371+
// For text-combine-upright, we may have collapsed the frame height,
6372+
// so we instead use 1em to ensure the selection is visible.
6373+
nscoord height = Style()->IsTextCombined()
6374+
? aParams.provider->GetFontMetrics()->EmHeight()
6375+
: GetSize().height;
63556376
bgRect = nsRect(nscoord(aParams.framePt.x + offs),
6356-
nscoord(aParams.framePt.y), nscoord(advance),
6357-
GetSize().height);
6377+
nscoord(aParams.framePt.y), nscoord(advance), height);
63586378
}
63596379

63606380
LayoutDeviceRect selectionRect =
@@ -7158,7 +7178,7 @@ void nsTextFrame::DrawTextRunAndDecorations(
71587178
// we need to revert the scaling here.
71597179
gfxContextMatrixAutoSaveRestore scaledRestorer;
71607180
if (Style()->IsTextCombined()) {
7161-
float scaleFactor = GetTextCombineScaleFactor(this);
7181+
float scaleFactor = GetTextCombineScale();
71627182
if (scaleFactor != 1.0f) {
71637183
scaledRestorer.SetContext(aParams.context);
71647184
gfxMatrix unscaled = aParams.context->CurrentMatrixDouble();
@@ -7414,7 +7434,7 @@ nsIFrame::ContentOffsets nsTextFrame::GetCharacterOffsetAtFramePointInternal(
74147434
? (mTextRun->IsInlineReversed() ? mRect.height - aPoint.y : aPoint.y)
74157435
: (mTextRun->IsInlineReversed() ? mRect.width - aPoint.x : aPoint.x);
74167436
if (Style()->IsTextCombined()) {
7417-
width /= GetTextCombineScaleFactor(this);
7437+
width /= GetTextCombineScale();
74187438
}
74197439
gfxFloat fitWidth;
74207440
Range skippedRange = ComputeTransformedRange(provider);
@@ -7722,7 +7742,7 @@ nsPoint nsTextFrame::GetPointFromIterator(const gfxSkipCharsIterator& aIter,
77227742
} else {
77237743
point.y = 0;
77247744
if (Style()->IsTextCombined()) {
7725-
iSize *= GetTextCombineScaleFactor(this);
7745+
iSize *= GetTextCombineScale();
77267746
}
77277747
if (mTextRun->IsInlineReversed()) {
77287748
point.x = mRect.width - iSize;
@@ -7851,7 +7871,7 @@ nsresult nsTextFrame::GetCharacterRectsInRange(int32_t aInOffset,
78517871
if (Style()->IsTextCombined()) {
78527872
// The scale factor applies to the inline advance of the glyphs, so it
78537873
// affects both the rect width and the origin point for the next glyph.
7854-
iSize *= GetTextCombineScaleFactor(this);
7874+
iSize *= GetTextCombineScale();
78557875
}
78567876
rect.width = iSize;
78577877
rect.height = mRect.height;
@@ -8883,12 +8903,15 @@ void nsTextFrame::AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
88838903
uint32_t start = FindStartAfterSkippingWhitespace(&provider, aData, textStyle,
88848904
&iter, flowEndInTextRun);
88858905

8886-
// text-combine-upright frame is constantly 1em on inline-axis.
8906+
// text-combine-upright frame is constantly 1em on inline-axis; but if it has
8907+
// a following sibling with the same style, it contributes nothing.
88878908
if (Style()->IsTextCombined()) {
88888909
if (start < flowEndInTextRun && textRun->CanBreakLineBefore(start)) {
88898910
aData->OptionallyBreak();
88908911
}
8891-
aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
8912+
if (!GetNextSibling() || GetNextSibling()->Style() != Style()) {
8913+
aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
8914+
}
88928915
aData->mTrailingWhitespace = 0;
88938916
return;
88948917
}
@@ -9154,9 +9177,12 @@ void nsTextFrame::AddInlinePrefISizeForFlow(gfxContext* aRenderingContext,
91549177
PropertyProvider provider(textRun, textStyle, frag, this, iter, INT32_MAX,
91559178
nullptr, 0, aTextRunType, aData->mLineIsEmpty);
91569179

9157-
// text-combine-upright frame is constantly 1em on inline-axis.
9180+
// text-combine-upright frame is constantly 1em on inline-axis, or zero if
9181+
// there is a following sibling with the same style.
91589182
if (Style()->IsTextCombined()) {
9159-
aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
9183+
if (!GetNextSibling() || GetNextSibling()->Style() != Style()) {
9184+
aData->mCurrentLine += provider.GetFontMetrics()->EmHeight();
9185+
}
91609186
aData->mTrailingWhitespace = 0;
91619187
aData->mLineIsEmpty = false;
91629188
return;
@@ -10159,30 +10185,88 @@ void nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
1015910185
nscoord width = finalSize.ISize(wm);
1016010186
nscoord em = fm->EmHeight();
1016110187
// Compress the characters in horizontal axis if necessary.
10162-
if (width <= em) {
10163-
RemoveProperty(TextCombineScaleFactorProperty());
10164-
} else {
10165-
SetProperty(TextCombineScaleFactorProperty(),
10166-
static_cast<float>(em) / static_cast<float>(width));
10167-
finalSize.ISize(wm) = em;
10168-
}
10169-
// Make the characters be in an 1em square.
10188+
auto* data = GetProperty(TextCombineDataProperty());
10189+
if (!data) {
10190+
data = new TextCombineData;
10191+
SetProperty(TextCombineDataProperty(), data);
10192+
}
10193+
data->mNaturalWidth = width;
10194+
finalSize.ISize(wm) = em;
10195+
// If we're going to have to adjust the block-size to make it 1em, make an
10196+
// appropriate adjustment to the font baseline (determined by the ascent
10197+
// returned in aMetrics)
1017010198
if (finalSize.BSize(wm) != em) {
1017110199
fontBaseline =
1017210200
aMetrics.BlockStartAscent() + (em - finalSize.BSize(wm)) / 2;
1017310201
aMetrics.SetBlockStartAscent(fontBaseline);
10202+
}
10203+
// If we have a next-in-flow with the same style, remove our block-size
10204+
// so that they end up beside each other; only the last in the series
10205+
// gets to keep its block-axis size.
10206+
if (GetNextSibling() && GetNextSibling()->Style() == Style()) {
10207+
finalSize.BSize(wm) = 0;
10208+
} else {
10209+
// Make the characters be in an 1em square.
1017410210
finalSize.BSize(wm) = em;
1017510211
}
10212+
// If there are earlier sibling frames with the same style, and we have
10213+
// reached the end of the run of same-style siblings, recompute the scale
10214+
// as necessary to make them all fit. (This is a bit inefficient, but is
10215+
// such a rare case that we don't much care.)
10216+
nsIFrame* f = GetPrevSibling();
10217+
if (f && f->Style() == Style() &&
10218+
(!GetNextSibling() || GetNextSibling()->Style() != Style())) {
10219+
// Collect the total "natural" width of the text.
10220+
while (f->Style() == Style()) {
10221+
if (auto* fData = f->GetProperty(TextCombineDataProperty())) {
10222+
width += fData->mNaturalWidth;
10223+
}
10224+
if (!f->GetPrevSibling()) {
10225+
break;
10226+
}
10227+
f = f->GetPrevSibling();
10228+
}
10229+
} else {
10230+
// Not at the end of a run of frames; we're just going to handle `this`.
10231+
f = this;
10232+
}
10233+
// Figure out scaling to apply to this frame (or to the run of same-style
10234+
// sibling frames), and the starting offset within the em square.
10235+
float scale;
10236+
nscoord offset;
10237+
if (width > em) {
10238+
scale = static_cast<float>(em) / width;
10239+
offset = 0;
10240+
} else {
10241+
scale = 1.0f;
10242+
offset = (em - width) / 2;
10243+
}
10244+
while (true) {
10245+
if (auto* fData = f->GetProperty(TextCombineDataProperty())) {
10246+
fData->mScale = scale;
10247+
fData->mOffset = offset;
10248+
offset += fData->mNaturalWidth * scale;
10249+
}
10250+
if (f == this) {
10251+
break;
10252+
}
10253+
f = f->GetNextSibling();
10254+
}
1017610255
}
1017710256
aMetrics.SetSize(wm, finalSize);
1017810257

1017910258
NS_ASSERTION(aMetrics.BlockStartAscent() >= 0, "Negative ascent???");
10180-
NS_ASSERTION(
10259+
// The effective "descent" here will be negative in the case of a frame that
10260+
// is participating in text-combine-upright, but is not the last frame within
10261+
// the combined upright cell, because we zero out its block-size (see above).
10262+
// So this creates an exception to the non-negative assertion here.
10263+
DebugOnly<nscoord> descent =
1018110264
(Style()->IsTextCombined() ? aMetrics.ISize(aMetrics.GetWritingMode())
1018210265
: aMetrics.BSize(aMetrics.GetWritingMode())) -
10183-
aMetrics.BlockStartAscent() >=
10184-
0,
10185-
"Negative descent???");
10266+
aMetrics.BlockStartAscent();
10267+
NS_ASSERTION(descent >= 0 || (Style()->IsTextCombined() && GetNextSibling() &&
10268+
GetNextSibling()->Style() == Style()),
10269+
"Unexpected negative descent???");
1018610270

1018710271
mAscent = fontBaseline;
1018810272

layout/generic/nsTextFrame.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,8 @@ class nsTextFrame : public nsIFrame {
10541054
ContentOffsets GetCharacterOffsetAtFramePointInternal(
10551055
const nsPoint& aPoint, bool aForInsertionPoint);
10561056

1057-
static float GetTextCombineScaleFactor(nsTextFrame* aFrame);
1057+
float GetTextCombineScale() const;
1058+
std::pair<nscoord, float> GetTextCombineOffsetAndScale() const;
10581059

10591060
void ClearFrameOffsetCache();
10601061

layout/painting/nsDisplayList.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7780,8 +7780,15 @@ void nsDisplayText::RenderToContext(gfxContext* aCtx,
77807780

77817781
nsPoint framePt = ToReferenceFrame();
77827782
if (f->Style()->IsTextCombined()) {
7783-
float scaleFactor = nsTextFrame::GetTextCombineScaleFactor(f);
7784-
if (scaleFactor != 1.0f) {
7783+
auto [offset, scale] = f->GetTextCombineOffsetAndScale();
7784+
gfxTextRun* textRun = f->GetTextRun(nsTextFrame::eInflated);
7785+
bool rtl = textRun && textRun->IsRightToLeft();
7786+
if (rtl) {
7787+
framePt.x -= offset;
7788+
} else {
7789+
framePt.x += offset;
7790+
}
7791+
if (scale != 1.0f) {
77857792
if (auto* textDrawer = aCtx->GetTextDrawer()) {
77867793
// WebRender doesn't support scaling text like this yet
77877794
textDrawer->FoundUnsupportedFeature();
@@ -7792,13 +7799,12 @@ void nsDisplayText::RenderToContext(gfxContext* aCtx,
77927799
// necessary. This is done here because we want selection be
77937800
// compressed at the same time as text.
77947801
gfxPoint pt = nsLayoutUtils::PointToGfxPoint(framePt, A2D);
7795-
gfxTextRun* textRun = f->GetTextRun(nsTextFrame::eInflated);
7796-
if (textRun && textRun->IsRightToLeft()) {
7802+
if (rtl) {
77977803
pt.x += gfxFloat(f->GetSize().width) / A2D;
77987804
}
77997805
gfxMatrix mat = aCtx->CurrentMatrixDouble()
78007806
.PreTranslate(pt)
7801-
.PreScale(scaleFactor, 1.0)
7807+
.PreScale(scale, 1.0)
78027808
.PreTranslate(-pt);
78037809
aCtx->SetMatrixDouble(mat);
78047810
}

0 commit comments

Comments
 (0)