2001-09-26 02:53:13 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
#include "WSRunObject.h"
|
2014-12-02 08:07:42 +03:00
|
|
|
|
2016-07-07 07:44:32 +03:00
|
|
|
#include "TextEditUtils.h"
|
2016-07-07 05:49:42 +03:00
|
|
|
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "mozilla/Assertions.h"
|
2014-08-20 16:25:16 +04:00
|
|
|
#include "mozilla/Casting.h"
|
2016-07-08 08:03:31 +03:00
|
|
|
#include "mozilla/EditorUtils.h"
|
2016-07-09 05:42:33 +03:00
|
|
|
#include "mozilla/HTMLEditor.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "mozilla/mozalloc.h"
|
2016-07-09 05:42:33 +03:00
|
|
|
#include "mozilla/OwningNonNull.h"
|
2016-07-09 05:34:41 +03:00
|
|
|
#include "mozilla/SelectionState.h"
|
2014-08-20 16:25:16 +04:00
|
|
|
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsAString.h"
|
|
|
|
#include "nsCRT.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsDebug.h"
|
|
|
|
#include "nsError.h"
|
2001-04-28 16:04:45 +04:00
|
|
|
#include "nsIContent.h"
|
2014-05-02 16:15:27 +04:00
|
|
|
#include "nsIDOMDocument.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsIDOMNode.h"
|
|
|
|
#include "nsISupportsImpl.h"
|
2012-01-10 18:19:54 +04:00
|
|
|
#include "nsRange.h"
|
2012-07-13 10:33:42 +04:00
|
|
|
#include "nsString.h"
|
|
|
|
#include "nsTextFragment.h"
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
using namespace dom;
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2014-01-04 19:02:17 +04:00
|
|
|
const char16_t nbsp = 160;
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::WSRunObject(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2014-05-02 15:11:26 +04:00
|
|
|
: mNode(aNode)
|
|
|
|
, mOffset(aOffset)
|
|
|
|
, mPRE(false)
|
|
|
|
, mStartOffset(0)
|
|
|
|
, mEndOffset(0)
|
|
|
|
, mFirstNBSPOffset(0)
|
|
|
|
, mLastNBSPOffset(0)
|
|
|
|
, mStartRun(nullptr)
|
|
|
|
, mEndRun(nullptr)
|
2016-07-07 13:00:51 +03:00
|
|
|
, mHTMLEditor(aHTMLEditor)
|
2014-05-02 15:11:26 +04:00
|
|
|
{
|
|
|
|
GetWSNodes();
|
|
|
|
GetRuns();
|
|
|
|
}
|
|
|
|
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::WSRunObject(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
nsIDOMNode* aNode,
|
|
|
|
int32_t aOffset)
|
|
|
|
: mNode(do_QueryInterface(aNode))
|
|
|
|
, mOffset(aOffset)
|
|
|
|
, mPRE(false)
|
|
|
|
, mStartOffset(0)
|
|
|
|
, mEndOffset(0)
|
|
|
|
, mFirstNBSPOffset(0)
|
|
|
|
, mLastNBSPOffset(0)
|
|
|
|
, mStartRun(nullptr)
|
|
|
|
, mEndRun(nullptr)
|
|
|
|
, mHTMLEditor(aHTMLEditor)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
GetWSNodes();
|
|
|
|
GetRuns();
|
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::~WSRunObject()
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
ClearRuns();
|
|
|
|
}
|
|
|
|
|
2001-12-09 12:24:33 +03:00
|
|
|
nsresult
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::ScrubBlockBoundary(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
BlockBoundary aBoundary,
|
|
|
|
nsINode* aBlock,
|
|
|
|
int32_t aOffset)
|
2001-12-09 12:24:33 +03:00
|
|
|
{
|
2016-07-07 13:00:51 +03:00
|
|
|
NS_ENSURE_TRUE(aHTMLEditor && aBlock, NS_ERROR_NULL_POINTER);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
|
|
|
int32_t offset;
|
|
|
|
if (aBoundary == kBlockStart) {
|
|
|
|
offset = 0;
|
|
|
|
} else if (aBoundary == kBlockEnd) {
|
|
|
|
offset = aBlock->Length();
|
|
|
|
} else {
|
|
|
|
// Else we are scrubbing an outer boundary - just before or after a block
|
|
|
|
// element.
|
|
|
|
NS_ENSURE_STATE(aOffset >= 0);
|
|
|
|
offset = aOffset;
|
|
|
|
}
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject theWSObj(aHTMLEditor, aBlock, offset);
|
2001-12-09 12:24:33 +03:00
|
|
|
return theWSObj.Scrub();
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:26 +04:00
|
|
|
nsresult
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::PrepareToJoinBlocks(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
Element* aLeftBlock,
|
|
|
|
Element* aRightBlock)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2016-07-07 13:00:51 +03:00
|
|
|
NS_ENSURE_TRUE(aLeftBlock && aRightBlock && aHTMLEditor,
|
|
|
|
NS_ERROR_NULL_POINTER);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject leftWSObj(aHTMLEditor, aLeftBlock, aLeftBlock->Length());
|
|
|
|
WSRunObject rightWSObj(aHTMLEditor, aRightBlock, 0);
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
|
|
|
|
}
|
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
nsresult
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::PrepareToDeleteRange(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
nsCOMPtr<nsINode>* aStartNode,
|
|
|
|
int32_t* aStartOffset,
|
|
|
|
nsCOMPtr<nsINode>* aEndNode,
|
|
|
|
int32_t* aEndOffset)
|
2014-05-02 15:11:26 +04:00
|
|
|
{
|
2016-07-07 13:00:51 +03:00
|
|
|
NS_ENSURE_TRUE(aHTMLEditor && aStartNode && *aStartNode && aStartOffset &&
|
2014-05-02 16:15:26 +04:00
|
|
|
aEndNode && *aEndNode && aEndOffset, NS_ERROR_NULL_POINTER);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
AutoTrackDOMPoint trackerStart(aHTMLEditor->mRangeUpdater,
|
|
|
|
aStartNode, aStartOffset);
|
|
|
|
AutoTrackDOMPoint trackerEnd(aHTMLEditor->mRangeUpdater,
|
|
|
|
aEndNode, aEndOffset);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject leftWSObj(aHTMLEditor, *aStartNode, *aStartOffset);
|
|
|
|
WSRunObject rightWSObj(aHTMLEditor, *aEndNode, *aEndOffset);
|
2001-05-10 15:55:49 +04:00
|
|
|
|
|
|
|
return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:26 +04:00
|
|
|
nsresult
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::PrepareToDeleteNode(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
nsIContent* aContent)
|
2001-05-10 15:55:49 +04:00
|
|
|
{
|
2016-07-07 13:00:51 +03:00
|
|
|
NS_ENSURE_TRUE(aContent && aHTMLEditor, NS_ERROR_NULL_POINTER);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsINode> parent = aContent->GetParentNode();
|
2014-05-02 15:11:26 +04:00
|
|
|
NS_ENSURE_STATE(parent);
|
2014-05-02 16:15:26 +04:00
|
|
|
int32_t offset = parent->IndexOf(aContent);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject leftWSObj(aHTMLEditor, parent, offset);
|
|
|
|
WSRunObject rightWSObj(aHTMLEditor, parent, offset + 1);
|
2001-05-10 15:55:49 +04:00
|
|
|
|
|
|
|
return leftWSObj.PrepareToDeleteRangePriv(&rightWSObj);
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:26 +04:00
|
|
|
nsresult
|
2016-07-09 05:42:33 +03:00
|
|
|
WSRunObject::PrepareToSplitAcrossBlocks(HTMLEditor* aHTMLEditor,
|
2016-07-07 13:00:51 +03:00
|
|
|
nsCOMPtr<nsINode>* aSplitNode,
|
|
|
|
int32_t* aSplitOffset)
|
2001-05-10 15:55:49 +04:00
|
|
|
{
|
2016-07-07 13:00:51 +03:00
|
|
|
NS_ENSURE_TRUE(aHTMLEditor && aSplitNode && *aSplitNode && aSplitOffset,
|
2014-05-02 16:15:26 +04:00
|
|
|
NS_ERROR_NULL_POINTER);
|
2001-05-11 16:43:22 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
AutoTrackDOMPoint tracker(aHTMLEditor->mRangeUpdater,
|
|
|
|
aSplitNode, aSplitOffset);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject wsObj(aHTMLEditor, *aSplitNode, *aSplitOffset);
|
2001-05-11 16:43:22 +04:00
|
|
|
|
|
|
|
return wsObj.PrepareToSplitAcrossBlocksPriv();
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2016-07-12 18:58:13 +03:00
|
|
|
already_AddRefed<Element>
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::InsertBreak(nsCOMPtr<nsINode>* aInOutParent,
|
|
|
|
int32_t* aInOutOffset,
|
|
|
|
nsIEditor::EDirection aSelect)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
// MOOSE: for now, we always assume non-PRE formatting. Fix this later.
|
2014-05-02 15:11:26 +04:00
|
|
|
// meanwhile, the pre case is handled in WillInsertText in
|
2016-07-07 13:05:51 +03:00
|
|
|
// HTMLEditRules.cpp
|
2014-05-02 15:11:26 +04:00
|
|
|
NS_ENSURE_TRUE(aInOutParent && aInOutOffset, nullptr);
|
2001-04-28 16:04:45 +04:00
|
|
|
|
|
|
|
WSFragment *beforeRun, *afterRun;
|
2014-05-02 16:15:27 +04:00
|
|
|
FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false);
|
|
|
|
FindRun(*aInOutParent, *aInOutOffset, &afterRun, true);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2016-06-24 09:08:16 +03:00
|
|
|
// Some scoping for AutoTrackDOMPoint. This will track our insertion
|
2014-05-02 15:11:26 +04:00
|
|
|
// point while we tweak any surrounding whitespace
|
2016-06-24 09:08:16 +03:00
|
|
|
AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, aInOutParent,
|
|
|
|
aInOutOffset);
|
2002-04-14 03:54:59 +04:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
// Handle any changes needed to ws run after inserted br
|
|
|
|
if (!afterRun || (afterRun->mType & WSType::trailingWS)) {
|
|
|
|
// Don't need to do anything. Just insert break. ws won't change.
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (afterRun->mType & WSType::leadingWS) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// Delete the leading ws that is after insertion point. We don't
|
|
|
|
// have to (it would still not be significant after br), but it's
|
2002-04-14 03:54:59 +04:00
|
|
|
// just more aesthetically pleasing to.
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = DeleteChars(*aInOutParent, *aInOutOffset,
|
|
|
|
afterRun->mEndNode, afterRun->mEndOffset,
|
|
|
|
eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (afterRun->mType == WSType::normalWS) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// Need to determine if break at front of non-nbsp run. If so, convert
|
|
|
|
// run to nbsp.
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint thePoint = GetCharAfter(*aInOutParent, *aInOutOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (thePoint.mTextNode && nsCRT::IsAsciiSpace(thePoint.mChar)) {
|
|
|
|
WSPoint prevPoint = GetCharBefore(thePoint);
|
|
|
|
if (prevPoint.mTextNode && !nsCRT::IsAsciiSpace(prevPoint.mChar)) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// We are at start of non-nbsps. Convert to a single nbsp.
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = ConvertToNBSP(thePoint);
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2002-04-14 03:54:59 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
|
|
|
|
// Handle any changes needed to ws run before inserted br
|
|
|
|
if (!beforeRun || (beforeRun->mType & WSType::leadingWS)) {
|
|
|
|
// Don't need to do anything. Just insert break. ws won't change.
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (beforeRun->mType & WSType::trailingWS) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// Need to delete the trailing ws that is before insertion point, because it
|
2002-04-14 03:54:59 +04:00
|
|
|
// would become significant after break inserted.
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = DeleteChars(beforeRun->mStartNode, beforeRun->mStartOffset,
|
|
|
|
*aInOutParent, *aInOutOffset,
|
|
|
|
eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (beforeRun->mType == WSType::normalWS) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// Try to change an nbsp to a space, just to prevent nbsp proliferation
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = CheckTrailingNBSP(beforeRun, *aInOutParent, *aInOutOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2002-04-14 03:54:59 +04:00
|
|
|
}
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
// ready, aim, fire!
|
2014-05-02 15:11:26 +04:00
|
|
|
return mHTMLEditor->CreateBRImpl(aInOutParent, aInOutOffset, aSelect);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::InsertText(const nsAString& aStringToInsert,
|
|
|
|
nsCOMPtr<nsINode>* aInOutParent,
|
|
|
|
int32_t* aInOutOffset,
|
|
|
|
nsIDocument* aDoc)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
// MOOSE: for now, we always assume non-PRE formatting. Fix this later.
|
2014-05-02 16:15:27 +04:00
|
|
|
// meanwhile, the pre case is handled in WillInsertText in
|
2016-07-07 13:05:51 +03:00
|
|
|
// HTMLEditRules.cpp
|
2001-04-28 16:04:45 +04:00
|
|
|
|
|
|
|
// MOOSE: for now, just getting the ws logic straight. This implementation
|
|
|
|
// is very slow. Will need to replace edit rules impl with a more efficient
|
|
|
|
// text sink here that does the minimal amount of searching/replacing/copying
|
|
|
|
|
2010-06-18 00:40:48 +04:00
|
|
|
NS_ENSURE_TRUE(aInOutParent && aInOutOffset && aDoc, NS_ERROR_NULL_POINTER);
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
if (aStringToInsert.IsEmpty()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
nsAutoString theString(aStringToInsert);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
WSFragment *beforeRun, *afterRun;
|
2014-05-02 16:15:27 +04:00
|
|
|
FindRun(*aInOutParent, *aInOutOffset, &beforeRun, false);
|
|
|
|
FindRun(*aInOutParent, *aInOutOffset, &afterRun, true);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2016-06-24 09:08:16 +03:00
|
|
|
// Some scoping for AutoTrackDOMPoint. This will track our insertion
|
2014-05-02 16:15:27 +04:00
|
|
|
// point while we tweak any surrounding whitespace
|
2016-06-24 09:08:16 +03:00
|
|
|
AutoTrackDOMPoint tracker(mHTMLEditor->mRangeUpdater, aInOutParent,
|
|
|
|
aInOutOffset);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Handle any changes needed to ws run after inserted text
|
|
|
|
if (!afterRun || afterRun->mType & WSType::trailingWS) {
|
|
|
|
// Don't need to do anything. Just insert text. ws won't change.
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (afterRun->mType & WSType::leadingWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Delete the leading ws that is after insertion point, because it
|
2002-04-14 03:54:59 +04:00
|
|
|
// would become significant after text inserted.
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
DeleteChars(*aInOutParent, *aInOutOffset, afterRun->mEndNode,
|
|
|
|
afterRun->mEndOffset, eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (afterRun->mType == WSType::normalWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Try to change an nbsp to a space, if possible, just to prevent nbsp
|
|
|
|
// proliferation
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = CheckLeadingNBSP(afterRun, *aInOutParent, *aInOutOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-04-14 03:54:59 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Handle any changes needed to ws run before inserted text
|
|
|
|
if (!beforeRun || beforeRun->mType & WSType::leadingWS) {
|
|
|
|
// Don't need to do anything. Just insert text. ws won't change.
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (beforeRun->mType & WSType::trailingWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Need to delete the trailing ws that is before insertion point, because
|
|
|
|
// it would become significant after text inserted.
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
DeleteChars(beforeRun->mStartNode, beforeRun->mStartOffset,
|
|
|
|
*aInOutParent, *aInOutOffset, eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (beforeRun->mType == WSType::normalWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Try to change an nbsp to a space, if possible, just to prevent nbsp
|
|
|
|
// proliferation
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = CheckTrailingNBSP(beforeRun, *aInOutParent, *aInOutOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-04-14 03:54:59 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Next up, tweak head and tail of string as needed. First the head: there
|
|
|
|
// are a variety of circumstances that would require us to convert a leading
|
|
|
|
// ws char into an nbsp:
|
|
|
|
|
|
|
|
if (nsCRT::IsAsciiSpace(theString[0])) {
|
|
|
|
// We have a leading space
|
2012-07-13 10:33:43 +04:00
|
|
|
if (beforeRun) {
|
|
|
|
if (beforeRun->mType & WSType::leadingWS) {
|
2001-04-28 16:04:45 +04:00
|
|
|
theString.SetCharAt(nbsp, 0);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (beforeRun->mType & WSType::normalWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint wspoint = GetCharBefore(*aInOutParent, *aInOutOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar)) {
|
2001-04-28 16:04:45 +04:00
|
|
|
theString.SetCharAt(nbsp, 0);
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
} else if (mStartReason & WSType::block || mStartReason == WSType::br) {
|
|
|
|
theString.SetCharAt(nbsp, 0);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
// Then the tail
|
|
|
|
uint32_t lastCharIndex = theString.Length() - 1;
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
if (nsCRT::IsAsciiSpace(theString[lastCharIndex])) {
|
|
|
|
// We have a leading space
|
|
|
|
if (afterRun) {
|
2012-07-13 10:33:43 +04:00
|
|
|
if (afterRun->mType & WSType::trailingWS) {
|
2001-04-28 16:04:45 +04:00
|
|
|
theString.SetCharAt(nbsp, lastCharIndex);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (afterRun->mType & WSType::normalWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint wspoint = GetCharAfter(*aInOutParent, *aInOutOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (wspoint.mTextNode && nsCRT::IsAsciiSpace(wspoint.mChar)) {
|
2001-04-28 16:04:45 +04:00
|
|
|
theString.SetCharAt(nbsp, lastCharIndex);
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
} else if (mEndReason & WSType::block) {
|
|
|
|
theString.SetCharAt(nbsp, lastCharIndex);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Next, scan string for adjacent ws and convert to nbsp/space combos
|
|
|
|
// MOOSE: don't need to convert tabs here since that is done by
|
|
|
|
// WillInsertText() before we are called. Eventually, all that logic will be
|
|
|
|
// pushed down into here and made more efficient.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool prevWS = false;
|
2014-05-02 16:15:27 +04:00
|
|
|
for (uint32_t i = 0; i <= lastCharIndex; i++) {
|
|
|
|
if (nsCRT::IsAsciiSpace(theString[i])) {
|
|
|
|
if (prevWS) {
|
|
|
|
// i - 1 can't be negative because prevWS starts out false
|
|
|
|
theString.SetCharAt(nbsp, i - 1);
|
|
|
|
} else {
|
2011-10-17 18:59:28 +04:00
|
|
|
prevWS = true;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
2011-10-17 18:59:28 +04:00
|
|
|
prevWS = false;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Ready, aim, fire!
|
2016-10-19 12:09:33 +03:00
|
|
|
mHTMLEditor->InsertTextImpl(theString, aInOutParent, aInOutOffset, aDoc);
|
2001-04-28 16:04:45 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:26 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::DeleteWSBackward()
|
2001-05-10 15:55:49 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharBefore(mNode, mOffset);
|
2010-06-17 23:41:16 +04:00
|
|
|
NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2016-10-24 05:27:45 +03:00
|
|
|
// Easy case, preformatted ws.
|
|
|
|
if (mPRE && (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == nbsp)) {
|
|
|
|
return DeleteChars(point.mTextNode, point.mOffset,
|
|
|
|
point.mTextNode, point.mOffset + 1);
|
2002-02-19 14:52:50 +03:00
|
|
|
}
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
// Caller's job to ensure that previous char is really ws. If it is normal
|
|
|
|
// ws, we need to delete the whole run.
|
|
|
|
if (nsCRT::IsAsciiSpace(point.mChar)) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> startNodeText, endNodeText;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t startOffset, endOffset;
|
2014-05-02 15:11:26 +04:00
|
|
|
GetAsciiWSBounds(eBoth, point.mTextNode, point.mOffset + 1,
|
|
|
|
getter_AddRefs(startNodeText), &startOffset,
|
|
|
|
getter_AddRefs(endNodeText), &endOffset);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
// adjust surrounding ws
|
2014-05-02 15:11:26 +04:00
|
|
|
nsCOMPtr<nsINode> startNode = startNodeText.get();
|
|
|
|
nsCOMPtr<nsINode> endNode = endNodeText.get();
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::PrepareToDeleteRange(mHTMLEditor,
|
|
|
|
address_of(startNode), &startOffset,
|
|
|
|
address_of(endNode), &endOffset);
|
2016-10-19 12:09:33 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
// finally, delete that ws
|
2014-05-02 16:15:27 +04:00
|
|
|
return DeleteChars(startNode, startOffset, endNode, endOffset);
|
2016-10-24 05:27:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (point.mChar == nbsp) {
|
2014-05-02 15:11:26 +04:00
|
|
|
nsCOMPtr<nsINode> node(point.mTextNode);
|
2001-05-10 15:55:49 +04:00
|
|
|
// adjust surrounding ws
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t startOffset = point.mOffset;
|
2014-05-02 15:11:26 +04:00
|
|
|
int32_t endOffset = point.mOffset + 1;
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::PrepareToDeleteRange(mHTMLEditor,
|
|
|
|
address_of(node), &startOffset,
|
|
|
|
address_of(node), &endOffset);
|
2016-10-19 12:09:33 +03:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
// finally, delete that ws
|
2014-05-02 16:15:27 +04:00
|
|
|
return DeleteChars(node, startOffset, node, endOffset);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
2016-10-24 05:27:45 +03:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
return NS_OK;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:26 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::DeleteWSForward()
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharAfter(mNode, mOffset);
|
2014-05-02 16:15:26 +04:00
|
|
|
NS_ENSURE_TRUE(point.mTextNode, NS_OK); // nothing to delete
|
|
|
|
|
2016-10-24 05:27:45 +03:00
|
|
|
// Easy case, preformatted ws.
|
|
|
|
if (mPRE && (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == nbsp)) {
|
|
|
|
return DeleteChars(point.mTextNode, point.mOffset,
|
|
|
|
point.mTextNode, point.mOffset + 1);
|
2002-02-19 14:52:50 +03:00
|
|
|
}
|
2014-05-02 16:15:26 +04:00
|
|
|
|
|
|
|
// Caller's job to ensure that next char is really ws. If it is normal ws,
|
|
|
|
// we need to delete the whole run.
|
|
|
|
if (nsCRT::IsAsciiSpace(point.mChar)) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> startNodeText, endNodeText;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t startOffset, endOffset;
|
2014-05-02 16:15:26 +04:00
|
|
|
GetAsciiWSBounds(eBoth, point.mTextNode, point.mOffset + 1,
|
|
|
|
getter_AddRefs(startNodeText), &startOffset,
|
|
|
|
getter_AddRefs(endNodeText), &endOffset);
|
|
|
|
|
|
|
|
// Adjust surrounding ws
|
|
|
|
nsCOMPtr<nsINode> startNode(startNodeText), endNode(endNodeText);
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
WSRunObject::PrepareToDeleteRange(mHTMLEditor,
|
|
|
|
address_of(startNode), &startOffset,
|
|
|
|
address_of(endNode), &endOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
|
|
|
// Finally, delete that ws
|
2014-05-02 16:15:27 +04:00
|
|
|
return DeleteChars(startNode, startOffset, endNode, endOffset);
|
2016-10-24 05:27:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (point.mChar == nbsp) {
|
2014-05-02 16:15:26 +04:00
|
|
|
nsCOMPtr<nsINode> node(point.mTextNode);
|
|
|
|
// Adjust surrounding ws
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t startOffset = point.mOffset;
|
|
|
|
int32_t endOffset = point.mOffset+1;
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
WSRunObject::PrepareToDeleteRange(mHTMLEditor,
|
|
|
|
address_of(node), &startOffset,
|
|
|
|
address_of(node), &endOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:26 +04:00
|
|
|
|
|
|
|
// Finally, delete that ws
|
2014-05-02 16:15:27 +04:00
|
|
|
return DeleteChars(node, startOffset, node, endOffset);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2016-10-24 05:27:45 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::PriorVisibleNode(nsINode* aNode,
|
|
|
|
int32_t aOffset,
|
|
|
|
nsCOMPtr<nsINode>* outVisNode,
|
|
|
|
int32_t* outVisOffset,
|
|
|
|
WSType* outType)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
// Find first visible thing before the point. Position
|
|
|
|
// outVisNode/outVisOffset just _after_ that thing. If we don't find
|
|
|
|
// anything return start of ws.
|
2012-06-01 15:03:17 +04:00
|
|
|
MOZ_ASSERT(aNode && outVisNode && outVisOffset && outType);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
WSFragment* run;
|
2014-05-02 16:15:27 +04:00
|
|
|
FindRun(aNode, aOffset, &run, false);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Is there a visible run there or earlier?
|
|
|
|
for (; run; run = run->mLeft) {
|
2012-07-13 10:33:43 +04:00
|
|
|
if (run->mType == WSType::normalWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharBefore(aNode, aOffset);
|
Bug 1315065 When selection is collapsed in an empty text node, Backspace/Delete key press should modify the nearest text node r=smaug
Currently, when selection is collapsed at an empty text node, the behavior of each major browser is different.
When you remove the last character of non-empty text node followed by empty text nodes, Chromium removes all following empty text nodes. However, Edge never removes empty text nodes even when selection is collapsed at an empty text node.
With this patch, our behavior becomes same as Edge. I think that we should take this for keeping backward compatibility since Gecko never removes empty text nodes. So, in other words, this patch makes Backspace key press at an empty text node modify the preceding non-empty text node.
When you remove the first character of non-empty text node preceded with empty text nodes, Edge removes all preceding empty text nodes. However, Chromium and Gecko keeps previous empty text nodes than caret position. So, we should keep current behavior for backward compatibility. In other words, this patch makes Delete key press at an empty text node modify the following non-empty text node and keep current behavior.
The fixing approach of this is, making WSRunObject::PriorVisibleNode() and WSRunObject::NextVisibleNode() ignore empty text node. This should make sense because empty text node is not a visible node. (On the other hand, when the DOMPoint has a null character, it should treat as visible character. That is visible with Unicode codepoint.)
MozReview-Commit-ID: 11YtqBktEvK
--HG--
extra : rebase_source : 70fa858866cc768179c1ca6a869e1a5c7cfe6e1a
2016-11-11 06:24:21 +03:00
|
|
|
// When it's a non-empty text node, return it.
|
|
|
|
if (point.mTextNode && point.mTextNode->Length()) {
|
2014-05-02 16:15:27 +04:00
|
|
|
*outVisNode = point.mTextNode;
|
|
|
|
*outVisOffset = point.mOffset + 1;
|
|
|
|
if (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == nbsp) {
|
2012-07-13 10:33:43 +04:00
|
|
|
*outType = WSType::normalWS;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
2012-07-13 10:33:43 +04:00
|
|
|
*outType = WSType::text;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
// If no text node, keep looking. We should eventually fall out of loop
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-12 16:12:47 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// If we get here, then nothing in ws data to find. Return start reason.
|
|
|
|
*outVisNode = mStartReasonNode;
|
|
|
|
// This really isn't meaningful if mStartReasonNode != mStartNode
|
|
|
|
*outVisOffset = mStartOffset;
|
2001-04-28 16:04:45 +04:00
|
|
|
*outType = mStartReason;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::NextVisibleNode(nsINode* aNode,
|
|
|
|
int32_t aOffset,
|
|
|
|
nsCOMPtr<nsINode>* outVisNode,
|
|
|
|
int32_t* outVisOffset,
|
|
|
|
WSType* outType)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
// Find first visible thing after the point. Position
|
|
|
|
// outVisNode/outVisOffset just _before_ that thing. If we don't find
|
|
|
|
// anything return end of ws.
|
2012-06-01 15:03:17 +04:00
|
|
|
MOZ_ASSERT(aNode && outVisNode && outVisOffset && outType);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
WSFragment* run;
|
2014-05-02 16:15:27 +04:00
|
|
|
FindRun(aNode, aOffset, &run, true);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Is there a visible run there or later?
|
|
|
|
for (; run; run = run->mRight) {
|
2012-07-13 10:33:43 +04:00
|
|
|
if (run->mType == WSType::normalWS) {
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharAfter(aNode, aOffset);
|
Bug 1315065 When selection is collapsed in an empty text node, Backspace/Delete key press should modify the nearest text node r=smaug
Currently, when selection is collapsed at an empty text node, the behavior of each major browser is different.
When you remove the last character of non-empty text node followed by empty text nodes, Chromium removes all following empty text nodes. However, Edge never removes empty text nodes even when selection is collapsed at an empty text node.
With this patch, our behavior becomes same as Edge. I think that we should take this for keeping backward compatibility since Gecko never removes empty text nodes. So, in other words, this patch makes Backspace key press at an empty text node modify the preceding non-empty text node.
When you remove the first character of non-empty text node preceded with empty text nodes, Edge removes all preceding empty text nodes. However, Chromium and Gecko keeps previous empty text nodes than caret position. So, we should keep current behavior for backward compatibility. In other words, this patch makes Delete key press at an empty text node modify the following non-empty text node and keep current behavior.
The fixing approach of this is, making WSRunObject::PriorVisibleNode() and WSRunObject::NextVisibleNode() ignore empty text node. This should make sense because empty text node is not a visible node. (On the other hand, when the DOMPoint has a null character, it should treat as visible character. That is visible with Unicode codepoint.)
MozReview-Commit-ID: 11YtqBktEvK
--HG--
extra : rebase_source : 70fa858866cc768179c1ca6a869e1a5c7cfe6e1a
2016-11-11 06:24:21 +03:00
|
|
|
// When it's a non-empty text node, return it.
|
|
|
|
if (point.mTextNode && point.mTextNode->Length()) {
|
2014-05-02 16:15:27 +04:00
|
|
|
*outVisNode = point.mTextNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
*outVisOffset = point.mOffset;
|
2014-05-02 16:15:27 +04:00
|
|
|
if (nsCRT::IsAsciiSpace(point.mChar) || point.mChar == nbsp) {
|
2012-07-13 10:33:43 +04:00
|
|
|
*outType = WSType::normalWS;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
2012-07-13 10:33:43 +04:00
|
|
|
*outType = WSType::text;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
// If no text node, keep looking. We should eventually fall out of loop
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-12 16:12:47 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// If we get here, then nothing in ws data to find. Return end reason
|
|
|
|
*outVisNode = mEndReasonNode;
|
|
|
|
// This really isn't meaningful if mEndReasonNode != mEndNode
|
|
|
|
*outVisOffset = mEndOffset;
|
2001-04-28 16:04:45 +04:00
|
|
|
*outType = mEndReason;
|
|
|
|
}
|
|
|
|
|
2015-05-28 18:58:42 +03:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::AdjustWhitespace()
|
2001-05-11 16:43:22 +04:00
|
|
|
{
|
|
|
|
// this routine examines a run of ws and tries to get rid of some unneeded nbsp's,
|
|
|
|
// replacing them with regualr ascii space if possible. Keeping things simple
|
|
|
|
// for now and just trying to fix up the trailing ws in the run.
|
2011-07-15 01:06:37 +04:00
|
|
|
if (!mLastNBSPNode) {
|
|
|
|
// nothing to do!
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-05-11 16:43:22 +04:00
|
|
|
WSFragment *curRun = mStartRun;
|
2016-10-24 05:27:45 +03:00
|
|
|
while (curRun) {
|
2001-05-11 16:43:22 +04:00
|
|
|
// look for normal ws run
|
2012-07-13 10:33:43 +04:00
|
|
|
if (curRun->mType == WSType::normalWS) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = CheckTrailingNBSPOfRun(curRun);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
|
|
|
curRun = curRun->mRight;
|
|
|
|
}
|
2016-10-19 12:09:33 +03:00
|
|
|
return NS_OK;
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
// protected methods
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
|
2016-05-01 21:29:23 +03:00
|
|
|
nsINode*
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetWSBoundingParent()
|
2009-02-21 07:28:09 +03:00
|
|
|
{
|
2012-07-30 18:20:58 +04:00
|
|
|
NS_ENSURE_TRUE(mNode, nullptr);
|
2015-04-19 15:28:49 +03:00
|
|
|
OwningNonNull<nsINode> wsBoundingParent = *mNode;
|
2014-05-02 15:11:26 +04:00
|
|
|
while (!IsBlockNode(wsBoundingParent)) {
|
|
|
|
nsCOMPtr<nsINode> parent = wsBoundingParent->GetParentNode();
|
|
|
|
if (!parent || !mHTMLEditor->IsEditable(parent)) {
|
2009-02-21 07:28:09 +03:00
|
|
|
break;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2015-04-19 15:28:49 +03:00
|
|
|
wsBoundingParent = parent;
|
2009-02-21 07:28:09 +03:00
|
|
|
}
|
2016-05-01 21:29:23 +03:00
|
|
|
return wsBoundingParent;
|
2009-02-21 07:28:09 +03:00
|
|
|
}
|
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetWSNodes()
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
// collect up an array of nodes that are contiguous with the insertion point
|
2015-05-28 18:58:42 +03:00
|
|
|
// and which contain only whitespace. Stop if you reach non-ws text or a new
|
2001-04-28 16:04:45 +04:00
|
|
|
// block boundary.
|
2016-06-23 11:13:03 +03:00
|
|
|
EditorDOMPoint start(mNode, mOffset), end(mNode, mOffset);
|
2014-05-02 15:11:26 +04:00
|
|
|
nsCOMPtr<nsINode> wsBoundingParent = GetWSBoundingParent();
|
2001-04-28 16:04:45 +04:00
|
|
|
|
|
|
|
// first look backwards to find preceding ws nodes
|
2015-10-18 08:24:48 +03:00
|
|
|
if (RefPtr<Text> textNode = mNode->GetAsText()) {
|
2014-05-02 15:11:26 +04:00
|
|
|
const nsTextFragment* textFrag = textNode->GetText();
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2014-08-13 15:53:32 +04:00
|
|
|
mNodeArray.InsertElementAt(0, textNode);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (mOffset) {
|
|
|
|
for (int32_t pos = mOffset - 1; pos >= 0; pos--) {
|
2002-05-24 02:05:35 +04:00
|
|
|
// sanity bounds check the char position. bug 136165
|
2014-05-02 15:11:26 +04:00
|
|
|
if (uint32_t(pos) >= textFrag->GetLength()) {
|
2002-05-24 02:05:35 +04:00
|
|
|
NS_NOTREACHED("looking beyond end of text fragment");
|
|
|
|
continue;
|
|
|
|
}
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t theChar = textFrag->CharAt(pos);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(theChar)) {
|
|
|
|
if (theChar != nbsp) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mStartNode = textNode;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartOffset = pos + 1;
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartReason = WSType::text;
|
2014-08-13 15:53:32 +04:00
|
|
|
mStartReasonNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// as we look backwards update our earliest found nbsp
|
2014-08-13 15:53:32 +04:00
|
|
|
mFirstNBSPNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mFirstNBSPOffset = pos;
|
|
|
|
// also keep track of latest nbsp so far
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!mLastNBSPNode) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mLastNBSPNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mLastNBSPOffset = pos;
|
|
|
|
}
|
|
|
|
}
|
2014-08-13 15:53:32 +04:00
|
|
|
start.node = textNode;
|
2014-04-28 19:34:05 +04:00
|
|
|
start.offset = pos;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-02-07 06:56:20 +03:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
while (!mStartNode) {
|
2001-04-28 16:04:45 +04:00
|
|
|
// we haven't found the start of ws yet. Keep looking
|
2014-10-22 16:45:30 +04:00
|
|
|
nsCOMPtr<nsIContent> priorNode = GetPreviousWSNode(start, wsBoundingParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (priorNode) {
|
|
|
|
if (IsBlockNode(priorNode)) {
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartNode = start.node;
|
2014-04-28 19:34:05 +04:00
|
|
|
mStartOffset = start.offset;
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartReason = WSType::otherBlock;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartReasonNode = priorNode;
|
2015-10-18 08:24:48 +03:00
|
|
|
} else if (RefPtr<Text> textNode = priorNode->GetAsText()) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mNodeArray.InsertElementAt(0, textNode);
|
2006-07-19 08:36:36 +04:00
|
|
|
const nsTextFragment *textFrag;
|
|
|
|
if (!textNode || !(textFrag = textNode->GetText())) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t len = textNode->TextLength();
|
2002-02-08 18:20:19 +03:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
if (len < 1) {
|
2002-02-08 18:20:19 +03:00
|
|
|
// Zero length text node. Set start point to it
|
|
|
|
// so we can get past it!
|
2014-05-02 15:11:26 +04:00
|
|
|
start.SetPoint(priorNode, 0);
|
|
|
|
} else {
|
|
|
|
for (int32_t pos = len - 1; pos >= 0; pos--) {
|
2002-05-24 02:05:35 +04:00
|
|
|
// sanity bounds check the char position. bug 136165
|
2014-05-02 15:11:26 +04:00
|
|
|
if (uint32_t(pos) >= textFrag->GetLength()) {
|
2002-05-24 02:05:35 +04:00
|
|
|
NS_NOTREACHED("looking beyond end of text fragment");
|
|
|
|
continue;
|
|
|
|
}
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t theChar = textFrag->CharAt(pos);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(theChar)) {
|
|
|
|
if (theChar != nbsp) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mStartNode = textNode;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartOffset = pos + 1;
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartReason = WSType::text;
|
2014-08-13 15:53:32 +04:00
|
|
|
mStartReasonNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// as we look backwards update our earliest found nbsp
|
2014-08-13 15:53:32 +04:00
|
|
|
mFirstNBSPNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
mFirstNBSPOffset = pos;
|
|
|
|
// also keep track of latest nbsp so far
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!mLastNBSPNode) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mLastNBSPNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
mLastNBSPOffset = pos;
|
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-08-13 15:53:32 +04:00
|
|
|
start.SetPoint(textNode, pos);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
2002-02-07 06:56:20 +03:00
|
|
|
// it's a break or a special node, like <img>, that is not a block and not
|
2001-04-28 16:04:45 +04:00
|
|
|
// a break but still serves as a terminator to ws runs.
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartNode = start.node;
|
2014-04-28 19:34:05 +04:00
|
|
|
mStartOffset = start.offset;
|
2016-07-07 07:44:32 +03:00
|
|
|
if (TextEditUtils::IsBreak(priorNode)) {
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartReason = WSType::br;
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartReason = WSType::special;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
|
|
|
mStartReasonNode = priorNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
2009-02-21 07:28:09 +03:00
|
|
|
// no prior node means we exhausted wsBoundingParent
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartNode = start.node;
|
2014-04-28 19:34:05 +04:00
|
|
|
mStartOffset = start.offset;
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartReason = WSType::thisBlock;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartReasonNode = wsBoundingParent;
|
2015-05-28 18:58:42 +03:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
// then look ahead to find following ws nodes
|
2015-10-18 08:24:48 +03:00
|
|
|
if (RefPtr<Text> textNode = mNode->GetAsText()) {
|
2005-11-25 11:16:51 +03:00
|
|
|
// don't need to put it on list. it already is from code above
|
2006-07-19 08:36:36 +04:00
|
|
|
const nsTextFragment *textFrag = textNode->GetText();
|
2004-05-08 00:55:17 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t len = textNode->TextLength();
|
2014-05-02 15:11:26 +04:00
|
|
|
if (uint16_t(mOffset)<len) {
|
|
|
|
for (uint32_t pos = mOffset; pos < len; pos++) {
|
2002-05-24 02:05:35 +04:00
|
|
|
// sanity bounds check the char position. bug 136165
|
2014-05-02 15:11:26 +04:00
|
|
|
if (pos >= textFrag->GetLength()) {
|
2002-05-24 02:05:35 +04:00
|
|
|
NS_NOTREACHED("looking beyond end of text fragment");
|
|
|
|
continue;
|
|
|
|
}
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t theChar = textFrag->CharAt(pos);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(theChar)) {
|
|
|
|
if (theChar != nbsp) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mEndNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mEndOffset = pos;
|
2012-07-13 10:33:43 +04:00
|
|
|
mEndReason = WSType::text;
|
2014-08-13 15:53:32 +04:00
|
|
|
mEndReasonNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// as we look forwards update our latest found nbsp
|
2014-08-13 15:53:32 +04:00
|
|
|
mLastNBSPNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mLastNBSPOffset = pos;
|
|
|
|
// also keep track of earliest nbsp so far
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!mFirstNBSPNode) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mFirstNBSPNode = textNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mFirstNBSPOffset = pos;
|
|
|
|
}
|
|
|
|
}
|
2014-08-13 15:53:32 +04:00
|
|
|
end.SetPoint(textNode, pos + 1);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
while (!mEndNode) {
|
2001-04-28 16:04:45 +04:00
|
|
|
// we haven't found the end of ws yet. Keep looking
|
2014-10-22 16:45:30 +04:00
|
|
|
nsCOMPtr<nsIContent> nextNode = GetNextWSNode(end, wsBoundingParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (nextNode) {
|
|
|
|
if (IsBlockNode(nextNode)) {
|
2001-04-28 16:04:45 +04:00
|
|
|
// we encountered a new block. therefore no more ws.
|
2014-05-02 15:11:26 +04:00
|
|
|
mEndNode = end.node;
|
2014-04-28 19:34:05 +04:00
|
|
|
mEndOffset = end.offset;
|
2012-07-13 10:33:43 +04:00
|
|
|
mEndReason = WSType::otherBlock;
|
2014-05-02 15:11:26 +04:00
|
|
|
mEndReasonNode = nextNode;
|
2015-10-18 08:24:48 +03:00
|
|
|
} else if (RefPtr<Text> textNode = nextNode->GetAsText()) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mNodeArray.AppendElement(textNode);
|
2006-07-19 08:36:36 +04:00
|
|
|
const nsTextFragment *textFrag;
|
|
|
|
if (!textNode || !(textFrag = textNode->GetText())) {
|
|
|
|
return NS_ERROR_NULL_POINTER;
|
|
|
|
}
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t len = textNode->TextLength();
|
2002-02-08 18:20:19 +03:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
if (len < 1) {
|
2002-02-08 18:20:19 +03:00
|
|
|
// Zero length text node. Set end point to it
|
|
|
|
// so we can get past it!
|
2014-08-13 15:53:32 +04:00
|
|
|
end.SetPoint(textNode, 0);
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
|
|
|
for (uint32_t pos = 0; pos < len; pos++) {
|
2002-05-24 02:05:35 +04:00
|
|
|
// sanity bounds check the char position. bug 136165
|
2014-05-02 15:11:26 +04:00
|
|
|
if (pos >= textFrag->GetLength()) {
|
2002-05-24 02:05:35 +04:00
|
|
|
NS_NOTREACHED("looking beyond end of text fragment");
|
|
|
|
continue;
|
|
|
|
}
|
2014-01-04 19:02:17 +04:00
|
|
|
char16_t theChar = textFrag->CharAt(pos);
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(theChar)) {
|
|
|
|
if (theChar != nbsp) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mEndNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
mEndOffset = pos;
|
2012-07-13 10:33:43 +04:00
|
|
|
mEndReason = WSType::text;
|
2014-08-13 15:53:32 +04:00
|
|
|
mEndReasonNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// as we look forwards update our latest found nbsp
|
2014-08-13 15:53:32 +04:00
|
|
|
mLastNBSPNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
mLastNBSPOffset = pos;
|
|
|
|
// also keep track of earliest nbsp so far
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!mFirstNBSPNode) {
|
2014-08-13 15:53:32 +04:00
|
|
|
mFirstNBSPNode = textNode;
|
2002-02-08 18:20:19 +03:00
|
|
|
mFirstNBSPOffset = pos;
|
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-08-13 15:53:32 +04:00
|
|
|
end.SetPoint(textNode, pos + 1);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
2015-05-28 18:58:42 +03:00
|
|
|
// we encountered a break or a special node, like <img>,
|
|
|
|
// that is not a block and not a break but still
|
2002-02-07 06:56:20 +03:00
|
|
|
// serves as a terminator to ws runs.
|
2014-05-02 15:11:26 +04:00
|
|
|
mEndNode = end.node;
|
2014-04-28 19:34:05 +04:00
|
|
|
mEndOffset = end.offset;
|
2016-07-07 07:44:32 +03:00
|
|
|
if (TextEditUtils::IsBreak(nextNode)) {
|
2012-07-13 10:33:43 +04:00
|
|
|
mEndReason = WSType::br;
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
2012-07-13 10:33:43 +04:00
|
|
|
mEndReason = WSType::special;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
|
|
|
mEndReasonNode = nextNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
} else {
|
2009-02-21 07:28:09 +03:00
|
|
|
// no next node means we exhausted wsBoundingParent
|
2014-05-02 15:11:26 +04:00
|
|
|
mEndNode = end.node;
|
2014-04-28 19:34:05 +04:00
|
|
|
mEndOffset = end.offset;
|
2012-07-13 10:33:43 +04:00
|
|
|
mEndReason = WSType::thisBlock;
|
2014-05-02 15:11:26 +04:00
|
|
|
mEndReasonNode = wsBoundingParent;
|
2015-05-28 18:58:42 +03:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetRuns()
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
ClearRuns();
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
// handle some easy cases first
|
2014-05-02 15:11:26 +04:00
|
|
|
mHTMLEditor->IsPreformatted(GetAsDOMNode(mNode), &mPRE);
|
2002-02-19 14:52:50 +03:00
|
|
|
// if it's preformatedd, or if we are surrounded by text or special, it's all one
|
2001-04-28 16:04:45 +04:00
|
|
|
// big normal ws run
|
2012-07-13 10:33:43 +04:00
|
|
|
if (mPRE ||
|
|
|
|
((mStartReason == WSType::text || mStartReason == WSType::special) &&
|
|
|
|
(mEndReason == WSType::text || mEndReason == WSType::special ||
|
|
|
|
mEndReason == WSType::br))) {
|
|
|
|
MakeSingleWSRun(WSType::normalWS);
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// if we are before or after a block (or after a break), and there are no nbsp's,
|
|
|
|
// then it's all non-rendering ws.
|
2012-07-13 10:33:43 +04:00
|
|
|
if (!mFirstNBSPNode && !mLastNBSPNode &&
|
|
|
|
((mStartReason & WSType::block) || mStartReason == WSType::br ||
|
|
|
|
(mEndReason & WSType::block))) {
|
|
|
|
WSType wstype;
|
|
|
|
if ((mStartReason & WSType::block) || mStartReason == WSType::br) {
|
|
|
|
wstype = WSType::leadingWS;
|
|
|
|
}
|
|
|
|
if (mEndReason & WSType::block) {
|
|
|
|
wstype |= WSType::trailingWS;
|
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
MakeSingleWSRun(wstype);
|
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
// otherwise a little trickier. shucks.
|
|
|
|
mStartRun = new WSFragment();
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartRun->mStartNode = mStartNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mStartRun->mStartOffset = mStartOffset;
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2012-07-13 10:33:43 +04:00
|
|
|
if (mStartReason & WSType::block || mStartReason == WSType::br) {
|
2001-04-28 16:04:45 +04:00
|
|
|
// set up mStartRun
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartRun->mType = WSType::leadingWS;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartRun->mEndNode = mFirstNBSPNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mStartRun->mEndOffset = mFirstNBSPOffset;
|
|
|
|
mStartRun->mLeftType = mStartReason;
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartRun->mRightType = WSType::normalWS;
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
// set up next run
|
|
|
|
WSFragment *normalRun = new WSFragment();
|
|
|
|
mStartRun->mRight = normalRun;
|
2012-07-13 10:33:43 +04:00
|
|
|
normalRun->mType = WSType::normalWS;
|
2014-05-02 15:11:26 +04:00
|
|
|
normalRun->mStartNode = mFirstNBSPNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
normalRun->mStartOffset = mFirstNBSPOffset;
|
2012-07-13 10:33:43 +04:00
|
|
|
normalRun->mLeftType = WSType::leadingWS;
|
2001-04-28 16:04:45 +04:00
|
|
|
normalRun->mLeft = mStartRun;
|
2012-07-13 10:33:43 +04:00
|
|
|
if (mEndReason != WSType::block) {
|
2001-04-28 16:04:45 +04:00
|
|
|
// then no trailing ws. this normal run ends the overall ws run.
|
|
|
|
normalRun->mRightType = mEndReason;
|
2014-05-02 15:11:26 +04:00
|
|
|
normalRun->mEndNode = mEndNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
normalRun->mEndOffset = mEndOffset;
|
|
|
|
mEndRun = normalRun;
|
2016-10-24 05:27:45 +03:00
|
|
|
} else {
|
2001-04-28 16:04:45 +04:00
|
|
|
// we might have trailing ws.
|
2001-05-11 16:43:22 +04:00
|
|
|
// it so happens that *if* there is an nbsp at end, {mEndNode,mEndOffset-1}
|
|
|
|
// will point to it, even though in general start/end points not
|
|
|
|
// guaranteed to be in text nodes.
|
2016-10-24 05:27:45 +03:00
|
|
|
if (mLastNBSPNode == mEndNode && mLastNBSPOffset == mEndOffset - 1) {
|
2001-04-28 16:04:45 +04:00
|
|
|
// normal ws runs right up to adjacent block (nbsp next to block)
|
|
|
|
normalRun->mRightType = mEndReason;
|
2014-05-02 15:11:26 +04:00
|
|
|
normalRun->mEndNode = mEndNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
normalRun->mEndOffset = mEndOffset;
|
|
|
|
mEndRun = normalRun;
|
2016-10-24 05:27:45 +03:00
|
|
|
} else {
|
2014-05-02 15:11:26 +04:00
|
|
|
normalRun->mEndNode = mLastNBSPNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
normalRun->mEndOffset = mLastNBSPOffset+1;
|
2012-07-13 10:33:43 +04:00
|
|
|
normalRun->mRightType = WSType::trailingWS;
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
// set up next run
|
|
|
|
WSFragment *lastRun = new WSFragment();
|
2012-07-13 10:33:43 +04:00
|
|
|
lastRun->mType = WSType::trailingWS;
|
2014-05-02 15:11:26 +04:00
|
|
|
lastRun->mStartNode = mLastNBSPNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
lastRun->mStartOffset = mLastNBSPOffset+1;
|
2014-05-02 15:11:26 +04:00
|
|
|
lastRun->mEndNode = mEndNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
lastRun->mEndOffset = mEndOffset;
|
2012-07-13 10:33:43 +04:00
|
|
|
lastRun->mLeftType = WSType::normalWS;
|
2001-04-28 16:04:45 +04:00
|
|
|
lastRun->mLeft = normalRun;
|
|
|
|
lastRun->mRightType = mEndReason;
|
|
|
|
mEndRun = lastRun;
|
|
|
|
normalRun->mRight = lastRun;
|
|
|
|
}
|
|
|
|
}
|
2012-07-13 10:33:43 +04:00
|
|
|
} else {
|
|
|
|
// mStartReason is not WSType::block or WSType::br; set up mStartRun
|
|
|
|
mStartRun->mType = WSType::normalWS;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartRun->mEndNode = mLastNBSPNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mStartRun->mEndOffset = mLastNBSPOffset+1;
|
|
|
|
mStartRun->mLeftType = mStartReason;
|
|
|
|
|
|
|
|
// we might have trailing ws.
|
2001-05-11 16:43:22 +04:00
|
|
|
// it so happens that *if* there is an nbsp at end, {mEndNode,mEndOffset-1}
|
|
|
|
// will point to it, even though in general start/end points not
|
|
|
|
// guaranteed to be in text nodes.
|
2016-10-24 05:27:45 +03:00
|
|
|
if (mLastNBSPNode == mEndNode && mLastNBSPOffset == (mEndOffset - 1)) {
|
2002-11-17 04:25:30 +03:00
|
|
|
mStartRun->mRightType = mEndReason;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartRun->mEndNode = mEndNode;
|
2002-11-17 04:25:30 +03:00
|
|
|
mStartRun->mEndOffset = mEndOffset;
|
|
|
|
mEndRun = mStartRun;
|
2016-10-24 05:27:45 +03:00
|
|
|
} else {
|
2001-04-28 16:04:45 +04:00
|
|
|
// set up next run
|
|
|
|
WSFragment *lastRun = new WSFragment();
|
2012-07-13 10:33:43 +04:00
|
|
|
lastRun->mType = WSType::trailingWS;
|
2014-05-02 15:11:26 +04:00
|
|
|
lastRun->mStartNode = mLastNBSPNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
lastRun->mStartOffset = mLastNBSPOffset+1;
|
2012-07-13 10:33:43 +04:00
|
|
|
lastRun->mLeftType = WSType::normalWS;
|
2001-04-28 16:04:45 +04:00
|
|
|
lastRun->mLeft = mStartRun;
|
|
|
|
lastRun->mRightType = mEndReason;
|
|
|
|
mEndRun = lastRun;
|
|
|
|
mStartRun->mRight = lastRun;
|
2012-07-13 10:33:43 +04:00
|
|
|
mStartRun->mRightType = WSType::trailingWS;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::ClearRuns()
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
WSFragment *tmp, *run;
|
|
|
|
run = mStartRun;
|
2016-10-24 05:27:45 +03:00
|
|
|
while (run) {
|
2001-04-28 16:04:45 +04:00
|
|
|
tmp = run->mRight;
|
|
|
|
delete run;
|
|
|
|
run = tmp;
|
|
|
|
}
|
|
|
|
mStartRun = 0;
|
|
|
|
mEndRun = 0;
|
|
|
|
}
|
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::MakeSingleWSRun(WSType aType)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
mStartRun = new WSFragment();
|
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartRun->mStartNode = mStartNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mStartRun->mStartOffset = mStartOffset;
|
|
|
|
mStartRun->mType = aType;
|
2014-05-02 15:11:26 +04:00
|
|
|
mStartRun->mEndNode = mEndNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
mStartRun->mEndOffset = mEndOffset;
|
|
|
|
mStartRun->mLeftType = mStartReason;
|
|
|
|
mStartRun->mRightType = mEndReason;
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-04-28 16:04:45 +04:00
|
|
|
mEndRun = mStartRun;
|
|
|
|
}
|
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
nsIContent*
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetPreviousWSNodeInner(nsINode* aStartNode,
|
|
|
|
nsINode* aBlockParent)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-10-22 16:45:30 +04:00
|
|
|
// Can't really recycle various getnext/prior routines because we have
|
2014-05-02 15:11:26 +04:00
|
|
|
// special needs here. Need to step into inline containers but not block
|
|
|
|
// containers.
|
2014-10-22 16:45:30 +04:00
|
|
|
MOZ_ASSERT(aStartNode && aBlockParent);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> priorNode = aStartNode->GetPreviousSibling();
|
2015-04-19 15:28:49 +03:00
|
|
|
OwningNonNull<nsINode> curNode = *aStartNode;
|
2014-10-22 16:45:30 +04:00
|
|
|
while (!priorNode) {
|
|
|
|
// We have exhausted nodes in parent of aStartNode.
|
|
|
|
nsCOMPtr<nsINode> curParent = curNode->GetParentNode();
|
|
|
|
NS_ENSURE_TRUE(curParent, nullptr);
|
|
|
|
if (curParent == aBlockParent) {
|
|
|
|
// We have exhausted nodes in the block parent. The convention here is
|
2014-05-02 15:11:26 +04:00
|
|
|
// to return null.
|
2014-10-22 16:45:30 +04:00
|
|
|
return nullptr;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// We have a parent: look for previous sibling
|
|
|
|
priorNode = curParent->GetPreviousSibling();
|
|
|
|
curNode = curParent;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// We have a prior node. If it's a block, return it.
|
|
|
|
if (IsBlockNode(priorNode)) {
|
|
|
|
return priorNode;
|
|
|
|
}
|
|
|
|
if (mHTMLEditor->IsContainer(priorNode)) {
|
|
|
|
// Else if it's a container, get deep rightmost child
|
|
|
|
nsCOMPtr<nsIContent> child = mHTMLEditor->GetRightmostChild(priorNode);
|
|
|
|
if (child) {
|
|
|
|
return child;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// Else return the node itself
|
|
|
|
return priorNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
nsIContent*
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetPreviousWSNode(EditorDOMPoint aPoint,
|
|
|
|
nsINode* aBlockParent)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-10-22 16:45:30 +04:00
|
|
|
// Can't really recycle various getnext/prior routines because we
|
2003-09-27 08:18:26 +04:00
|
|
|
// have special needs here. Need to step into inline containers but
|
|
|
|
// not block containers.
|
2014-10-22 16:45:30 +04:00
|
|
|
MOZ_ASSERT(aPoint.node && aBlockParent);
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
if (aPoint.node->NodeType() == nsIDOMNode::TEXT_NODE) {
|
2014-10-22 16:45:30 +04:00
|
|
|
return GetPreviousWSNodeInner(aPoint.node, aBlockParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
|
|
|
if (!mHTMLEditor->IsContainer(aPoint.node)) {
|
2014-10-22 16:45:30 +04:00
|
|
|
return GetPreviousWSNodeInner(aPoint.node, aBlockParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!aPoint.offset) {
|
|
|
|
if (aPoint.node == aBlockParent) {
|
2014-10-22 16:45:30 +04:00
|
|
|
// We are at start of the block.
|
|
|
|
return nullptr;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
// We are at start of non-block container
|
|
|
|
return GetPreviousWSNodeInner(aPoint.node, aBlockParent);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
nsCOMPtr<nsIContent> startContent = do_QueryInterface(aPoint.node);
|
|
|
|
NS_ENSURE_TRUE(startContent, nullptr);
|
|
|
|
nsCOMPtr<nsIContent> priorNode = startContent->GetChildAt(aPoint.offset - 1);
|
|
|
|
NS_ENSURE_TRUE(priorNode, nullptr);
|
|
|
|
// We have a prior node. If it's a block, return it.
|
|
|
|
if (IsBlockNode(priorNode)) {
|
|
|
|
return priorNode;
|
|
|
|
}
|
|
|
|
if (mHTMLEditor->IsContainer(priorNode)) {
|
|
|
|
// Else if it's a container, get deep rightmost child
|
|
|
|
nsCOMPtr<nsIContent> child = mHTMLEditor->GetRightmostChild(priorNode);
|
|
|
|
if (child) {
|
|
|
|
return child;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// Else return the node itself
|
|
|
|
return priorNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
nsIContent*
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetNextWSNodeInner(nsINode* aStartNode,
|
|
|
|
nsINode* aBlockParent)
|
2002-02-07 06:56:20 +03:00
|
|
|
{
|
2014-10-22 16:45:30 +04:00
|
|
|
// Can't really recycle various getnext/prior routines because we have
|
2014-05-02 15:11:26 +04:00
|
|
|
// special needs here. Need to step into inline containers but not block
|
|
|
|
// containers.
|
2014-10-22 16:45:30 +04:00
|
|
|
MOZ_ASSERT(aStartNode && aBlockParent);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> nextNode = aStartNode->GetNextSibling();
|
|
|
|
nsCOMPtr<nsINode> curNode = aStartNode;
|
|
|
|
while (!nextNode) {
|
|
|
|
// We have exhausted nodes in parent of aStartNode.
|
|
|
|
nsCOMPtr<nsINode> curParent = curNode->GetParentNode();
|
|
|
|
NS_ENSURE_TRUE(curParent, nullptr);
|
|
|
|
if (curParent == aBlockParent) {
|
|
|
|
// We have exhausted nodes in the block parent. The convention here is
|
2014-05-02 15:11:26 +04:00
|
|
|
// to return null.
|
2014-10-22 16:45:30 +04:00
|
|
|
return nullptr;
|
2002-02-07 06:56:20 +03:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// We have a parent: look for next sibling
|
|
|
|
nextNode = curParent->GetNextSibling();
|
|
|
|
curNode = curParent;
|
2002-02-07 06:56:20 +03:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// We have a next node. If it's a block, return it.
|
|
|
|
if (IsBlockNode(nextNode)) {
|
|
|
|
return nextNode;
|
|
|
|
}
|
|
|
|
if (mHTMLEditor->IsContainer(nextNode)) {
|
|
|
|
// Else if it's a container, get deep leftmost child
|
|
|
|
nsCOMPtr<nsIContent> child = mHTMLEditor->GetLeftmostChild(nextNode);
|
|
|
|
if (child) {
|
|
|
|
return child;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2002-02-07 06:56:20 +03:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// Else return the node itself
|
|
|
|
return nextNode;
|
2002-02-07 06:56:20 +03:00
|
|
|
}
|
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
nsIContent*
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetNextWSNode(EditorDOMPoint aPoint,
|
|
|
|
nsINode* aBlockParent)
|
2002-02-07 06:56:20 +03:00
|
|
|
{
|
2014-10-22 16:45:30 +04:00
|
|
|
// Can't really recycle various getnext/prior routines because we have
|
2014-05-02 15:11:26 +04:00
|
|
|
// special needs here. Need to step into inline containers but not block
|
|
|
|
// containers.
|
2014-10-22 16:45:30 +04:00
|
|
|
MOZ_ASSERT(aPoint.node && aBlockParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
|
|
|
if (aPoint.node->NodeType() == nsIDOMNode::TEXT_NODE) {
|
2014-10-22 16:45:30 +04:00
|
|
|
return GetNextWSNodeInner(aPoint.node, aBlockParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
|
|
|
if (!mHTMLEditor->IsContainer(aPoint.node)) {
|
2014-10-22 16:45:30 +04:00
|
|
|
return GetNextWSNodeInner(aPoint.node, aBlockParent);
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> startContent = do_QueryInterface(aPoint.node);
|
|
|
|
NS_ENSURE_TRUE(startContent, nullptr);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> nextNode = startContent->GetChildAt(aPoint.offset);
|
|
|
|
if (!nextNode) {
|
2014-05-02 15:11:26 +04:00
|
|
|
if (aPoint.node == aBlockParent) {
|
2014-10-22 16:45:30 +04:00
|
|
|
// We are at end of the block.
|
|
|
|
return nullptr;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2003-09-27 08:18:26 +04:00
|
|
|
|
2014-10-22 16:45:30 +04:00
|
|
|
// We are at end of non-block container
|
|
|
|
return GetNextWSNodeInner(aPoint.node, aBlockParent);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
|
|
|
|
// We have a next node. If it's a block, return it.
|
|
|
|
if (IsBlockNode(nextNode)) {
|
|
|
|
return nextNode;
|
|
|
|
}
|
|
|
|
if (mHTMLEditor->IsContainer(nextNode)) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// else if it's a container, get deep leftmost child
|
2014-10-22 16:45:30 +04:00
|
|
|
nsCOMPtr<nsIContent> child = mHTMLEditor->GetLeftmostChild(nextNode);
|
|
|
|
if (child) {
|
|
|
|
return child;
|
2014-05-02 15:11:26 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-10-22 16:45:30 +04:00
|
|
|
// Else return the node itself
|
|
|
|
return nextNode;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2015-05-28 18:58:42 +03:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::PrepareToDeleteRangePriv(WSRunObject* aEndObject)
|
2001-05-10 15:55:49 +04:00
|
|
|
{
|
|
|
|
// this routine adjust whitespace before *this* and after aEndObject
|
2015-05-28 18:58:42 +03:00
|
|
|
// in preperation for the two areas to become adjacent after the
|
2001-05-10 15:55:49 +04:00
|
|
|
// intervening content is deleted. It's overly agressive right
|
|
|
|
// now. There might be a block boundary remaining between them after
|
|
|
|
// the deletion, in which case these adjstments are unneeded (though
|
|
|
|
// I don't think they can ever be harmful?)
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2010-06-18 00:40:48 +04:00
|
|
|
NS_ENSURE_TRUE(aEndObject, NS_ERROR_NULL_POINTER);
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
// get the runs before and after selection
|
|
|
|
WSFragment *beforeRun, *afterRun;
|
2014-05-02 16:15:27 +04:00
|
|
|
FindRun(mNode, mOffset, &beforeRun, false);
|
|
|
|
aEndObject->FindRun(aEndObject->mNode, aEndObject->mOffset, &afterRun, true);
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
// trim after run of any leading ws
|
2012-07-13 10:33:43 +04:00
|
|
|
if (afterRun && (afterRun->mType & WSType::leadingWS)) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
aEndObject->DeleteChars(aEndObject->mNode, aEndObject->mOffset,
|
|
|
|
afterRun->mEndNode, afterRun->mEndOffset,
|
|
|
|
eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
// adjust normal ws in afterRun if needed
|
2012-07-13 10:33:43 +04:00
|
|
|
if (afterRun && afterRun->mType == WSType::normalWS && !aEndObject->mPRE) {
|
|
|
|
if ((beforeRun && (beforeRun->mType & WSType::leadingWS)) ||
|
|
|
|
(!beforeRun && ((mStartReason & WSType::block) ||
|
|
|
|
mStartReason == WSType::br))) {
|
2001-05-10 15:55:49 +04:00
|
|
|
// make sure leading char of following ws is an nbsp, so that it will show up
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = aEndObject->GetCharAfter(aEndObject->mNode,
|
2012-06-01 15:03:17 +04:00
|
|
|
aEndObject->mOffset);
|
2016-10-24 05:27:45 +03:00
|
|
|
if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = aEndObject->ConvertToNBSP(point, eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// trim before run of any trailing ws
|
2012-07-13 10:33:43 +04:00
|
|
|
if (beforeRun && (beforeRun->mType & WSType::trailingWS)) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = DeleteChars(beforeRun->mStartNode, beforeRun->mStartOffset,
|
|
|
|
mNode, mOffset, eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2012-07-13 10:33:43 +04:00
|
|
|
} else if (beforeRun && beforeRun->mType == WSType::normalWS && !mPRE) {
|
|
|
|
if ((afterRun && (afterRun->mType & WSType::trailingWS)) ||
|
|
|
|
(afterRun && afterRun->mType == WSType::normalWS) ||
|
|
|
|
(!afterRun && (aEndObject->mEndReason & WSType::block))) {
|
2001-05-10 15:55:49 +04:00
|
|
|
// make sure trailing char of starting ws is an nbsp, so that it will show up
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharBefore(mNode, mOffset);
|
2016-10-24 05:27:45 +03:00
|
|
|
if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> wsStartNode, wsEndNode;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t wsStartOffset, wsEndOffset;
|
2014-05-02 16:15:27 +04:00
|
|
|
GetAsciiWSBounds(eBoth, mNode, mOffset,
|
|
|
|
getter_AddRefs(wsStartNode), &wsStartOffset,
|
|
|
|
getter_AddRefs(wsEndNode), &wsEndOffset);
|
|
|
|
point.mTextNode = wsStartNode;
|
2001-05-10 15:55:49 +04:00
|
|
|
point.mOffset = wsStartOffset;
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = ConvertToNBSP(point, eOutsideUserSelectAll);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-10-19 12:09:33 +03:00
|
|
|
return NS_OK;
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
|
2015-05-28 18:58:42 +03:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::PrepareToSplitAcrossBlocksPriv()
|
2001-05-11 16:43:22 +04:00
|
|
|
{
|
2015-05-28 18:58:42 +03:00
|
|
|
// used to prepare ws to be split across two blocks. The main issue
|
2001-05-11 16:43:22 +04:00
|
|
|
// here is make sure normalWS doesn't end up becoming non-significant
|
|
|
|
// leading or trailing ws after the split.
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-05-11 16:43:22 +04:00
|
|
|
// get the runs before and after selection
|
|
|
|
WSFragment *beforeRun, *afterRun;
|
2014-05-02 16:15:27 +04:00
|
|
|
FindRun(mNode, mOffset, &beforeRun, false);
|
|
|
|
FindRun(mNode, mOffset, &afterRun, true);
|
2015-05-28 18:58:42 +03:00
|
|
|
|
2001-05-11 16:43:22 +04:00
|
|
|
// adjust normal ws in afterRun if needed
|
2012-07-13 10:33:43 +04:00
|
|
|
if (afterRun && afterRun->mType == WSType::normalWS) {
|
2001-05-11 16:43:22 +04:00
|
|
|
// make sure leading char of following ws is an nbsp, so that it will show up
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharAfter(mNode, mOffset);
|
2016-10-24 05:27:45 +03:00
|
|
|
if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = ConvertToNBSP(point);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust normal ws in beforeRun if needed
|
2012-07-13 10:33:43 +04:00
|
|
|
if (beforeRun && beforeRun->mType == WSType::normalWS) {
|
2001-05-11 16:43:22 +04:00
|
|
|
// make sure trailing char of starting ws is an nbsp, so that it will show up
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint point = GetCharBefore(mNode, mOffset);
|
2016-10-24 05:27:45 +03:00
|
|
|
if (point.mTextNode && nsCRT::IsAsciiSpace(point.mChar)) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> wsStartNode, wsEndNode;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t wsStartOffset, wsEndOffset;
|
2014-05-02 16:15:27 +04:00
|
|
|
GetAsciiWSBounds(eBoth, mNode, mOffset,
|
|
|
|
getter_AddRefs(wsStartNode), &wsStartOffset,
|
|
|
|
getter_AddRefs(wsEndNode), &wsEndOffset);
|
|
|
|
point.mTextNode = wsStartNode;
|
2001-05-11 16:43:22 +04:00
|
|
|
point.mOffset = wsStartOffset;
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = ConvertToNBSP(point);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
|
|
|
}
|
2016-10-19 12:09:33 +03:00
|
|
|
return NS_OK;
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::DeleteChars(nsINode* aStartNode,
|
|
|
|
int32_t aStartOffset,
|
|
|
|
nsINode* aEndNode,
|
|
|
|
int32_t aEndOffset,
|
|
|
|
AreaRestriction aAR)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
// MOOSE: this routine needs to be modified to preserve the integrity of the
|
|
|
|
// wsFragment info.
|
2010-06-18 00:40:48 +04:00
|
|
|
NS_ENSURE_TRUE(aStartNode && aEndNode, NS_ERROR_NULL_POINTER);
|
2001-05-10 15:55:49 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
if (aAR == eOutsideUserSelectAll) {
|
|
|
|
nsCOMPtr<nsIDOMNode> san =
|
|
|
|
mHTMLEditor->FindUserSelectAllNode(GetAsDOMNode(aStartNode));
|
|
|
|
if (san) {
|
2003-06-11 16:02:49 +04:00
|
|
|
return NS_OK;
|
2014-05-02 16:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (aStartNode != aEndNode) {
|
|
|
|
san = mHTMLEditor->FindUserSelectAllNode(GetAsDOMNode(aEndNode));
|
|
|
|
if (san) {
|
2003-06-11 16:02:49 +04:00
|
|
|
return NS_OK;
|
2014-05-02 16:15:27 +04:00
|
|
|
}
|
2003-06-11 16:02:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
if (aStartNode == aEndNode && aStartOffset == aEndOffset) {
|
|
|
|
// Nothing to delete
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
int32_t idx = mNodeArray.IndexOf(aStartNode);
|
|
|
|
if (idx == -1) {
|
|
|
|
// If our strarting point wasn't one of our ws text nodes, then just go
|
|
|
|
// through them from the beginning.
|
|
|
|
idx = 0;
|
|
|
|
}
|
|
|
|
|
2014-08-13 15:53:32 +04:00
|
|
|
if (aStartNode == aEndNode && aStartNode->GetAsText()) {
|
2014-08-20 16:25:16 +04:00
|
|
|
return mHTMLEditor->DeleteText(*aStartNode->GetAsText(),
|
|
|
|
static_cast<uint32_t>(aStartOffset),
|
|
|
|
static_cast<uint32_t>(aEndOffset - aStartOffset));
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<nsRange> range;
|
2014-05-02 16:15:27 +04:00
|
|
|
int32_t count = mNodeArray.Length();
|
2014-05-02 16:15:27 +04:00
|
|
|
for (; idx < count; idx++) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> node = mNodeArray[idx];
|
2014-05-02 16:15:27 +04:00
|
|
|
if (!node) {
|
|
|
|
// We ran out of ws nodes; must have been deleting to end
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
if (node == aStartNode) {
|
|
|
|
uint32_t len = node->Length();
|
|
|
|
if (uint32_t(aStartOffset) < len) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
mHTMLEditor->DeleteText(*node, AssertedCast<uint32_t>(aStartOffset),
|
|
|
|
len - aStartOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
} else if (node == aEndNode) {
|
|
|
|
if (aEndOffset) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
mHTMLEditor->DeleteText(*node, 0, AssertedCast<uint32_t>(aEndOffset));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
break;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
|
|
|
if (!range) {
|
|
|
|
range = new nsRange(aStartNode);
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
range->Set(aStartNode, aStartOffset, aEndNode, aEndOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2011-09-29 10:19:26 +04:00
|
|
|
bool nodeBefore, nodeAfter;
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
nsRange::CompareNodeToRange(node, range, &nodeBefore, &nodeAfter);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:27 +04:00
|
|
|
if (nodeAfter) {
|
2001-04-28 16:04:45 +04:00
|
|
|
break;
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
if (!nodeBefore) {
|
2016-10-19 12:09:33 +03:00
|
|
|
rv = mHTMLEditor->DeleteNode(node);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:27 +04:00
|
|
|
mNodeArray.RemoveElement(node);
|
2003-01-16 22:27:50 +03:00
|
|
|
--count;
|
|
|
|
--idx;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
return NS_OK;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::WSPoint
|
|
|
|
WSRunObject::GetCharAfter(nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2012-06-01 15:03:17 +04:00
|
|
|
MOZ_ASSERT(aNode);
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
int32_t idx = mNodeArray.IndexOf(aNode);
|
|
|
|
if (idx == -1) {
|
|
|
|
// Use range comparisons to get right ws node
|
2014-05-02 16:15:27 +04:00
|
|
|
return GetWSPointAfter(aNode, aOffset);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2016-10-24 05:27:45 +03:00
|
|
|
// Use WSPoint version of GetCharAfter()
|
|
|
|
return GetCharAfter(WSPoint(mNodeArray[idx], aOffset, 0));
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::WSPoint
|
|
|
|
WSRunObject::GetCharBefore(nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2012-06-01 15:03:17 +04:00
|
|
|
MOZ_ASSERT(aNode);
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
int32_t idx = mNodeArray.IndexOf(aNode);
|
|
|
|
if (idx == -1) {
|
|
|
|
// Use range comparisons to get right ws node
|
2014-05-02 16:15:27 +04:00
|
|
|
return GetWSPointBefore(aNode, aOffset);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2016-10-24 05:27:45 +03:00
|
|
|
// Use WSPoint version of GetCharBefore()
|
|
|
|
return GetCharBefore(WSPoint(mNodeArray[idx], aOffset, 0));
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::WSPoint
|
|
|
|
WSRunObject::GetCharAfter(const WSPoint &aPoint)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2012-06-01 15:03:17 +04:00
|
|
|
MOZ_ASSERT(aPoint.mTextNode);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
WSPoint outPoint;
|
2012-07-30 18:20:58 +04:00
|
|
|
outPoint.mTextNode = nullptr;
|
2012-06-01 15:03:17 +04:00
|
|
|
outPoint.mOffset = 0;
|
|
|
|
outPoint.mChar = 0;
|
2002-11-12 22:40:11 +03:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
int32_t idx = mNodeArray.IndexOf(aPoint.mTextNode);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (idx == -1) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Can't find point, but it's not an error
|
2012-06-01 15:03:17 +04:00
|
|
|
return outPoint;
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2016-10-24 05:27:45 +03:00
|
|
|
if (static_cast<uint16_t>(aPoint.mOffset) < aPoint.mTextNode->TextLength()) {
|
2012-06-01 15:03:17 +04:00
|
|
|
outPoint = aPoint;
|
|
|
|
outPoint.mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset);
|
|
|
|
return outPoint;
|
2016-10-24 05:27:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int32_t numNodes = mNodeArray.Length();
|
|
|
|
if (idx + 1 < numNodes) {
|
2014-05-02 16:15:27 +04:00
|
|
|
outPoint.mTextNode = mNodeArray[idx + 1];
|
2014-05-02 16:15:27 +04:00
|
|
|
MOZ_ASSERT(outPoint.mTextNode);
|
2012-06-01 15:03:17 +04:00
|
|
|
outPoint.mOffset = 0;
|
|
|
|
outPoint.mChar = GetCharAt(outPoint.mTextNode, 0);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2016-10-24 05:27:45 +03:00
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
return outPoint;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::WSPoint
|
|
|
|
WSRunObject::GetCharBefore(const WSPoint &aPoint)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2012-06-01 15:03:17 +04:00
|
|
|
MOZ_ASSERT(aPoint.mTextNode);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
WSPoint outPoint;
|
2012-07-30 18:20:58 +04:00
|
|
|
outPoint.mTextNode = nullptr;
|
2012-06-01 15:03:17 +04:00
|
|
|
outPoint.mOffset = 0;
|
|
|
|
outPoint.mChar = 0;
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
int32_t idx = mNodeArray.IndexOf(aPoint.mTextNode);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (idx == -1) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Can't find point, but it's not an error
|
2012-06-01 15:03:17 +04:00
|
|
|
return outPoint;
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
2016-10-24 05:27:45 +03:00
|
|
|
if (aPoint.mOffset) {
|
2012-06-01 15:03:17 +04:00
|
|
|
outPoint = aPoint;
|
|
|
|
outPoint.mOffset--;
|
2014-05-02 16:15:27 +04:00
|
|
|
outPoint.mChar = GetCharAt(aPoint.mTextNode, aPoint.mOffset - 1);
|
2012-06-01 15:03:17 +04:00
|
|
|
return outPoint;
|
2016-10-24 05:27:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (idx) {
|
2014-05-02 16:15:27 +04:00
|
|
|
outPoint.mTextNode = mNodeArray[idx - 1];
|
2004-05-08 00:55:17 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint32_t len = outPoint.mTextNode->TextLength();
|
2014-05-02 16:15:27 +04:00
|
|
|
if (len) {
|
|
|
|
outPoint.mOffset = len - 1;
|
|
|
|
outPoint.mChar = GetCharAt(outPoint.mTextNode, len - 1);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
return outPoint;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::ConvertToNBSP(WSPoint aPoint, AreaRestriction aAR)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
// MOOSE: this routine needs to be modified to preserve the integrity of the
|
|
|
|
// wsFragment info.
|
2010-06-18 00:40:48 +04:00
|
|
|
NS_ENSURE_TRUE(aPoint.mTextNode, NS_ERROR_NULL_POINTER);
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
if (aAR == eOutsideUserSelectAll) {
|
|
|
|
nsCOMPtr<nsIDOMNode> san =
|
|
|
|
mHTMLEditor->FindUserSelectAllNode(GetAsDOMNode(aPoint.mTextNode));
|
|
|
|
if (san) {
|
|
|
|
return NS_OK;
|
2003-06-11 16:02:49 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
// First, insert an nbsp
|
2016-06-23 12:01:23 +03:00
|
|
|
AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor);
|
2001-04-28 16:04:45 +04:00
|
|
|
nsAutoString nbspStr(nbsp);
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
mHTMLEditor->InsertTextIntoTextNodeImpl(nbspStr, *aPoint.mTextNode,
|
|
|
|
aPoint.mOffset, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Next, find range of ws it will replace
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> startNode, endNode;
|
2014-05-02 16:15:27 +04:00
|
|
|
int32_t startOffset = 0, endOffset = 0;
|
|
|
|
|
|
|
|
GetAsciiWSBounds(eAfter, aPoint.mTextNode, aPoint.mOffset + 1,
|
|
|
|
getter_AddRefs(startNode), &startOffset,
|
|
|
|
getter_AddRefs(endNode), &endOffset);
|
|
|
|
|
|
|
|
// Finally, delete that replaced ws, if any
|
|
|
|
if (startNode) {
|
2016-10-19 12:09:33 +03:00
|
|
|
rv = DeleteChars(startNode, startOffset, endNode, endOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
|
2014-05-02 15:11:26 +04:00
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetAsciiWSBounds(int16_t aDir,
|
|
|
|
nsINode* aNode,
|
|
|
|
int32_t aOffset,
|
|
|
|
Text** outStartNode,
|
|
|
|
int32_t* outStartOffset,
|
|
|
|
Text** outEndNode,
|
|
|
|
int32_t* outEndOffset)
|
2014-05-02 15:11:26 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
MOZ_ASSERT(aNode && outStartNode && outStartOffset && outEndNode &&
|
|
|
|
outEndOffset);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> startNode, endNode;
|
2014-05-02 16:15:27 +04:00
|
|
|
int32_t startOffset = 0, endOffset = 0;
|
2001-05-10 15:55:49 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
if (aDir & eAfter) {
|
|
|
|
WSPoint point = GetCharAfter(aNode, aOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (point.mTextNode) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// We found a text node, at least
|
|
|
|
startNode = endNode = point.mTextNode;
|
|
|
|
startOffset = endOffset = point.mOffset;
|
|
|
|
|
|
|
|
// Scan ahead to end of ASCII ws
|
|
|
|
for (; nsCRT::IsAsciiSpace(point.mChar) && point.mTextNode;
|
|
|
|
point = GetCharAfter(point)) {
|
|
|
|
endNode = point.mTextNode;
|
|
|
|
// endOffset is _after_ ws
|
|
|
|
point.mOffset++;
|
2001-05-10 15:55:49 +04:00
|
|
|
endOffset = point.mOffset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
if (aDir & eBefore) {
|
|
|
|
WSPoint point = GetCharBefore(aNode, aOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (point.mTextNode) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// We found a text node, at least
|
|
|
|
startNode = point.mTextNode;
|
|
|
|
startOffset = point.mOffset + 1;
|
|
|
|
if (!endNode) {
|
2001-05-10 15:55:49 +04:00
|
|
|
endNode = startNode;
|
|
|
|
endOffset = startOffset;
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Scan back to start of ASCII ws
|
|
|
|
for (; nsCRT::IsAsciiSpace(point.mChar) && point.mTextNode;
|
|
|
|
point = GetCharBefore(point)) {
|
|
|
|
startNode = point.mTextNode;
|
2001-05-10 15:55:49 +04:00
|
|
|
startOffset = point.mOffset;
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
startNode.forget(outStartNode);
|
2001-05-10 15:55:49 +04:00
|
|
|
*outStartOffset = startOffset;
|
2014-05-02 16:15:27 +04:00
|
|
|
endNode.forget(outEndNode);
|
2001-05-10 15:55:49 +04:00
|
|
|
*outEndOffset = endOffset;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
/**
|
|
|
|
* Given a dompoint, find the ws run that is before or after it, as caller
|
|
|
|
* needs
|
|
|
|
*/
|
2012-06-01 15:03:17 +04:00
|
|
|
void
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::FindRun(nsINode* aNode,
|
|
|
|
int32_t aOffset,
|
|
|
|
WSFragment** outRun,
|
|
|
|
bool after)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-05-12 16:12:42 +04:00
|
|
|
MOZ_ASSERT(aNode && outRun);
|
2014-05-02 16:15:27 +04:00
|
|
|
*outRun = nullptr;
|
|
|
|
|
|
|
|
for (WSFragment* run = mStartRun; run; run = run->mRight) {
|
|
|
|
int32_t comp = run->mStartNode ? nsContentUtils::ComparePoints(aNode,
|
|
|
|
aOffset, run->mStartNode, run->mStartOffset) : -1;
|
|
|
|
if (comp <= 0) {
|
|
|
|
if (after) {
|
2001-04-28 16:04:45 +04:00
|
|
|
*outRun = run;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
|
|
|
// before
|
2012-07-30 18:20:58 +04:00
|
|
|
*outRun = nullptr;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
comp = run->mEndNode ? nsContentUtils::ComparePoints(aNode, aOffset,
|
|
|
|
run->mEndNode, run->mEndOffset) : -1;
|
|
|
|
if (comp < 0) {
|
2001-04-28 16:04:45 +04:00
|
|
|
*outRun = run;
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2016-10-24 05:27:45 +03:00
|
|
|
} else if (!comp) {
|
2014-05-02 16:15:27 +04:00
|
|
|
if (after) {
|
2001-04-28 16:04:45 +04:00
|
|
|
*outRun = run->mRight;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
|
|
|
// before
|
2001-04-28 16:04:45 +04:00
|
|
|
*outRun = run;
|
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
if (!run->mRight) {
|
|
|
|
if (after) {
|
2012-07-30 18:20:58 +04:00
|
|
|
*outRun = nullptr;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
|
|
|
// before
|
2001-04-28 16:04:45 +04:00
|
|
|
*outRun = run;
|
|
|
|
}
|
2012-06-01 15:03:17 +04:00
|
|
|
return;
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-28 18:58:42 +03:00
|
|
|
char16_t
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::GetCharAt(Text* aTextNode,
|
|
|
|
int32_t aOffset)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
|
|
|
// return 0 if we can't get a char, for whatever reason
|
2010-06-18 00:40:48 +04:00
|
|
|
NS_ENSURE_TRUE(aTextNode, 0);
|
2006-07-19 08:36:36 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t len = int32_t(aTextNode->TextLength());
|
2016-10-24 05:27:45 +03:00
|
|
|
if (aOffset < 0 || aOffset >= len) {
|
2001-04-28 16:04:45 +04:00
|
|
|
return 0;
|
2016-10-24 05:27:45 +03:00
|
|
|
}
|
2006-07-19 08:36:36 +04:00
|
|
|
return aTextNode->GetText()->CharAt(aOffset);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::WSPoint
|
|
|
|
WSRunObject::GetWSPointAfter(nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
// Note: only to be called if aNode is not a ws node.
|
|
|
|
|
|
|
|
// Binary search on wsnodes
|
|
|
|
uint32_t numNodes = mNodeArray.Length();
|
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
if (!numNodes) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Do nothing if there are no nodes to search
|
2012-06-01 15:03:17 +04:00
|
|
|
WSPoint outPoint;
|
|
|
|
return outPoint;
|
|
|
|
}
|
2006-08-08 04:22:52 +04:00
|
|
|
|
2014-05-02 16:15:27 +04:00
|
|
|
uint32_t firstNum = 0, curNum = numNodes/2, lastNum = numNodes;
|
|
|
|
int16_t cmp = 0;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> curNode;
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Begin binary search. We do this because we need to minimize calls to
|
|
|
|
// ComparePoints(), which is expensive.
|
|
|
|
while (curNum != lastNum) {
|
|
|
|
curNode = mNodeArray[curNum];
|
2012-01-28 19:42:14 +04:00
|
|
|
cmp = nsContentUtils::ComparePoints(aNode, aOffset, curNode, 0);
|
2014-05-02 16:15:27 +04:00
|
|
|
if (cmp < 0) {
|
2006-08-08 04:22:52 +04:00
|
|
|
lastNum = curNum;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
2006-08-08 04:22:52 +04:00
|
|
|
firstNum = curNum + 1;
|
2014-05-02 16:15:27 +04:00
|
|
|
}
|
|
|
|
curNum = (lastNum - firstNum)/2 + firstNum;
|
|
|
|
MOZ_ASSERT(firstNum <= curNum && curNum <= lastNum, "Bad binary search");
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2006-08-08 04:22:52 +04:00
|
|
|
|
|
|
|
// When the binary search is complete, we always know that the current node
|
|
|
|
// is the same as the end node, which is always past our range. Therefore,
|
|
|
|
// we've found the node immediately after the point of interest.
|
2014-05-02 16:15:27 +04:00
|
|
|
if (curNum == mNodeArray.Length()) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// hey asked for past our range (it's after the last node). GetCharAfter
|
2006-08-08 04:22:52 +04:00
|
|
|
// will do the work for us when we pass it the last index of the last node.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> textNode(mNodeArray[curNum - 1]);
|
2004-05-08 00:55:17 +04:00
|
|
|
WSPoint point(textNode, textNode->TextLength(), 0);
|
2012-06-01 15:03:17 +04:00
|
|
|
return GetCharAfter(point);
|
2006-08-08 04:22:52 +04:00
|
|
|
} else {
|
2014-05-02 16:15:27 +04:00
|
|
|
// The char after the point is the first character of our range.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> textNode(mNodeArray[curNum]);
|
2006-08-08 04:22:52 +04:00
|
|
|
WSPoint point(textNode, 0, 0);
|
2012-06-01 15:03:17 +04:00
|
|
|
return GetCharAfter(point);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::WSPoint
|
|
|
|
WSRunObject::GetWSPointBefore(nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2001-04-28 16:04:45 +04:00
|
|
|
{
|
2014-05-02 16:15:27 +04:00
|
|
|
// Note: only to be called if aNode is not a ws node.
|
|
|
|
|
|
|
|
// Binary search on wsnodes
|
|
|
|
uint32_t numNodes = mNodeArray.Length();
|
|
|
|
|
2012-06-01 15:03:17 +04:00
|
|
|
if (!numNodes) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Do nothing if there are no nodes to search
|
2012-06-01 15:03:17 +04:00
|
|
|
WSPoint outPoint;
|
|
|
|
return outPoint;
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
uint32_t firstNum = 0, curNum = numNodes/2, lastNum = numNodes;
|
|
|
|
int16_t cmp = 0;
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> curNode;
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Begin binary search. We do this because we need to minimize calls to
|
|
|
|
// ComparePoints(), which is expensive.
|
|
|
|
while (curNum != lastNum) {
|
|
|
|
curNode = mNodeArray[curNum];
|
2012-01-28 19:42:14 +04:00
|
|
|
cmp = nsContentUtils::ComparePoints(aNode, aOffset, curNode, 0);
|
2014-05-02 16:15:27 +04:00
|
|
|
if (cmp < 0) {
|
2006-08-08 04:22:52 +04:00
|
|
|
lastNum = curNum;
|
2014-05-02 16:15:27 +04:00
|
|
|
} else {
|
2006-08-08 04:22:52 +04:00
|
|
|
firstNum = curNum + 1;
|
2014-05-02 16:15:27 +04:00
|
|
|
}
|
|
|
|
curNum = (lastNum - firstNum)/2 + firstNum;
|
|
|
|
MOZ_ASSERT(firstNum <= curNum && curNum <= lastNum, "Bad binary search");
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
2006-08-08 04:22:52 +04:00
|
|
|
|
|
|
|
// When the binary search is complete, we always know that the current node
|
|
|
|
// is the same as the end node, which is always past our range. Therefore,
|
|
|
|
// we've found the node immediately after the point of interest.
|
2014-05-02 16:15:27 +04:00
|
|
|
if (curNum == mNodeArray.Length()) {
|
2014-05-02 16:15:27 +04:00
|
|
|
// Get the point before the end of the last node, we can pass the length of
|
|
|
|
// the node into GetCharBefore, and it will return the last character.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> textNode(mNodeArray[curNum - 1]);
|
2004-05-08 00:55:17 +04:00
|
|
|
WSPoint point(textNode, textNode->TextLength(), 0);
|
2012-06-01 15:03:17 +04:00
|
|
|
return GetCharBefore(point);
|
2006-08-08 04:22:52 +04:00
|
|
|
} else {
|
2014-05-02 16:15:27 +04:00
|
|
|
// We can just ask the current node for the point immediately before it,
|
2006-08-08 04:22:52 +04:00
|
|
|
// it will handle moving to the previous node (if any) and returning the
|
|
|
|
// appropriate character
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> textNode(mNodeArray[curNum]);
|
2006-08-08 04:22:52 +04:00
|
|
|
WSPoint point(textNode, 0, 0);
|
2012-06-01 15:03:17 +04:00
|
|
|
return GetCharBefore(point);
|
2001-04-28 16:04:45 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-05-11 16:43:22 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::CheckTrailingNBSPOfRun(WSFragment *aRun)
|
2014-05-02 15:11:26 +04:00
|
|
|
{
|
|
|
|
// Try to change an nbsp to a space, if possible, just to prevent nbsp
|
|
|
|
// proliferation. Examine what is before and after the trailing nbsp, if
|
|
|
|
// any.
|
2010-06-17 23:41:16 +04:00
|
|
|
NS_ENSURE_TRUE(aRun, NS_ERROR_NULL_POINTER);
|
2011-09-29 10:19:26 +04:00
|
|
|
bool leftCheck = false;
|
|
|
|
bool spaceNBSP = false;
|
|
|
|
bool rightCheck = false;
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2001-05-11 16:43:22 +04:00
|
|
|
// confirm run is normalWS
|
2012-07-13 10:33:43 +04:00
|
|
|
if (aRun->mType != WSType::normalWS) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
|
2001-05-11 16:43:22 +04:00
|
|
|
// first check for trailing nbsp
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint thePoint = GetCharBefore(aRun->mEndNode, aRun->mEndOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (thePoint.mTextNode && thePoint.mChar == nbsp) {
|
2001-05-11 16:43:22 +04:00
|
|
|
// now check that what is to the left of it is compatible with replacing nbsp with space
|
2012-06-01 15:03:17 +04:00
|
|
|
WSPoint prevPoint = GetCharBefore(thePoint);
|
|
|
|
if (prevPoint.mTextNode) {
|
2014-05-02 15:11:26 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) {
|
|
|
|
leftCheck = true;
|
|
|
|
} else {
|
|
|
|
spaceNBSP = true;
|
|
|
|
}
|
|
|
|
} else if (aRun->mLeftType == WSType::text ||
|
|
|
|
aRun->mLeftType == WSType::special) {
|
2012-07-13 10:33:43 +04:00
|
|
|
leftCheck = true;
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
if (leftCheck || spaceNBSP) {
|
|
|
|
// now check that what is to the right of it is compatible with replacing
|
|
|
|
// nbsp with space
|
|
|
|
if (aRun->mRightType == WSType::text ||
|
|
|
|
aRun->mRightType == WSType::special ||
|
|
|
|
aRun->mRightType == WSType::br) {
|
2012-07-13 10:33:43 +04:00
|
|
|
rightCheck = true;
|
|
|
|
}
|
|
|
|
if ((aRun->mRightType & WSType::block) &&
|
2016-05-01 21:29:23 +03:00
|
|
|
IsBlockNode(GetWSBoundingParent())) {
|
2014-05-02 15:11:26 +04:00
|
|
|
// We are at a block boundary. Insert a <br>. Why? Well, first note
|
|
|
|
// that the br will have no visible effect since it is up against a
|
|
|
|
// block boundary. |foo<br><p>bar| renders like |foo<p>bar| and
|
|
|
|
// similarly |<p>foo<br></p>bar| renders like |<p>foo</p>bar|. What
|
|
|
|
// this <br> addition gets us is the ability to convert a trailing nbsp
|
|
|
|
// to a space. Consider: |<body>foo. '</body>|, where ' represents
|
|
|
|
// selection. User types space attempting to put 2 spaces after the
|
|
|
|
// end of their sentence. We used to do this as: |<body>foo.
|
|
|
|
//  </body>| This caused problems with soft wrapping: the nbsp
|
|
|
|
// would wrap to the next line, which looked attrocious. If you try to
|
|
|
|
// do: |<body>foo.  </body>| instead, the trailing space is
|
|
|
|
// invisible because it is against a block boundary. If you do:
|
|
|
|
// |<body>foo.  </body>| then you get an even uglier soft
|
|
|
|
// wrapping problem, where foo is on one line until you type the final
|
|
|
|
// space, and then "foo " jumps down to the next line. Ugh. The best
|
|
|
|
// way I can find out of this is to throw in a harmless <br> here,
|
|
|
|
// which allows us to do: |<body>foo.  <br></body>|, which doesn't
|
|
|
|
// cause foo to jump lines, doesn't cause spaces to show up at the
|
|
|
|
// beginning of soft wrapped lines, and lets the user see 2 spaces when
|
|
|
|
// they type 2 spaces.
|
|
|
|
|
|
|
|
nsCOMPtr<Element> brNode =
|
|
|
|
mHTMLEditor->CreateBR(aRun->mEndNode, aRun->mEndOffset);
|
|
|
|
NS_ENSURE_TRUE(brNode, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
// Refresh thePoint, prevPoint
|
2014-05-02 16:15:27 +04:00
|
|
|
thePoint = GetCharBefore(aRun->mEndNode, aRun->mEndOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
prevPoint = GetCharBefore(thePoint);
|
2011-10-17 18:59:28 +04:00
|
|
|
rightCheck = true;
|
2002-11-17 04:25:30 +03:00
|
|
|
}
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
2014-05-02 15:11:26 +04:00
|
|
|
if (leftCheck && rightCheck) {
|
|
|
|
// Now replace nbsp with space. First, insert a space
|
2016-06-23 12:01:23 +03:00
|
|
|
AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor);
|
2014-01-04 19:02:17 +04:00
|
|
|
nsAutoString spaceStr(char16_t(32));
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, *thePoint.mTextNode,
|
|
|
|
thePoint.mOffset, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
|
|
|
// Finally, delete that nbsp
|
2016-10-19 12:09:33 +03:00
|
|
|
rv = DeleteChars(thePoint.mTextNode, thePoint.mOffset + 1,
|
|
|
|
thePoint.mTextNode, thePoint.mOffset + 2);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 15:11:26 +04:00
|
|
|
} else if (!mPRE && spaceNBSP && rightCheck) {
|
|
|
|
// Don't mess with this preformatted for now. We have a run of ASCII
|
|
|
|
// whitespace (which will render as one space) followed by an nbsp (which
|
|
|
|
// is at the end of the whitespace run). Let's switch their order. This
|
|
|
|
// will ensure that if someone types two spaces after a sentence, and the
|
|
|
|
// editor softwraps at this point, the spaces won't be split across lines,
|
|
|
|
// which looks ugly and is bad for the moose.
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<Text> startNode, endNode;
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t startOffset, endOffset;
|
2014-05-02 15:11:26 +04:00
|
|
|
GetAsciiWSBounds(eBoth, prevPoint.mTextNode, prevPoint.mOffset + 1,
|
|
|
|
getter_AddRefs(startNode), &startOffset,
|
|
|
|
getter_AddRefs(endNode), &endOffset);
|
|
|
|
|
|
|
|
// Delete that nbsp
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = DeleteChars(thePoint.mTextNode, thePoint.mOffset,
|
|
|
|
thePoint.mTextNode, thePoint.mOffset + 1);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 15:11:26 +04:00
|
|
|
|
|
|
|
// Finally, insert that nbsp before the ASCII ws run
|
2016-06-23 12:01:23 +03:00
|
|
|
AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor);
|
2002-11-17 04:25:30 +03:00
|
|
|
nsAutoString nbspStr(nbsp);
|
2016-10-19 12:09:33 +03:00
|
|
|
rv = mHTMLEditor->InsertTextIntoTextNodeImpl(nbspStr, *startNode,
|
|
|
|
startOffset, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2002-11-17 04:25:30 +03:00
|
|
|
}
|
2001-05-11 16:43:22 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::CheckTrailingNBSP(WSFragment* aRun,
|
|
|
|
nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2014-05-02 16:15:27 +04:00
|
|
|
{
|
|
|
|
// 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 break or text, so we don't have to worry
|
|
|
|
// about what is after it. What is after it now will end up after the
|
|
|
|
// inserted object.
|
2010-06-17 23:41:16 +04:00
|
|
|
NS_ENSURE_TRUE(aRun && aNode, NS_ERROR_NULL_POINTER);
|
2011-09-29 10:19:26 +04:00
|
|
|
bool canConvert = false;
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint thePoint = GetCharBefore(aNode, aOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (thePoint.mTextNode && thePoint.mChar == nbsp) {
|
|
|
|
WSPoint prevPoint = GetCharBefore(thePoint);
|
|
|
|
if (prevPoint.mTextNode) {
|
2014-05-02 16:15:27 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(prevPoint.mChar)) {
|
|
|
|
canConvert = true;
|
|
|
|
}
|
|
|
|
} else if (aRun->mLeftType == WSType::text ||
|
|
|
|
aRun->mLeftType == WSType::special) {
|
2012-07-13 10:33:43 +04:00
|
|
|
canConvert = true;
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
if (canConvert) {
|
|
|
|
// First, insert a space
|
2016-06-23 12:01:23 +03:00
|
|
|
AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor);
|
2014-01-04 19:02:17 +04:00
|
|
|
nsAutoString spaceStr(char16_t(32));
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, *thePoint.mTextNode,
|
|
|
|
thePoint.mOffset, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Finally, delete that nbsp
|
2016-10-19 12:09:33 +03:00
|
|
|
rv = DeleteChars(thePoint.mTextNode, thePoint.mOffset + 1,
|
|
|
|
thePoint.mTextNode, thePoint.mOffset + 2);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-04-28 16:04:45 +04:00
|
|
|
|
2001-05-10 15:55:49 +04:00
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::CheckLeadingNBSP(WSFragment* aRun,
|
|
|
|
nsINode* aNode,
|
|
|
|
int32_t aOffset)
|
2014-05-02 16:15:27 +04:00
|
|
|
{
|
|
|
|
// 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.
|
2011-09-29 10:19:26 +04:00
|
|
|
bool canConvert = false;
|
2014-05-02 16:15:27 +04:00
|
|
|
WSPoint thePoint = GetCharAfter(aNode, aOffset);
|
2012-06-01 15:03:17 +04:00
|
|
|
if (thePoint.mChar == nbsp) {
|
|
|
|
WSPoint tmp = thePoint;
|
2014-05-02 16:15:27 +04:00
|
|
|
// we want to be after thePoint
|
|
|
|
tmp.mOffset++;
|
2012-06-01 15:03:17 +04:00
|
|
|
WSPoint nextPoint = GetCharAfter(tmp);
|
|
|
|
if (nextPoint.mTextNode) {
|
2014-05-02 16:15:27 +04:00
|
|
|
if (!nsCRT::IsAsciiSpace(nextPoint.mChar)) {
|
|
|
|
canConvert = true;
|
|
|
|
}
|
|
|
|
} else if (aRun->mRightType == WSType::text ||
|
|
|
|
aRun->mRightType == WSType::special ||
|
|
|
|
aRun->mRightType == WSType::br) {
|
2012-07-13 10:33:43 +04:00
|
|
|
canConvert = true;
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:15:27 +04:00
|
|
|
if (canConvert) {
|
|
|
|
// First, insert a space
|
2016-06-23 12:01:23 +03:00
|
|
|
AutoTransactionsConserveSelection dontSpazMySelection(mHTMLEditor);
|
2014-01-04 19:02:17 +04:00
|
|
|
nsAutoString spaceStr(char16_t(32));
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv =
|
|
|
|
mHTMLEditor->InsertTextIntoTextNodeImpl(spaceStr, *thePoint.mTextNode,
|
|
|
|
thePoint.mOffset, true);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2014-05-02 16:15:27 +04:00
|
|
|
|
|
|
|
// Finally, delete that nbsp
|
2016-10-19 12:09:33 +03:00
|
|
|
rv = DeleteChars(thePoint.mTextNode, thePoint.mOffset + 1,
|
|
|
|
thePoint.mTextNode, thePoint.mOffset + 2);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-05-10 15:55:49 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2001-12-09 12:24:33 +03:00
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::Scrub()
|
2001-12-09 12:24:33 +03:00
|
|
|
{
|
|
|
|
WSFragment *run = mStartRun;
|
2016-10-24 05:27:45 +03:00
|
|
|
while (run) {
|
2012-07-13 10:33:43 +04:00
|
|
|
if (run->mType & (WSType::leadingWS | WSType::trailingWS)) {
|
2016-10-19 12:09:33 +03:00
|
|
|
nsresult rv = DeleteChars(run->mStartNode, run->mStartOffset,
|
|
|
|
run->mEndNode, run->mEndOffset);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2001-12-09 12:24:33 +03:00
|
|
|
}
|
|
|
|
run = run->mRight;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2016-07-07 12:40:45 +03:00
|
|
|
|
|
|
|
bool
|
2016-07-07 13:00:51 +03:00
|
|
|
WSRunObject::IsBlockNode(nsINode* aNode)
|
2016-07-07 12:40:45 +03:00
|
|
|
{
|
|
|
|
return aNode && aNode->IsElement() &&
|
2016-07-09 05:42:33 +03:00
|
|
|
HTMLEditor::NodeIsBlockStatic(aNode->AsElement());
|
2016-07-07 12:40:45 +03:00
|
|
|
}
|
2016-07-07 13:00:51 +03:00
|
|
|
|
|
|
|
} // namespace mozilla
|