Bug 1649980 - part 7: Redesign WSRunObject::MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace() r=m_kato

Same as the previous patch, it can be split to computation part and
modifying the DOM tree part.  Then, the former can be in `TextFragmentData`
and the latter can be done by the caller which is only
`WSRunObject::InsertText()`.

Depends on D82699

Differential Revision: https://phabricator.services.mozilla.com/D82700
This commit is contained in:
Masayuki Nakano 2020-07-13 08:31:51 +00:00
parent b85c0263f1
commit ab1d1d9708
5 changed files with 64 additions and 46 deletions

View File

@ -12,6 +12,7 @@
<div contenteditable id="editor"><p><br></p></div>
<script>
SimpleTest.waitForExplicitFinish();
SimpleTest.expectAssertions(2); // Assertions in WSRunScanner::TextFragmentData::GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace()
SimpleTest.waitForFocus(async function doTests() {
await SpecialPowers.pushPrefEnv({set: [
["dom.compositionevent.text.dispatch_only_system_group_in_content", true],

View File

@ -415,13 +415,22 @@ nsresult WSRunObject::InsertText(Document& aDocument,
PointPosition::StartOfFragment ||
pointPositionWithVisibleWhiteSpacesAtEnd ==
PointPosition::MiddleOfFragment) {
nsresult rv = MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace(
visibleWhiteSpacesAtEnd.ref(), pointToInsert);
if (NS_FAILED(rv)) {
NS_WARNING(
"WSRunObject::MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace() "
"failed");
return rv;
EditorDOMPointInText atNBSPReplacedWithASCIIWhiteSpace =
textFragmentDataAtEnd
.GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace(
pointToInsert);
if (atNBSPReplacedWithASCIIWhiteSpace.IsSet()) {
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
nsresult rv =
MOZ_KnownLive(mHTMLEditor)
.ReplaceTextWithTransaction(
MOZ_KnownLive(
*atNBSPReplacedWithASCIIWhiteSpace.ContainerAsText()),
atNBSPReplacedWithASCIIWhiteSpace.Offset(), 1, u" "_ns);
if (NS_FAILED(rv)) {
NS_WARNING("HTMLEditor::ReplaceTextWithTransaction() failed");
return rv;
}
}
}
@ -2154,19 +2163,28 @@ EditorDOMPointInText WSRunScanner::TextFragmentData::
return atPreviousChar;
}
nsresult WSRunObject::MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace(
const VisibleWhiteSpacesData& aVisibleWhiteSpacesData,
const EditorDOMPoint& aPoint) {
MOZ_ASSERT(aPoint.IsSetAndValid());
EditorDOMPointInText WSRunScanner::TextFragmentData::
GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace(
const EditorDOMPoint& aPointToInsert) const {
MOZ_ASSERT(aPointToInsert.IsSetAndValid());
MOZ_ASSERT(CreateVisibleWhiteSpacesData().isSome());
NS_ASSERTION(
CreateVisibleWhiteSpacesData().ref().ComparePoint(aPointToInsert) ==
PointPosition::StartOfFragment ||
CreateVisibleWhiteSpacesData().ref().ComparePoint(aPointToInsert) ==
PointPosition::MiddleOfFragment,
"Inclusive next char of aPointToInsert should be in the visible "
"white-spaces");
// Try to change an nbsp to a space, if possible, just to prevent nbsp
// proliferation This routine is called when we are about to make this point
// in the ws abut an inserted text, so we don't have to worry about what is
// before it. What is before it now will end up before the inserted text.
EditorDOMPointInText atNextChar = GetInclusiveNextEditableCharPoint(aPoint);
EditorDOMPointInText atNextChar =
GetInclusiveNextEditableCharPoint(aPointToInsert);
if (!atNextChar.IsSet() || NS_WARN_IF(atNextChar.IsEndOfContainer()) ||
!atNextChar.IsCharNBSP()) {
return NS_OK;
return EditorDOMPointInText();
}
EditorDOMPointInText atNextCharOfNextCharOfNBSP =
@ -2176,25 +2194,22 @@ nsresult WSRunObject::MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace(
// need to replace it with same character.
if (!atNextCharOfNextCharOfNBSP.IsEndOfContainer() &&
atNextCharOfNextCharOfNBSP.IsCharASCIISpace()) {
return NS_OK;
return EditorDOMPointInText();
}
}
// If the NBSP is last character in the hard line, we don't need to
// replace it because it's required to render multiple white-spaces.
else if (!aVisibleWhiteSpacesData.EndsByNormalText() &&
!aVisibleWhiteSpacesData.EndsBySpecialContent() &&
!aVisibleWhiteSpacesData.EndsByBRElement()) {
return NS_OK;
return atNextChar;
}
AutoTransactionsConserveSelection dontChangeMySelection(mHTMLEditor);
nsresult rv = MOZ_KnownLive(mHTMLEditor)
.ReplaceTextWithTransaction(
MOZ_KnownLive(*atNextChar.ContainerAsText()),
atNextChar.Offset(), 1, u" "_ns);
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
"HTMLEditor::ReplaceTextWithTransaction() failed");
return rv;
// If the NBSP is last character in the hard line, we don't need to
// replace it because it's required to render multiple white-spaces.
Maybe<VisibleWhiteSpacesData> visibleWhiteSpaces =
CreateVisibleWhiteSpacesData();
if (!visibleWhiteSpaces.ref().EndsByNormalText() &&
!visibleWhiteSpaces.ref().EndsBySpecialContent() &&
!visibleWhiteSpaces.ref().EndsByBRElement()) {
return EditorDOMPointInText();
}
return atNextChar;
}
nsresult WSRunObject::DeleteInvisibleASCIIWhiteSpacesInternal() {

View File

@ -1023,6 +1023,19 @@ class MOZ_STACK_CLASS WSRunScanner {
EditorDOMPointInText GetPreviousNBSPPointIfNeedToReplaceWithASCIIWhiteSpace(
const EditorDOMPoint& aPointToInsert) const;
/**
* GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace() may return
* an NBSP point which should be replaced with an ASCII white-space when
* the caller inserts text into aPointToInsert.
* Note that this is a helper method for the traditional white-space
* normalizer. Don't use this with the new white-space normalizer.
* Must be called only when CreateVisibleWhiteSpacesData() returns some,
* and inclusive next char of aPointToInsert is in the range.
*/
EditorDOMPointInText
GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace(
const EditorDOMPoint& aPointToInsert) const;
/**
* CreateVisibleWhiteSpacesData() creates VisibleWhiteSpacesData.
* That is zero or more white-spaces which are visible.
@ -1250,20 +1263,6 @@ class MOZ_STACK_CLASS WSRunObject final : public WSRunScanner {
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult NormalizeWhiteSpacesAtEndOf(
const VisibleWhiteSpacesData& aVisibleWhiteSpacesData);
/**
* MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace() replaces an NBSP at
* the point with an ASCII white-space only when the point is an NBSP and
* it's replaceable with an ASCII white-space.
*
* @param aPoint If point in a text node, the character is checked
* whether it's an NBSP or not. Otherwise, first
* character of next editable text node is checked.
*/
[[nodiscard]] MOZ_CAN_RUN_SCRIPT nsresult
MaybeReplaceInclusiveNextNBSPWithASCIIWhiteSpace(
const VisibleWhiteSpacesData& aVisibleWhiteSpacesData,
const EditorDOMPoint& aPoint);
/**
* See explanation of the static method for this.
*/

View File

@ -20,6 +20,7 @@
<script class="testbody" type="application/javascript">
SimpleTest.waitForExplicitFinish();
SimpleTest.expectAssertions(1); // Assertions in WSRunScanner::TextFragmentData::GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace()
SimpleTest.waitForFocus(runTests);
const kLF = !navigator.platform.indexOf("Win") ? "\r\n" : "\n";

View File

@ -18,12 +18,14 @@
<script class="testbody" type="application/javascript">
<![CDATA[
// If setting selection with eSetSelection event whose range is larger than
// the actual range, hits "Can only call this on frames that have been reflowed:
// 3 assertions are: If setting selection with eSetSelection event whose range
// is larger than the actual range, hits "Can only call this on frames that have
// been reflowed:
// '!(GetStateBits() & NS_FRAME_FIRST_REFLOW) || (GetParent()->GetStateBits() &
// NS_FRAME_TOO_DEEP_IN_FRAME_TREE)'" in nsTextFrame.cpp.
// Strangely, this doesn't occur with RDP on Windows.
SimpleTest.expectAssertions(0, 3);
// 12 assertions are: assertions in WSRunScanner::TextFragmentData::GetInclusiveNextNBSPPointIfNeedToReplaceWithASCIIWhiteSpace()
SimpleTest.expectAssertions(0, 3 + 12);
SimpleTest.waitForExplicitFinish();
window.openDialog("window_composition_text_querycontent.xhtml", "_blank",
"chrome,width=600,height=600,noopener", window);