mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
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:
parent
959c2ec0d0
commit
6599844c53
@ -186,10 +186,14 @@ gfxSkipCharsIterator::IsOriginalCharSkipped(PRInt32* aRunLength) const
|
|||||||
|
|
||||||
// figure out which segment we're in
|
// figure out which segment we're in
|
||||||
PRUint32 currentRunLength = mSkipChars->mList[mListPrefixLength];
|
PRUint32 currentRunLength = mSkipChars->mList[mListPrefixLength];
|
||||||
|
NS_ASSERTION(PRUint32(mOriginalStringOffset) >= mListPrefixCharCount,
|
||||||
|
"Invariant violation");
|
||||||
|
PRUint32 offsetIntoCurrentRun =
|
||||||
|
PRUint32(mOriginalStringOffset) - mListPrefixCharCount;
|
||||||
if (mListPrefixLength >= mSkipChars->mListLength - 1 &&
|
if (mListPrefixLength >= mSkipChars->mListLength - 1 &&
|
||||||
PRUint32(mOriginalStringOffset) >= mListPrefixCharCount + currentRunLength) {
|
offsetIntoCurrentRun >= currentRunLength) {
|
||||||
NS_ASSERTION(mListPrefixLength == mSkipChars->mListLength - 1 &&
|
NS_ASSERTION(mListPrefixLength == mSkipChars->mListLength - 1 &&
|
||||||
PRUint32(mOriginalStringOffset) == mListPrefixCharCount + currentRunLength,
|
offsetIntoCurrentRun == currentRunLength,
|
||||||
"Overran end of string");
|
"Overran end of string");
|
||||||
// We're at the end of the string
|
// We're at the end of the string
|
||||||
if (aRunLength) {
|
if (aRunLength) {
|
||||||
@ -203,12 +207,13 @@ gfxSkipCharsIterator::IsOriginalCharSkipped(PRInt32* aRunLength) const
|
|||||||
// Long runs of all-skipped or all-kept characters will be encoded as
|
// 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
|
// sequences of 255, 0, 255, 0 etc. Compute the maximum run length by skipping
|
||||||
// over zero entries.
|
// over zero entries.
|
||||||
for (PRUint32 i = mListPrefixLength + 2; i < mSkipChars->mListLength; ++i) {
|
PRUint32 runLength = currentRunLength - offsetIntoCurrentRun;
|
||||||
if (isSkipped == !IsKeepEntry(i) && mSkipChars->mList[i - 1] == 0) {
|
for (PRUint32 i = mListPrefixLength + 2; i < mSkipChars->mListLength; i += 2) {
|
||||||
currentRunLength += mSkipChars->mList[i];
|
if (mSkipChars->mList[i - 1] != 0)
|
||||||
}
|
break;
|
||||||
|
runLength += mSkipChars->mList[i];
|
||||||
}
|
}
|
||||||
*aRunLength = currentRunLength;
|
*aRunLength = runLength;
|
||||||
}
|
}
|
||||||
return isSkipped;
|
return isSkipped;
|
||||||
}
|
}
|
||||||
|
@ -1155,7 +1155,7 @@ GetFontGroupForFrame(nsIFrame* aFrame)
|
|||||||
nsCOMPtr<nsIFontMetrics> metrics;
|
nsCOMPtr<nsIFontMetrics> metrics;
|
||||||
devContext->GetMetricsFor(fontStyle->mFont, visibilityStyle->mLangGroup,
|
devContext->GetMetricsFor(fontStyle->mFont, visibilityStyle->mLangGroup,
|
||||||
*getter_AddRefs(metrics));
|
*getter_AddRefs(metrics));
|
||||||
if (!metrics)
|
if (!metrics)
|
||||||
return nsnull;
|
return nsnull;
|
||||||
|
|
||||||
nsIFontMetrics* metricsRaw = metrics;
|
nsIFontMetrics* metricsRaw = metrics;
|
||||||
@ -1679,7 +1679,9 @@ static PRBool IsJustifiableCharacter(const nsTextFragment* aFrag, PRInt32 aPos,
|
|||||||
PRBool aLangIsCJ)
|
PRBool aLangIsCJ)
|
||||||
{
|
{
|
||||||
PRUnichar ch = aFrag->CharAt(aPos);
|
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
|
// Don't justify spaces that are combined with diacriticals
|
||||||
if (!aFrag->Is2b())
|
if (!aFrag->Is2b())
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
@ -2085,7 +2087,7 @@ PropertyProvider::GetHyphenationBreaks(PRUint32 aStart, PRUint32 aLength,
|
|||||||
|
|
||||||
// Iterate through the original-string character runs
|
// Iterate through the original-string character runs
|
||||||
nsSkipCharsRunIterator
|
nsSkipCharsRunIterator
|
||||||
run(mStart, nsSkipCharsRunIterator::LENGTH_INCLUDES_SKIPPED, aLength);
|
run(mStart, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aLength);
|
||||||
run.SetSkippedOffset(aStart);
|
run.SetSkippedOffset(aStart);
|
||||||
// We need to visit skipped characters so that we can detect SHY
|
// We need to visit skipped characters so that we can detect SHY
|
||||||
run.SetVisitSkipped();
|
run.SetVisitSkipped();
|
||||||
@ -2167,6 +2169,14 @@ PropertyProvider::SetupJustificationSpacing()
|
|||||||
gfxFloat naturalWidth =
|
gfxFloat naturalWidth =
|
||||||
mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(),
|
mTextRun->GetAdvanceWidth(mStart.GetSkippedOffset(),
|
||||||
GetSkippedDistance(mStart, realEnd), this);
|
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;
|
gfxFloat totalJustificationSpace = mFrame->GetSize().width - naturalWidth;
|
||||||
if (totalJustificationSpace <= 0) {
|
if (totalJustificationSpace <= 0) {
|
||||||
// No space available
|
// No space available
|
||||||
@ -3481,43 +3491,39 @@ SelectionIterator::SelectionIterator(SelectionType* aSelectionBuffer,
|
|||||||
PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
|
PRBool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
|
||||||
PRUint32* aOffset, PRUint32* aLength, gfxFloat* aHyphenWidth, SelectionType* aType)
|
PRUint32* aOffset, PRUint32* aLength, gfxFloat* aHyphenWidth, SelectionType* aType)
|
||||||
{
|
{
|
||||||
for (;;) {
|
if (mIterator.GetOriginalOffset() >= mOriginalEnd)
|
||||||
if (mIterator.GetOriginalOffset() >= mOriginalEnd)
|
return PR_FALSE;
|
||||||
return PR_FALSE;
|
|
||||||
|
|
||||||
// save offset into transformed string now
|
// save offset into transformed string now
|
||||||
PRUint32 runOffset = mIterator.GetSkippedOffset();
|
PRUint32 runOffset = mIterator.GetSkippedOffset();
|
||||||
|
|
||||||
PRInt32 index = mIterator.GetOriginalOffset() - mOriginalStart;
|
PRInt32 index = mIterator.GetOriginalOffset() - mOriginalStart;
|
||||||
SelectionType type = mSelectionBuffer[index];
|
SelectionType type = mSelectionBuffer[index];
|
||||||
do {
|
do {
|
||||||
++index;
|
++index;
|
||||||
if (mSelectionBuffer[index] != type)
|
if (mSelectionBuffer[index] != type)
|
||||||
break;
|
break;
|
||||||
} while (mOriginalStart + index < mOriginalEnd);
|
} while (mOriginalStart + index < mOriginalEnd);
|
||||||
mIterator.SetOriginalOffset(index + mOriginalStart);
|
mIterator.SetOriginalOffset(index + mOriginalStart);
|
||||||
|
|
||||||
// Advance to the next cluster boundary
|
// Advance to the next cluster boundary
|
||||||
while (mIterator.GetOriginalOffset() < mOriginalEnd &&
|
while (mIterator.GetOriginalOffset() < mOriginalEnd &&
|
||||||
!mIterator.IsOriginalCharSkipped() &&
|
!mIterator.IsOriginalCharSkipped() &&
|
||||||
!mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) {
|
!mTextRun->IsClusterStart(mIterator.GetSkippedOffset())) {
|
||||||
mIterator.AdvanceOriginal(1);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// 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);
|
PRInt32 startOffset = mContentOffset + (*aOffset < 0 ? mContentLength : *aOffset);
|
||||||
|
|
||||||
if (!aForward) {
|
if (!aForward) {
|
||||||
*aOffset = 0;
|
|
||||||
PRInt32 i;
|
PRInt32 i;
|
||||||
for (i = PR_MIN(trimmed.mStart + trimmed.mLength, startOffset) - 1;
|
for (i = PR_MIN(trimmed.mStart + trimmed.mLength, startOffset) - 1;
|
||||||
i >= trimmed.mStart; --i) {
|
i >= trimmed.mStart; --i) {
|
||||||
@ -4151,20 +4156,22 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*aOffset = 0;
|
||||||
} else {
|
} else {
|
||||||
*aOffset = mContentLength;
|
|
||||||
PRInt32 i;
|
PRInt32 i;
|
||||||
// XXX there's something weird here about end-of-line. Need to test
|
for (i = startOffset + 1; i <= trimmed.mStart + trimmed.mLength; ++i) {
|
||||||
// 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) {
|
|
||||||
iter.SetOriginalOffset(i);
|
iter.SetOriginalOffset(i);
|
||||||
if (!iter.IsOriginalCharSkipped() &&
|
// XXX we can't necessarily stop at the end of this frame,
|
||||||
mTextRun->IsClusterStart(iter.GetSkippedOffset())) {
|
// 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;
|
*aOffset = i - mContentOffset;
|
||||||
return PR_TRUE;
|
return PR_TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*aOffset = mContentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
@ -4207,19 +4214,20 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool
|
|||||||
PRBool stopAfterPunctuation = nsTextTransformer::GetWordSelectStopAtPunctuation();
|
PRBool stopAfterPunctuation = nsTextTransformer::GetWordSelectStopAtPunctuation();
|
||||||
PRBool stopBeforePunctuation = stopAfterPunctuation && aIsKeyboardSelect;
|
PRBool stopBeforePunctuation = stopAfterPunctuation && aIsKeyboardSelect;
|
||||||
PRInt32 direction = aForward ? 1 : -1;
|
PRInt32 direction = aForward ? 1 : -1;
|
||||||
|
PRInt32 dirAdjust = aForward ? 0 : -1;
|
||||||
*aOffset = aForward ? mContentLength : 0;
|
*aOffset = aForward ? mContentLength : 0;
|
||||||
if (startOffset + direction < offset ||
|
if (startOffset + direction < offset ||
|
||||||
startOffset + direction >= offset + length)
|
startOffset + direction >= offset + length)
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
|
|
||||||
PRInt32 wordLen = nsTextFrameUtils::FindWordBoundary(frag,
|
PRInt32 wordLen = nsTextFrameUtils::FindWordBoundary(frag,
|
||||||
mTextRun, &iter, offset, length, startOffset + direction,
|
mTextRun, &iter, offset, length, startOffset + dirAdjust,
|
||||||
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace);
|
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace);
|
||||||
if (wordLen < 0)
|
if (wordLen < 0)
|
||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
|
|
||||||
if (aWordSelectEatSpace == isWhitespace || !*aSawBeforeType) {
|
if (aWordSelectEatSpace == isWhitespace || !*aSawBeforeType) {
|
||||||
PRInt32 nextWordFirstChar = startOffset + direction*wordLen;
|
PRInt32 nextWordFirstChar = startOffset + dirAdjust + direction*wordLen;
|
||||||
*aOffset = (aForward ? nextWordFirstChar : nextWordFirstChar + 1) - mContentOffset;
|
*aOffset = (aForward ? nextWordFirstChar : nextWordFirstChar + 1) - mContentOffset;
|
||||||
if (aWordSelectEatSpace == isWhitespace) {
|
if (aWordSelectEatSpace == isWhitespace) {
|
||||||
*aSawBeforeType = PR_TRUE;
|
*aSawBeforeType = PR_TRUE;
|
||||||
@ -4230,7 +4238,7 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool
|
|||||||
return PR_FALSE;
|
return PR_FALSE;
|
||||||
wordLen = nsTextFrameUtils::FindWordBoundary(frag,
|
wordLen = nsTextFrameUtils::FindWordBoundary(frag,
|
||||||
mTextRun, &iter, offset, length, nextWordFirstChar,
|
mTextRun, &iter, offset, length, nextWordFirstChar,
|
||||||
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace);
|
direction, stopBeforePunctuation, stopAfterPunctuation, &isWhitespace) - 1;
|
||||||
if (wordLen < 0 ||
|
if (wordLen < 0 ||
|
||||||
(aWordSelectEatSpace ? !isWhitespace : *aSawBeforeType))
|
(aWordSelectEatSpace ? !isWhitespace : *aSawBeforeType))
|
||||||
break;
|
break;
|
||||||
@ -4310,39 +4318,6 @@ FindFirstLetterRange(const nsTextFragment* aFrag,
|
|||||||
return PR_TRUE;
|
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)
|
static nsRect ConvertGfxRectOutward(const gfxRect& aRect)
|
||||||
{
|
{
|
||||||
nsRect r;
|
nsRect r;
|
||||||
@ -4553,6 +4528,39 @@ nsTextFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
|
|||||||
return nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
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
|
NS_IMETHODIMP
|
||||||
nsTextFrame::Reflow(nsPresContext* aPresContext,
|
nsTextFrame::Reflow(nsPresContext* aPresContext,
|
||||||
nsHTMLReflowMetrics& aMetrics,
|
nsHTMLReflowMetrics& aMetrics,
|
||||||
|
Loading…
Reference in New Issue
Block a user