зеркало из https://github.com/mozilla/pjs.git
Not part of the build (well, gfxSkipChars is built but not used): fix bugs in gfxSkipChars, and new textframe fixes for soft hyphens, justification, and caret movement (PeekOffset*) among other things
This commit is contained in:
Родитель
a31d2ddb34
Коммит
2dda45ed64
|
@ -186,10 +186,14 @@ gfxSkipCharsIterator::IsOriginalCharSkipped(PRInt32* aRunLength) const
|
|||
|
||||
// figure out which segment we're in
|
||||
PRUint32 currentRunLength = mSkipChars->mList[mListPrefixLength];
|
||||
NS_ASSERTION(PRUint32(mOriginalStringOffset) >= mListPrefixCharCount,
|
||||
"Invariant violation");
|
||||
PRUint32 offsetIntoCurrentRun =
|
||||
PRUint32(mOriginalStringOffset) - mListPrefixCharCount;
|
||||
if (mListPrefixLength >= mSkipChars->mListLength - 1 &&
|
||||
PRUint32(mOriginalStringOffset) >= mListPrefixCharCount + currentRunLength) {
|
||||
offsetIntoCurrentRun >= currentRunLength) {
|
||||
NS_ASSERTION(mListPrefixLength == mSkipChars->mListLength - 1 &&
|
||||
PRUint32(mOriginalStringOffset) == mListPrefixCharCount + currentRunLength,
|
||||
offsetIntoCurrentRun == currentRunLength,
|
||||
"Overran end of string");
|
||||
// We're at the end of the string
|
||||
if (aRunLength) {
|
||||
|
@ -203,12 +207,13 @@ gfxSkipCharsIterator::IsOriginalCharSkipped(PRInt32* aRunLength) const
|
|||
// Long runs of all-skipped or all-kept characters will be encoded as
|
||||
// sequences of 255, 0, 255, 0 etc. Compute the maximum run length by skipping
|
||||
// over zero entries.
|
||||
for (PRUint32 i = mListPrefixLength + 2; i < mSkipChars->mListLength; ++i) {
|
||||
if (isSkipped == !IsKeepEntry(i) && mSkipChars->mList[i - 1] == 0) {
|
||||
currentRunLength += mSkipChars->mList[i];
|
||||
}
|
||||
PRUint32 runLength = currentRunLength - offsetIntoCurrentRun;
|
||||
for (PRUint32 i = mListPrefixLength + 2; i < mSkipChars->mListLength; i += 2) {
|
||||
if (mSkipChars->mList[i - 1] != 0)
|
||||
break;
|
||||
runLength += mSkipChars->mList[i];
|
||||
}
|
||||
*aRunLength = currentRunLength;
|
||||
*aRunLength = runLength;
|
||||
}
|
||||
return isSkipped;
|
||||
}
|
||||
|
|
|
@ -1155,7 +1155,7 @@ GetFontGroupForFrame(nsIFrame* aFrame)
|
|||
nsCOMPtr<nsIFontMetrics> metrics;
|
||||
devContext->GetMetricsFor(fontStyle->mFont, visibilityStyle->mLangGroup,
|
||||
*getter_AddRefs(metrics));
|
||||
if (!metrics)
|
||||
if (!metrics)
|
||||
return nsnull;
|
||||
|
||||
nsIFontMetrics* metricsRaw = metrics;
|
||||
|
@ -1679,7 +1679,9 @@ static PRBool IsJustifiableCharacter(const nsTextFragment* aFrag, PRInt32 aPos,
|
|||
PRBool aLangIsCJ)
|
||||
{
|
||||
PRUnichar ch = aFrag->CharAt(aPos);
|
||||
if (0x20u == ch || 0xa0u == ch) {
|
||||
if (ch == '\n' || ch == '\t')
|
||||
return PR_TRUE;
|
||||
if (ch == ' ') {
|
||||
// Don't justify spaces that are combined with diacriticals
|
||||
if (!aFrag->Is2b())
|
||||
return PR_TRUE;
|
||||
|
@ -2085,7 +2087,7 @@ PropertyProvider::GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
|
|||
|
||||
// Iterate through the original-string character runs
|
||||
nsSkipCharsRunIterator
|
||||
run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength);
|
||||
run(mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
|
||||
run.SetSkippedOffset(aStart);
|
||||
// We need to visit skipped characters so that we can detect SHY
|
||||
run.SetVisitSkipped();
|
||||
|
@ -2167,6 +2169,14 @@ PropertyProvider::SetupJustificationSpacing()
|
|||
gfxFloat naturalWidth =
|
||||
mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(),
|
||||
GetSkippedDistance(mStart, realEnd), this);
|
||||
if (mFrame->GetStateBits() & TEXT_HYPHEN_BREAK) {
|
||||
gfxTextRun* specialTextRun =
|
||||
GetSpecialString(GetFontGroup(), gfxFontGroup::STRING_HYPHEN, mTextRun);
|
||||
if (specialTextRun) {
|
||||
naturalWidth +=
|
||||
specialTextRun->GetAdvanceWidth(0, specialTextRun->GetLength(), nsnull);
|
||||
}
|
||||
}
|
||||
gfxFloat totalJustificationSpace = mFrame->GetSize().width - naturalWidth;
|
||||
if (totalJustificationSpace <= 0) {
|
||||
// No space available
|
||||
|
@ -3481,43 +3491,39 @@ SelectionIterator::SelectionIterator(SelectionType* aSelectionBuffer,
|
|||
PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
|
||||
PRUint32* aOffset, PRUint32* aLength, gfxFloat* aHyphenWidth, SelectionType* aType)
|
||||
{
|
||||
for (;;) {
|
||||
if (mIterator.GetOriginalOffset() >= mOriginalEnd)
|
||||
return PR_FALSE;
|
||||
if (mIterator.GetOriginalOffset() >= mOriginalEnd)
|
||||
return PR_FALSE;
|
||||
|
||||
// save offset into transformed string now
|
||||
PRUint32 runOffset = mIterator.GetSkippedOffset();
|
||||
// save offset into transformed string now
|
||||
PRUint32 runOffset = mIterator.GetSkippedOffset();
|
||||
|
||||
PRInt32 index = mIterator.GetOriginalOffset() - mOriginalStart;
|
||||
SelectionType type = mSelectionBuffer[index];
|
||||
do {
|
||||
++index;
|
||||
if (mSelectionBuffer[index] != type)
|
||||
break;
|
||||
} while (mOriginalStart + index < mOriginalEnd);
|
||||
mIterator.SetOriginalOffset(index + mOriginalStart);
|
||||
PRInt32 index = mIterator.GetOriginalOffset() - mOriginalStart;
|
||||
SelectionType type = mSelectionBuffer[index];
|
||||
do {
|
||||
++index;
|
||||
if (mSelectionBuffer[index] != type)
|
||||
break;
|
||||
} while (mOriginalStart + index < mOriginalEnd);
|
||||
mIterator.SetOriginalOffset(index + mOriginalStart);
|
||||
|
||||
// Advance to the next cluster boundary
|
||||
while (mIterator.GetOriginalOffset() < mOriginalEnd &&
|
||||
!mIterator.IsOriginalCharSkipped() &&
|
||||
!mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) {
|
||||
mIterator.AdvanceOriginal(1);
|
||||
}
|
||||
|
||||
// Check whether we actually got some non-skipped text in this segment
|
||||
if (runOffset < mIterator.GetSkippedOffset()) {
|
||||
*aOffset = runOffset;
|
||||
*aLength = mIterator.GetSkippedOffset() - runOffset;
|
||||
*aXOffset = mXOffset;
|
||||
*aHyphenWidth = 0;
|
||||
if (mIterator.GetOriginalOffset() == mOriginalEnd &&
|
||||
(mProvider.GetFrame()->GetStateBits() & TEXT_HYPHEN_BREAK)) {
|
||||
*aHyphenWidth = mProvider.GetHyphenWidth();
|
||||
}
|
||||
*aType = type;
|
||||
return PR_TRUE;
|
||||
}
|
||||
// Advance to the next cluster boundary
|
||||
while (mIterator.GetOriginalOffset() < mOriginalEnd &&
|
||||
!mIterator.IsOriginalCharSkipped() &&
|
||||
!mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) {
|
||||
mIterator.AdvanceOriginal(1);
|
||||
}
|
||||
|
||||
PRBool haveHyphenBreak =
|
||||
(mProvider.GetFrame()->GetStateBits() & TEXT_HYPHEN_BREAK) != 0;
|
||||
*aOffset = runOffset;
|
||||
*aLength = mIterator.GetSkippedOffset() - runOffset;
|
||||
*aXOffset = mXOffset;
|
||||
*aHyphenWidth = 0;
|
||||
if (mIterator.GetOriginalOffset() == mOriginalEnd && haveHyphenBreak) {
|
||||
*aHyphenWidth = mProvider.GetHyphenWidth();
|
||||
}
|
||||
*aType = type;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// Paints selection backgrounds and text in the correct colors. Also computes
|
||||
|
@ -4140,7 +4146,6 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||
PRInt32 startOffset = mContentOffset + (*aOffset < 0 ? mContentLength : *aOffset);
|
||||
|
||||
if (!aForward) {
|
||||
*aOffset = 0;
|
||||
PRInt32 i;
|
||||
for (i = PR_MIN(trimmed.mStart + trimmed.mLength, startOffset) - 1;
|
||||
i >= trimmed.mStart; --i) {
|
||||
|
@ -4151,20 +4156,22 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
*aOffset = 0;
|
||||
} else {
|
||||
*aOffset = mContentLength;
|
||||
PRInt32 i;
|
||||
// XXX there's something weird here about end-of-line. Need to test
|
||||
// caret movement through line endings. The old code could return mContentLength,
|
||||
// but we can't anymore...
|
||||
for (i = startOffset; i < trimmed.mStart + trimmed.mLength; ++i) {
|
||||
for (i = startOffset + 1; i <= trimmed.mStart + trimmed.mLength; ++i) {
|
||||
iter.SetOriginalOffset(i);
|
||||
if (!iter.IsOriginalCharSkipped() &&
|
||||
mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
|
||||
// XXX we can't necessarily stop at the end of this frame,
|
||||
// but we really have no choice right now. We need to do a deeper
|
||||
// fix/restructuring of PeekOffsetCharacter
|
||||
if (i == trimmed.mStart + trimmed.mLength ||
|
||||
(!iter.IsOriginalCharSkipped() &&
|
||||
mTextRun->IsClusterStart(iter.GetSkippedOffset()))) {
|
||||
*aOffset = i - mContentOffset;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
*aOffset = mContentLength;
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
|
@ -4207,19 +4214,20 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool
|
|||
PRBool stopAfterPunctuation = nsTextTransformer::GetWordSelectStopAtPunctuation();
|
||||
PRBool stopBeforePunctuation = stopAfterPunctuation && aIsKeyboardSelect;
|
||||
PRInt32 direction = aForward ? 1 : -1;
|
||||
PRInt32 dirAdjust = aForward ? 0 : -1;
|
||||
*aOffset = aForward ? mContentLength : 0;
|
||||
if (startOffset + direction < offset ||
|
||||
startOffset + direction >= offset + length)
|
||||
return PR_FALSE;
|
||||
|
||||
PRInt32 wordLen = nsTextFrameUtils::FindWordBoundary(frag,
|
||||
mTextRun, &iter, offset, length, startOffset + direction,
|
||||
mTextRun, &iter, offset, length, startOffset + dirAdjust,
|
||||
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace);
|
||||
if (wordLen < 0)
|
||||
return PR_FALSE;
|
||||
|
||||
if (aWordSelectEatSpace == isWhitespace || !*aSawBeforeType) {
|
||||
PRInt32 nextWordFirstChar = startOffset + direction*wordLen;
|
||||
PRInt32 nextWordFirstChar = startOffset + dirAdjust + direction*wordLen;
|
||||
*aOffset = (aForward ? nextWordFirstChar : nextWordFirstChar + 1) - mContentOffset;
|
||||
if (aWordSelectEatSpace == isWhitespace) {
|
||||
*aSawBeforeType = PR_TRUE;
|
||||
|
@ -4230,7 +4238,7 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool
|
|||
return PR_FALSE;
|
||||
wordLen = nsTextFrameUtils::FindWordBoundary(frag,
|
||||
mTextRun, &iter, offset, length, nextWordFirstChar,
|
||||
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace);
|
||||
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace) - 1;
|
||||
if (wordLen < 0 ||
|
||||
(aWordSelectEatSpace ? !isWhitespace : *aSawBeforeType))
|
||||
break;
|
||||
|
@ -4310,39 +4318,6 @@ FindFirstLetterRange(const nsTextFragment* aFrag,
|
|||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
AddCharToMetrics(gfxFloat aWidth, PropertyProvider* aProvider,
|
||||
gfxFontGroup::SpecialString aSpecial, gfxTextRun* aTextRun,
|
||||
gfxTextRun::Metrics* aMetrics, PRBool aTightBoundingBox)
|
||||
{
|
||||
gfxRect charRect;
|
||||
if (aTightBoundingBox) {
|
||||
gfxTextRun* specialTextRun =
|
||||
GetSpecialString(aProvider->GetFontGroup(), aSpecial, aTextRun);
|
||||
gfxTextRun::Metrics charMetrics;
|
||||
if (specialTextRun) {
|
||||
charMetrics =
|
||||
specialTextRun->MeasureText(0, specialTextRun->GetLength(), PR_TRUE, nsnull);
|
||||
}
|
||||
charRect = charMetrics.mBoundingBox;
|
||||
} else {
|
||||
// assume char does not overflow font metrics!!!
|
||||
charRect = gfxRect(0, -aMetrics->mAscent, aWidth,
|
||||
aMetrics->mAscent + aMetrics->mDescent);
|
||||
}
|
||||
if (aTextRun->IsRightToLeft()) {
|
||||
// Char comes before text, so the bounding box is moved to the
|
||||
// right by aWidth
|
||||
aMetrics->mBoundingBox.MoveBy(gfxPoint(aWidth, 0));
|
||||
} else {
|
||||
// char is moved to the right by mAdvanceWidth
|
||||
charRect.MoveBy(gfxPoint(aMetrics->mAdvanceWidth, 0));
|
||||
}
|
||||
aMetrics->mBoundingBox = aMetrics->mBoundingBox.Union(charRect);
|
||||
|
||||
aMetrics->mAdvanceWidth += aWidth;
|
||||
}
|
||||
|
||||
static nsRect ConvertGfxRectOutward(const gfxRect& aRect)
|
||||
{
|
||||
nsRect r;
|
||||
|
@ -4553,6 +4528,39 @@ nsTextFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
|
|||
return nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
static void
|
||||
AddCharToMetrics(gfxFloat aWidth, PropertyProvider* aProvider,
|
||||
gfxFontGroup::SpecialString aSpecial, gfxTextRun* aTextRun,
|
||||
gfxTextRun::Metrics* aMetrics, PRBool aTightBoundingBox)
|
||||
{
|
||||
gfxRect charRect;
|
||||
if (aTightBoundingBox) {
|
||||
gfxTextRun* specialTextRun =
|
||||
GetSpecialString(aProvider->GetFontGroup(), aSpecial, aTextRun);
|
||||
gfxTextRun::Metrics charMetrics;
|
||||
if (specialTextRun) {
|
||||
charMetrics =
|
||||
specialTextRun->MeasureText(0, specialTextRun->GetLength(), PR_TRUE, nsnull);
|
||||
}
|
||||
charRect = charMetrics.mBoundingBox;
|
||||
} else {
|
||||
// assume char does not overflow font metrics!!!
|
||||
charRect = gfxRect(0, -aMetrics->mAscent, aWidth,
|
||||
aMetrics->mAscent + aMetrics->mDescent);
|
||||
}
|
||||
if (aTextRun->IsRightToLeft()) {
|
||||
// Char comes before text, so the bounding box is moved to the
|
||||
// right by aWidth
|
||||
aMetrics->mBoundingBox.MoveBy(gfxPoint(aWidth, 0));
|
||||
} else {
|
||||
// char is moved to the right by mAdvanceWidth
|
||||
charRect.MoveBy(gfxPoint(aMetrics->mAdvanceWidth, 0));
|
||||
}
|
||||
aMetrics->mBoundingBox = aMetrics->mBoundingBox.Union(charRect);
|
||||
|
||||
aMetrics->mAdvanceWidth += aWidth;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTextFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aMetrics,
|
||||
|
|
Загрузка…
Ссылка в новой задаче