зеркало из https://github.com/mozilla/pjs.git
Bug 392809. Break between whitespace and following punctuation even when stop_at_punctuation is false. Don't stop between punctuation and following non-punctuatino if the preceding punctuation follows white-space. r=smontagu
This commit is contained in:
Родитель
d6b06250be
Коммит
eb7da8df0c
|
@ -877,6 +877,8 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
}
|
||||
#endif
|
||||
|
||||
// See comment below about oldSize. Use *only* for the
|
||||
// abs-pos-containing-block-size-change optimization!
|
||||
nsSize oldSize = GetSize();
|
||||
|
||||
// Should we create a space manager?
|
||||
|
@ -1131,7 +1133,14 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext,
|
|||
// can use our rect (the border edge) since if the border style
|
||||
// changed, the reflow would have been targeted at us so we'd satisfy
|
||||
// condition 1.
|
||||
if (mAbsoluteContainer.HasAbsoluteFrames()) {
|
||||
// XXX checking oldSize is bogus, there are various reasons we might have
|
||||
// reflowed but our size might not have been changed to what we
|
||||
// asked for (e.g., we ended up being pushed to a new page)
|
||||
// Because of this, we must not reflow our abs-pos children if we will
|
||||
// reflow again due to a clearance change --- what we think is our "new size"
|
||||
// will not be our real new size. This also happens to be more efficient.
|
||||
if (mAbsoluteContainer.HasAbsoluteFrames() &&
|
||||
!aReflowState.WillReflowAgainForClearance()) {
|
||||
nsRect childBounds;
|
||||
nsSize containingBlockSize
|
||||
= CalculateContainingBlockSizeForAbsolutes(aReflowState,
|
||||
|
@ -1871,8 +1880,7 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
|||
rv = ReflowLine(aState, line, &keepGoing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (aState.mReflowState.mDiscoveredClearance &&
|
||||
*aState.mReflowState.mDiscoveredClearance) {
|
||||
if (aState.mReflowState.WillReflowAgainForClearance()) {
|
||||
line->MarkDirty();
|
||||
willReflowAgain = PR_TRUE;
|
||||
// Note that once we've entered this state, every line that gets here
|
||||
|
|
|
@ -4947,7 +4947,7 @@ nsFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsK
|
|||
if (!aState->mAtStart) {
|
||||
if (aState->mLastCharWasPunctuation) {
|
||||
// We're not punctuation, so this is a punctuation boundary.
|
||||
if (BreakWordBetweenPunctuation(aForward, aIsKeyboardSelect))
|
||||
if (BreakWordBetweenPunctuation(aState, PR_FALSE, PR_FALSE, aIsKeyboardSelect))
|
||||
return PR_TRUE;
|
||||
} else {
|
||||
// This is not a punctuation boundary.
|
||||
|
@ -4957,7 +4957,9 @@ nsFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsK
|
|||
}
|
||||
// Otherwise skip to the other side and note that we encountered non-whitespace.
|
||||
*aOffset = 1 - startOffset;
|
||||
aState->Update(PR_FALSE);
|
||||
aState->Update(PR_FALSE, // not punctuation
|
||||
PR_FALSE // not whitespace
|
||||
);
|
||||
if (!aWordSelectEatSpace)
|
||||
aState->SetSawBeforeType();
|
||||
}
|
||||
|
@ -4965,18 +4967,32 @@ nsFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool aIsK
|
|||
}
|
||||
|
||||
PRBool
|
||||
nsFrame::BreakWordBetweenPunctuation(PRBool aAfterPunct, PRBool aIsKeyboardSelect)
|
||||
nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
|
||||
PRBool aPunctAfter, PRBool aWhitespaceAfter,
|
||||
PRBool aIsKeyboardSelect)
|
||||
{
|
||||
NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
|
||||
"Call this only at punctuation boundaries");
|
||||
if (aState->mLastCharWasWhitespace) {
|
||||
// We always stop between whitespace and punctuation
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (!nsContentUtils::GetBoolPref("layout.word_select.stop_at_punctuation")) {
|
||||
// When this pref is false, we never stop at a punctuation boundary.
|
||||
// When this pref is false, we never stop at a punctuation boundary unless
|
||||
// it's after whitespace
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (!aIsKeyboardSelect) {
|
||||
// mouse caret movement (e.g. word selection) always stops at every punctuation boundary
|
||||
return PR_TRUE;
|
||||
}
|
||||
// keyboard caret movement stops after punctuation, not before it
|
||||
return aAfterPunct;
|
||||
if (!aState->mLastCharWasPunctuation) {
|
||||
// keyboard caret movement stops after punctuation, not before it
|
||||
return PR_FALSE;
|
||||
}
|
||||
// Stop only if we've seen some non-punctuation since the last whitespace;
|
||||
// don't stop after punctuation that follows whitespace.
|
||||
return aState->mSeenNonPunctuationSinceWhitespace;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -251,11 +251,14 @@ public:
|
|||
PRInt32* aOffset, PeekWordState *aState);
|
||||
/**
|
||||
* Check whether we should break at a boundary between punctuation and
|
||||
* non-punctuation.
|
||||
* @param aAfterPunct true when this point is logically *after* punctuation.
|
||||
* non-punctuation. Only call it at a punctuation boundary
|
||||
* (i.e. exactly one of the previous and next characters are punctuation).
|
||||
* @param aPunctAfter true if the next character is punctuation
|
||||
*/
|
||||
PRBool BreakWordBetweenPunctuation(PRBool aAfterPunct, PRBool aIsKeyboardSelect);
|
||||
|
||||
PRBool BreakWordBetweenPunctuation(const PeekWordState* aState,
|
||||
PRBool aPunctAfter, PRBool aWhitespaceAfter,
|
||||
PRBool aIsKeyboardSelect);
|
||||
|
||||
NS_IMETHOD CheckVisibility(nsPresContext* aContext, PRInt32 aStartIndex, PRInt32 aEndIndex, PRBool aRecurse, PRBool *aFinished, PRBool *_retval);
|
||||
|
||||
NS_IMETHOD GetOffsets(PRInt32 &aStart, PRInt32 &aEnd) const;
|
||||
|
|
|
@ -466,6 +466,10 @@ public:
|
|||
|
||||
void SetTruncated(const nsHTMLReflowMetrics& aMetrics, nsReflowStatus* aStatus) const;
|
||||
|
||||
PRBool WillReflowAgainForClearance() const {
|
||||
return mDiscoveredClearance && *mDiscoveredClearance;
|
||||
}
|
||||
|
||||
protected:
|
||||
void InitFrameType();
|
||||
void InitCBReflowState();
|
||||
|
|
|
@ -2168,15 +2168,27 @@ protected:
|
|||
PRPackedBool mSawBeforeType;
|
||||
// true when the last character encountered was punctuation
|
||||
PRPackedBool mLastCharWasPunctuation;
|
||||
// true when the last character encountered was whitespace
|
||||
PRPackedBool mLastCharWasWhitespace;
|
||||
// true when we've seen non-punctuation since the last whitespace
|
||||
PRPackedBool mSeenNonPunctuationSinceWhitespace;
|
||||
// text that's *before* the current frame when aForward is true, *after*
|
||||
// the current frame when aForward is false.
|
||||
// the current frame when aForward is false. Only includes the text
|
||||
// on the current line.
|
||||
nsAutoString mContext;
|
||||
|
||||
PeekWordState() : mAtStart(PR_TRUE), mSawBeforeType(PR_FALSE),
|
||||
mLastCharWasPunctuation(PR_FALSE) {}
|
||||
mLastCharWasPunctuation(PR_FALSE), mLastCharWasWhitespace(PR_FALSE),
|
||||
mSeenNonPunctuationSinceWhitespace(PR_FALSE) {}
|
||||
void SetSawBeforeType() { mSawBeforeType = PR_TRUE; }
|
||||
void Update(PRBool aAfterPunctuation) {
|
||||
void Update(PRBool aAfterPunctuation, PRBool aAfterWhitespace) {
|
||||
mLastCharWasPunctuation = aAfterPunctuation;
|
||||
mLastCharWasWhitespace = aAfterWhitespace;
|
||||
if (aAfterWhitespace) {
|
||||
mSeenNonPunctuationSinceWhitespace = PR_FALSE;
|
||||
} else if (!aAfterPunctuation) {
|
||||
mSeenNonPunctuationSinceWhitespace = PR_TRUE;
|
||||
}
|
||||
mAtStart = PR_FALSE;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4723,23 +4723,23 @@ nsTextFrame::PeekOffsetWord(PRBool aForward, PRBool aWordSelectEatSpace, PRBool
|
|||
|
||||
do {
|
||||
PRBool isPunctuation = cIter.IsPunctuation();
|
||||
if (aWordSelectEatSpace == cIter.IsWhitespace() && !aState->mSawBeforeType) {
|
||||
PRBool isWhitespace = cIter.IsWhitespace();
|
||||
if (aWordSelectEatSpace == isWhitespace && !aState->mSawBeforeType) {
|
||||
aState->SetSawBeforeType();
|
||||
aState->Update(isPunctuation);
|
||||
aState->Update(isPunctuation, isWhitespace);
|
||||
continue;
|
||||
}
|
||||
// See if we can break before the current cluster
|
||||
if (!aState->mAtStart) {
|
||||
PRBool canBreak = isPunctuation != aState->mLastCharWasPunctuation
|
||||
? BreakWordBetweenPunctuation(aForward ? aState->mLastCharWasPunctuation : isPunctuation,
|
||||
aIsKeyboardSelect)
|
||||
? BreakWordBetweenPunctuation(aState, isPunctuation, isWhitespace, aIsKeyboardSelect)
|
||||
: cIter.HaveWordBreakBefore() && aState->mSawBeforeType;
|
||||
if (canBreak) {
|
||||
*aOffset = cIter.GetBeforeOffset() - mContentOffset;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
aState->Update(isPunctuation);
|
||||
aState->Update(isPunctuation, isWhitespace);
|
||||
} while (cIter.NextCluster());
|
||||
|
||||
*aOffset = cIter.GetAfterOffset() - mContentOffset;
|
||||
|
@ -5481,8 +5481,16 @@ nsTextFrame::Reflow(nsPresContext* aPresContext,
|
|||
textMetrics.mAdvanceWidth + provider.GetHyphenWidth() <= availWidth);
|
||||
}
|
||||
PRBool breakAfter = PR_FALSE;
|
||||
if ((charsFit == length && transformedOffset + transformedLength == mTextRun->GetLength() &&
|
||||
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK))) {
|
||||
if (charsFit == length && transformedOffset + transformedLength == mTextRun->GetLength() &&
|
||||
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK) &&
|
||||
// check that we shouldn't be suppressing an initial break. Note that
|
||||
// a text frame of collapsible space at the start of a line will have
|
||||
// transformedLength 0 because the space will be trimmed away.
|
||||
(transformedLength > 0 || lineLayout.LineIsBreakable())) {
|
||||
// We placed all the text in the textrun and we have a break opportunity at
|
||||
// the end of the textrun. We need to record it because the following
|
||||
// content may not care about nsLineBreaker.
|
||||
|
||||
// Note that because we didn't break, we can be sure that (thanks to the
|
||||
// code up above) textMetrics.mAdvanceWidth includes the width of any
|
||||
// trailing whitespace. So we need to subtract trimmableWidth here
|
||||
|
|
|
@ -31,15 +31,19 @@ function getPrefs() {
|
|||
.getBranch("layout.word_select.");
|
||||
}
|
||||
|
||||
function setEatSpace(newValue) {
|
||||
getPrefs().setBoolPref("eat_space_to_next_word", newValue);
|
||||
eatSpace = newValue;
|
||||
function setPrefs(eat_space, stop_at_punctuation) {
|
||||
getPrefs().setBoolPref("eat_space_to_next_word", eat_space);
|
||||
getPrefs().setBoolPref("stop_at_punctuation", stop_at_punctuation);
|
||||
eatSpace = eat_space;
|
||||
}
|
||||
|
||||
function restoreEatSpace() {
|
||||
function restorePrefs() {
|
||||
try {
|
||||
getPrefs().clearUserPref("eat_space_to_next_word");
|
||||
} catch(ex) {}
|
||||
try {
|
||||
getPrefs().clearUserPref("stop_at_punctuation");
|
||||
} catch(ex) {}
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
@ -69,7 +73,7 @@ function test() {
|
|||
|
||||
var afterEditorNode = document.getElementById("catch").firstChild;
|
||||
|
||||
setEatSpace(false);
|
||||
setPrefs(false, true);
|
||||
|
||||
editor.innerHTML = "Hello Kitty";
|
||||
sel.collapse(editor.firstChild, 0);
|
||||
|
@ -103,7 +107,18 @@ function test() {
|
|||
testLeft(editor.firstChild.firstChild, 4);
|
||||
testLeft(editor.firstChild.firstChild, 0);
|
||||
|
||||
setEatSpace(true);
|
||||
editor.innerHTML = "Set .rc to <b>'</b>quiz'";
|
||||
sel.collapse(editor.firstChild, 0);
|
||||
testRight(editor.firstChild, 3);
|
||||
testRight(editor.firstChild, 7);
|
||||
testRight(editor.firstChild, 10);
|
||||
testRight(editor.firstChild.nextSibling.nextSibling, 5);
|
||||
testLeft(editor.firstChild, 11);
|
||||
testLeft(editor.firstChild, 8);
|
||||
testLeft(editor.firstChild, 4);
|
||||
testLeft(editor.firstChild, 0);
|
||||
|
||||
setPrefs(true, true);
|
||||
|
||||
// test basic word movement with eat_space_next_to_word true.
|
||||
|
||||
|
@ -137,7 +152,18 @@ function test() {
|
|||
testLeft(editor.firstChild.firstChild, 4);
|
||||
testLeft(editor.firstChild.firstChild, 0);
|
||||
|
||||
restoreEatSpace();
|
||||
editor.innerHTML = "Set .rc to <b>'</b>quiz'";
|
||||
sel.collapse(editor.firstChild, 0);
|
||||
testRight(editor.firstChild, 4);
|
||||
testRight(editor.firstChild, 8);
|
||||
testRight(editor.firstChild.nextSibling.firstChild, 0);
|
||||
testRight(afterEditorNode, 0);
|
||||
testLeft(editor.firstChild, 11);
|
||||
testLeft(editor.firstChild, 8);
|
||||
testLeft(editor.firstChild, 4);
|
||||
testLeft(editor.firstChild, 0);
|
||||
|
||||
restorePrefs();
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче