--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -2890,17 +2890,16 @@ public:
mLineContainer(aLineContainer),
mFrame(aFrame), mStart(aStart), mTempIterator(aStart),
mTabWidths(nullptr), mTabWidthsAnalyzedLimit(0),
mLength(aLength),
mWordSpacing(WordSpacing(aFrame, mTextRun, aTextStyle)),
mLetterSpacing(LetterSpacing(aFrame, aTextStyle)),
mHyphenWidth(-1),
mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs),
- mJustificationSpacing(0),
mReflowing(true),
mWhichTextRun(aWhichTextRun)
{
NS_ASSERTION(mStart.IsInitialized(), "Start not initialized?");
}
/**
* Use this constructor after the frame has been reflowed and we don't
@@ -2915,17 +2914,16 @@ public:
mLineContainer(nullptr),
mFrame(aFrame), mStart(aStart), mTempIterator(aStart),
mTabWidths(nullptr), mTabWidthsAnalyzedLimit(0),
mLength(aFrame->GetContentLength()),
mWordSpacing(WordSpacing(aFrame, mTextRun)),
mLetterSpacing(LetterSpacing(aFrame)),
mHyphenWidth(-1),
mOffsetFromBlockOriginForTabs(0),
- mJustificationSpacing(0),
mReflowing(false),
mWhichTextRun(aWhichTextRun)
{
NS_ASSERTION(mTextRun, "Textrun not initialized!");
}
// Call this after construction if you're not going to reflow the text
void InitializeForDisplay(bool aTrimAfter);
@@ -2945,20 +2943,21 @@ public:
virtual uint32_t GetAppUnitsPerDevUnit() {
return mTextRun->GetAppUnitsPerDevUnit();
}
void GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs);
/**
- * Compute the justification information in given DOM range, and fill data
- * necessary for computation of spacing.
+ * Compute the justification information in given DOM range, return
+ * justification info and assignments if requested.
*/
- void ComputeJustification(Range aRange);
+ JustificationInfo ComputeJustification(
+ Range aRange, nsTArray<JustificationAssignment>* aAssignments = nullptr);
const nsStyleText* StyleText() { return mTextStyle; }
nsTextFrame* GetFrame() { return mFrame; }
// This may not be equal to the frame offset/length in because we may have
// adjusted for whitespace trimming according to the state bits set in the frame
// (for the static provider)
const gfxSkipCharsIterator& GetStart() { return mStart; }
// May return INT32_MAX if that was given to the constructor
@@ -2979,21 +2978,16 @@ public:
InitFontGroupAndFontMetrics();
return mFontMetrics;
}
void CalcTabWidths(Range aTransformedRange);
const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; }
- const JustificationInfo& GetJustificationInfo() const
- {
- return mJustificationInfo;
- }
-
protected:
void SetupJustificationSpacing(bool aPostReflow);
void InitFontGroupAndFontMetrics() {
float inflation = (mWhichTextRun == nsTextFrame::eInflated)
? mFrame->GetFontSizeInflation() : 1.0f;
mFontGroup = GetFontGroupForFrame(mFrame, inflation,
getter_AddRefs(mFontMetrics));
@@ -3017,24 +3011,20 @@ protected:
uint32_t mTabWidthsAnalyzedLimit;
int32_t mLength; // DOM string length, may be INT32_MAX
gfxFloat mWordSpacing; // space for each whitespace char
gfxFloat mLetterSpacing; // space for each letter
gfxFloat mHyphenWidth;
gfxFloat mOffsetFromBlockOriginForTabs;
- // The total spacing for justification
- gfxFloat mJustificationSpacing;
- int32_t mTotalJustificationGaps;
- JustificationInfo mJustificationInfo;
- // The values in mJustificationAssignments corresponds to unskipped
+ // The values in mJustificationSpacings corresponds to unskipped
// characters start from mJustificationArrayStart.
uint32_t mJustificationArrayStart;
- nsTArray<JustificationAssignment> mJustificationAssignments;
+ nsTArray<Spacing> mJustificationSpacings;
bool mReflowing;
nsTextFrame::TextRunType mWhichTextRun;
};
/**
* Finds the offset of the first character of the cluster containing aPos
*/
@@ -3069,90 +3059,96 @@ static void FindClusterEnd(gfxTextRun* a
aTextRun->IsLigatureGroupStart(aPos->GetSkippedOffset())))) {
break;
}
aPos->AdvanceOriginal(1);
}
aPos->AdvanceOriginal(-1);
}
-void
-PropertyProvider::ComputeJustification(Range aRange)
-{
+JustificationInfo
+PropertyProvider::ComputeJustification(
+ Range aRange, nsTArray<JustificationAssignment>* aAssignments)
+{
+ JustificationInfo info;
+
// Horizontal-in-vertical frame is orthogonal to the line, so it
// doesn't actually include any justification opportunity inside.
// The spec says such frame should be treated as a U+FFFC. Since we
// do not insert justification opportunities on the sides of that
// character, the sides of this frame are not justifiable either.
if (mFrame->StyleContext()->IsTextCombined()) {
- return;
+ return info;
}
bool isCJ = IsChineseOrJapanese(mFrame);
nsSkipCharsRunIterator run(
mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aRange.Length());
run.SetOriginalOffset(aRange.start);
mJustificationArrayStart = run.GetSkippedOffset();
- MOZ_ASSERT(mJustificationAssignments.IsEmpty());
- mJustificationAssignments.SetCapacity(aRange.Length());
+ nsTArray<JustificationAssignment> assignments;
+ assignments.SetCapacity(aRange.Length());
while (run.NextRun()) {
uint32_t originalOffset = run.GetOriginalOffset();
uint32_t skippedOffset = run.GetSkippedOffset();
uint32_t length = run.GetRunLength();
- mJustificationAssignments.SetLength(
- skippedOffset + length - mJustificationArrayStart);
+ assignments.SetLength(skippedOffset + length - mJustificationArrayStart);
gfxSkipCharsIterator iter = run.GetPos();
for (uint32_t i = 0; i < length; ++i) {
uint32_t offset = originalOffset + i;
if (!IsJustifiableCharacter(mFrag, offset, isCJ)) {
continue;
}
iter.SetOriginalOffset(offset);
FindClusterStart(mTextRun, originalOffset, &iter);
uint32_t firstCharOffset = iter.GetSkippedOffset();
uint32_t firstChar = firstCharOffset > mJustificationArrayStart ?
firstCharOffset - mJustificationArrayStart : 0;
if (!firstChar) {
- mJustificationInfo.mIsStartJustifiable = true;
+ info.mIsStartJustifiable = true;
} else {
- auto& assign = mJustificationAssignments[firstChar];
- auto& prevAssign = mJustificationAssignments[firstChar - 1];
+ auto& assign = assignments[firstChar];
+ auto& prevAssign = assignments[firstChar - 1];
if (prevAssign.mGapsAtEnd) {
prevAssign.mGapsAtEnd = 1;
assign.mGapsAtStart = 1;
} else {
assign.mGapsAtStart = 2;
- mJustificationInfo.mInnerOpportunities++;
+ info.mInnerOpportunities++;
}
}
FindClusterEnd(mTextRun, originalOffset + length, &iter);
uint32_t lastChar = iter.GetSkippedOffset() - mJustificationArrayStart;
// Assign the two gaps temporary to the last char. If the next cluster is
// justifiable as well, one of the gaps will be removed by code above.
- mJustificationAssignments[lastChar].mGapsAtEnd = 2;
- mJustificationInfo.mInnerOpportunities++;
+ assignments[lastChar].mGapsAtEnd = 2;
+ info.mInnerOpportunities++;
// Skip the whole cluster
i = iter.GetOriginalOffset() - originalOffset;
}
}
- if (!mJustificationAssignments.IsEmpty() &&
- mJustificationAssignments.LastElement().mGapsAtEnd) {
+ if (!assignments.IsEmpty() && assignments.LastElement().mGapsAtEnd) {
// We counted the expansion opportunity after the last character,
// but it is not an inner opportunity.
- MOZ_ASSERT(mJustificationInfo.mInnerOpportunities > 0);
- mJustificationInfo.mInnerOpportunities--;
- mJustificationInfo.mIsEndJustifiable = true;
- }
+ MOZ_ASSERT(info.mInnerOpportunities > 0);
+ info.mInnerOpportunities--;
+ info.mIsEndJustifiable = true;
+ }
+
+ if (aAssignments) {
+ *aAssignments = Move(assignments);
+ }
+ return info;
}
// aStart, aLength in transformed string offsets
void
PropertyProvider::GetSpacing(Range aRange, Spacing* aSpacing)
{
GetSpacingInternal(aRange, aSpacing,
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TAB) == 0);
@@ -3224,32 +3220,30 @@ PropertyProvider::GetSpacingInternal(Ran
if (mTabWidths) {
mTabWidths->ApplySpacing(aSpacing,
aRange.start - mStart.GetSkippedOffset(),
aRange.Length());
}
}
// Now add in justification spacing
- if (mJustificationSpacing > 0 && mTotalJustificationGaps) {
+ if (mJustificationSpacings.Length() > 0) {
// If there is any spaces trimmed at the end, aStart + aLength may
// be larger than the flags array. When that happens, we can simply
// ignore those spaces.
auto arrayEnd = mJustificationArrayStart +
- static_cast<uint32_t>(mJustificationAssignments.Length());
+ static_cast<uint32_t>(mJustificationSpacings.Length());
auto end = std::min(aRange.end, arrayEnd);
MOZ_ASSERT(aRange.start >= mJustificationArrayStart);
- JustificationApplicationState state(
- mTotalJustificationGaps, NSToCoordRound(mJustificationSpacing));
for (auto i = aRange.start; i < end; i++) {
- const auto& assign =
- mJustificationAssignments[i - mJustificationArrayStart];
+ const auto& spacing =
+ mJustificationSpacings[i - mJustificationArrayStart];
uint32_t offset = i - aRange.start;
- aSpacing[offset].mBefore += state.Consume(assign.mGapsAtStart);
- aSpacing[offset].mAfter += state.Consume(assign.mGapsAtEnd);
+ aSpacing[offset].mBefore += spacing.mBefore;
+ aSpacing[offset].mAfter += spacing.mAfter;
}
}
}
static gfxFloat
ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
{
// Get the number of spaces from CSS -moz-tab-size
@@ -3450,45 +3444,56 @@ PropertyProvider::SetupJustificationSpac
gfxSkipCharsIterator start(mStart), end(mStart);
// We can't just use our mLength here; when InitializeForDisplay is
// called with false for aTrimAfter, we still shouldn't be assigning
// justification space to any trailing whitespace.
nsTextFrame::TrimmedOffsets trimmed =
mFrame->GetTrimmedOffsets(mFrag, true, aPostReflow);
end.AdvanceOriginal(trimmed.mLength);
gfxSkipCharsIterator realEnd(end);
- ComputeJustification(Range(uint32_t(start.GetOriginalOffset()),
- uint32_t(end.GetOriginalOffset())));
+
+ Range range(uint32_t(start.GetOriginalOffset()),
+ uint32_t(end.GetOriginalOffset()));
+ nsTArray<JustificationAssignment> assignments;
+ JustificationInfo info = ComputeJustification(range, &assignments);
auto assign = mFrame->GetJustificationAssignment();
- mTotalJustificationGaps =
- JustificationUtils::CountGaps(mJustificationInfo, assign);
- if (!mTotalJustificationGaps || mJustificationAssignments.IsEmpty()) {
+ auto totalGaps = JustificationUtils::CountGaps(info, assign);
+ if (!totalGaps || assignments.IsEmpty()) {
// Nothing to do, nothing is justifiable and we shouldn't have any
// justification space assigned
return;
}
// Remember that textrun measurements are in the run's orientation,
// so its advance "width" is actually a height in vertical writing modes,
// corresponding to the inline-direction of the frame.
gfxFloat naturalWidth =
mTextRun->GetAdvanceWidth(Range(mStart.GetSkippedOffset(),
realEnd.GetSkippedOffset()), this);
if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) {
naturalWidth += GetHyphenWidth();
}
- mJustificationSpacing = mFrame->ISize() - naturalWidth;
- if (mJustificationSpacing <= 0) {
+ nscoord totalSpacing = mFrame->ISize() - naturalWidth;
+ if (totalSpacing <= 0) {
// No space available
return;
}
- mJustificationAssignments[0].mGapsAtStart = assign.mGapsAtStart;
- mJustificationAssignments.LastElement().mGapsAtEnd = assign.mGapsAtEnd;
+ assignments[0].mGapsAtStart = assign.mGapsAtStart;
+ assignments.LastElement().mGapsAtEnd = assign.mGapsAtEnd;
+
+ MOZ_ASSERT(mJustificationSpacings.IsEmpty());
+ JustificationApplicationState state(totalGaps, totalSpacing);
+ mJustificationSpacings.SetCapacity(assignments.Length());
+ for (const JustificationAssignment& assign : assignments) {
+ Spacing* spacing = mJustificationSpacings.AppendElement();
+ spacing->mBefore = state.Consume(assign.mGapsAtStart);
+ spacing->mAfter = state.Consume(assign.mGapsAtEnd);
+ }
}
//----------------------------------------------------------------------
static nscolor
EnsureDifferentColors(nscolor colorA, nscolor colorB)
{
if (colorA == colorB) {
@@ -9129,19 +9134,18 @@ nsTextFrame::ReflowText(nsLineLayout& aL
// Compute space and letter counts for justification, if required
if (!textStyle->WhiteSpaceIsSignificant() &&
(lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
shouldSuppressLineBreak) &&
!lineContainer->IsSVGText()) {
AddStateBits(TEXT_JUSTIFICATION_ENABLED);
- provider.ComputeJustification(Range(uint32_t(offset),
- uint32_t(offset + charsFit)));
- aLineLayout.SetJustificationInfo(provider.GetJustificationInfo());
+ Range range(uint32_t(offset), uint32_t(offset + charsFit));
+ aLineLayout.SetJustificationInfo(provider.ComputeJustification(range));
}
SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION);
InvalidateFrame();
#ifdef NOISY_REFLOW
ListTag(stdout);