зеркало из https://github.com/mozilla/pjs.git
Back out bug 240933 and bug 590554 because of reftest failure on Win7 and also bug 593211
This commit is contained in:
Родитель
090ea7deb3
Коммит
05dd2c5a12
|
@ -50,7 +50,19 @@
|
|||
role: ROLE_ENTRY,
|
||||
children: [
|
||||
{
|
||||
role: ROLE_TEXT_LEAF // hello1\nhello2 text
|
||||
role: ROLE_TEXT_LEAF // hello1 text
|
||||
},
|
||||
{
|
||||
role: ROLE_WHITESPACE
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF, // hello2 text
|
||||
},
|
||||
{
|
||||
role: ROLE_WHITESPACE
|
||||
},
|
||||
{
|
||||
role: ROLE_TEXT_LEAF, // whitepsace text
|
||||
},
|
||||
{
|
||||
role: ROLE_WHITESPACE
|
||||
|
|
|
@ -385,7 +385,7 @@ nsGenericDOMDataNode::SetTextInternal(PRUint32 aOffset, PRUint32 aCount,
|
|||
delete [] to;
|
||||
}
|
||||
|
||||
UpdateBidiStatus(aBuffer, aLength);
|
||||
SetBidiStatus();
|
||||
|
||||
// Notify observers
|
||||
if (aNotify) {
|
||||
|
@ -1084,7 +1084,7 @@ nsGenericDOMDataNode::AppendTextTo(nsAString& aResult)
|
|||
mText.AppendTo(aResult);
|
||||
}
|
||||
|
||||
void nsGenericDOMDataNode::UpdateBidiStatus(const PRUnichar* aBuffer, PRUint32 aLength)
|
||||
void nsGenericDOMDataNode::SetBidiStatus()
|
||||
{
|
||||
nsIDocument *document = GetCurrentDoc();
|
||||
if (document && document->GetBidiEnabled()) {
|
||||
|
@ -1092,7 +1092,7 @@ void nsGenericDOMDataNode::UpdateBidiStatus(const PRUnichar* aBuffer, PRUint32 a
|
|||
return;
|
||||
}
|
||||
|
||||
mText.UpdateBidiFlag(aBuffer, aLength);
|
||||
mText.SetBidiFlag();
|
||||
|
||||
if (document && mText.IsBidi()) {
|
||||
document->SetBidiEnabled();
|
||||
|
|
|
@ -358,7 +358,7 @@ protected:
|
|||
nsTextFragment mText;
|
||||
|
||||
private:
|
||||
void UpdateBidiStatus(const PRUnichar* aBuffer, PRUint32 aLength);
|
||||
void SetBidiStatus();
|
||||
|
||||
already_AddRefed<nsIAtom> GetCurrentValueAtom();
|
||||
};
|
||||
|
|
|
@ -372,11 +372,11 @@ nsTextFragment::Append(const PRUnichar* aBuffer, PRUint32 aLength)
|
|||
// To save time we only do this when we really want to know, not during
|
||||
// every allocation
|
||||
void
|
||||
nsTextFragment::UpdateBidiFlag(const PRUnichar* aBuffer, PRUint32 aLength)
|
||||
nsTextFragment::SetBidiFlag()
|
||||
{
|
||||
if (mState.mIs2b && !mState.mIsBidi) {
|
||||
const PRUnichar* cp = aBuffer;
|
||||
const PRUnichar* end = cp + aLength;
|
||||
const PRUnichar* cp = m2b;
|
||||
const PRUnichar* end = cp + mState.mLength;
|
||||
while (cp < end) {
|
||||
PRUnichar ch1 = *cp++;
|
||||
PRUint32 utf32Char = ch1;
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
/**
|
||||
* Return PR_TRUE if this fragment contains Bidi text
|
||||
* For performance reasons this flag is not set automatically, but
|
||||
* requires an explicit call to UpdateBidiFlag()
|
||||
* requires an explicit call to SetBidiFlag()
|
||||
*/
|
||||
PRBool IsBidi() const
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ public:
|
|||
* Scan the contents of the fragment and turn on mState.mIsBidi if it
|
||||
* includes any Bidi characters.
|
||||
*/
|
||||
void UpdateBidiFlag(const PRUnichar* aBuffer, PRUint32 aLength);
|
||||
void SetBidiFlag();
|
||||
|
||||
struct FragmentBits {
|
||||
// PRUint32 to ensure that the values are unsigned, because we
|
||||
|
|
|
@ -90,7 +90,6 @@ FORCE_STATIC_LIB = 1
|
|||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
INCLUDES += \
|
||||
-I$(topsrcdir)/editor/libeditor/text \
|
||||
-I$(topsrcdir)/content/base/src \
|
||||
-I$(topsrcdir)/content/events/src \
|
||||
-I$(topsrcdir)/layout/style \
|
||||
|
|
|
@ -113,7 +113,6 @@
|
|||
|
||||
#include "nsITransferable.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsTextEditUtils.h"
|
||||
|
||||
#include "mozilla/FunctionTimer.h"
|
||||
|
||||
|
@ -904,27 +903,14 @@ nsEditor::EndPlaceHolderTransaction()
|
|||
if (selPrivate) {
|
||||
selPrivate->SetCanCacheFrameOffset(PR_TRUE);
|
||||
}
|
||||
|
||||
// time to turn off the batch
|
||||
EndUpdateViewBatch();
|
||||
// make sure selection is in view
|
||||
|
||||
{
|
||||
// Hide the caret here to avoid hiding it twice, once in EndUpdateViewBatch
|
||||
// and once in ScrollSelectionIntoView.
|
||||
nsRefPtr<nsCaret> caret;
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
GetPresShell(getter_AddRefs(presShell));
|
||||
|
||||
if (presShell)
|
||||
caret = presShell->GetCaret();
|
||||
|
||||
StCaretHider caretHider(caret);
|
||||
|
||||
// time to turn off the batch
|
||||
EndUpdateViewBatch();
|
||||
// make sure selection is in view
|
||||
|
||||
// After ScrollSelectionIntoView(), the pending notifications might be
|
||||
// flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
|
||||
ScrollSelectionIntoView(PR_FALSE);
|
||||
}
|
||||
// After ScrollSelectionIntoView(), the pending notifications might be
|
||||
// flushed and PresShell/PresContext/Frames may be dead. See bug 418470.
|
||||
ScrollSelectionIntoView(PR_FALSE);
|
||||
|
||||
// cached for frame offset are Not available now
|
||||
if (selPrivate) {
|
||||
|
@ -2287,75 +2273,11 @@ NS_IMETHODIMP nsEditor::InsertTextImpl(const nsAString& aStringToInsert,
|
|||
// class to turn off txn selection updating. Caller also turned on rules sniffing
|
||||
// if desired.
|
||||
|
||||
nsresult res;
|
||||
NS_ENSURE_TRUE(aInOutNode && *aInOutNode && aInOutOffset && aDoc, NS_ERROR_NULL_POINTER);
|
||||
if (!mInIMEMode && aStringToInsert.IsEmpty()) return NS_OK;
|
||||
nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(*aInOutNode);
|
||||
if (!nodeAsText && IsPlaintextEditor()) {
|
||||
// In some cases, aInOutNode is the anonymous DIV, and aInOutOffset is 0.
|
||||
// To avoid injecting unneeded text nodes, we first look to see if we have
|
||||
// one available. In that case, we'll just adjust aInOutNode and aInOutOffset
|
||||
// accordingly.
|
||||
if (*aInOutNode == GetRoot() && *aInOutOffset == 0) {
|
||||
nsCOMPtr<nsIDOMNode> possibleTextNode;
|
||||
res = (*aInOutNode)->GetFirstChild(getter_AddRefs(possibleTextNode));
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
nodeAsText = do_QueryInterface(possibleTextNode);
|
||||
if (nodeAsText) {
|
||||
*aInOutNode = possibleTextNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
// In some other cases, aInOutNode is the anonymous DIV, and aInOutOffset points
|
||||
// to the terminating mozBR. In that case, we'll adjust aInOutNode and aInOutOffset
|
||||
// to the preceding text node, if any.
|
||||
if (!nodeAsText && *aInOutNode == GetRoot() && *aInOutOffset > 0) {
|
||||
nsCOMPtr<nsIDOMNodeList> children;
|
||||
res = (*aInOutNode)->GetChildNodes(getter_AddRefs(children));
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
nsCOMPtr<nsIDOMNode> possibleMozBRNode;
|
||||
res = children->Item(*aInOutOffset, getter_AddRefs(possibleMozBRNode));
|
||||
if (NS_SUCCEEDED(res) && nsTextEditUtils::IsMozBR(possibleMozBRNode)) {
|
||||
nsCOMPtr<nsIDOMNode> possibleTextNode;
|
||||
res = children->Item(*aInOutOffset - 1, getter_AddRefs(possibleTextNode));
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
nodeAsText = do_QueryInterface(possibleTextNode);
|
||||
if (nodeAsText) {
|
||||
PRUint32 length;
|
||||
res = nodeAsText->GetLength(&length);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
*aInOutOffset = PRInt32(length);
|
||||
*aInOutNode = possibleTextNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sometimes, aInOutNode is the mozBR element itself. In that case, we'll
|
||||
// adjust the insertion point to the previous text node, if one exists, or
|
||||
// to the parent anonymous DIV.
|
||||
if (nsTextEditUtils::IsMozBR(*aInOutNode) && *aInOutOffset == 0) {
|
||||
nsCOMPtr<nsIDOMNode> previous;
|
||||
(*aInOutNode)->GetPreviousSibling(getter_AddRefs(previous));
|
||||
nodeAsText = do_QueryInterface(previous);
|
||||
if (nodeAsText) {
|
||||
PRUint32 length;
|
||||
res = nodeAsText->GetLength(&length);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
*aInOutOffset = PRInt32(length);
|
||||
*aInOutNode = previous;
|
||||
}
|
||||
} else {
|
||||
nsCOMPtr<nsIDOMNode> parent;
|
||||
(*aInOutNode)->GetParentNode(getter_AddRefs(parent));
|
||||
if (parent == GetRoot()) {
|
||||
*aInOutNode = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PRInt32 offset = *aInOutOffset;
|
||||
nsresult res;
|
||||
if (mInIMEMode)
|
||||
{
|
||||
if (!nodeAsText)
|
||||
|
@ -3624,9 +3546,8 @@ nsEditor::IsEditable(nsIDOMNode *aNode)
|
|||
// and uses enhanced logic to find out in the HTML world.
|
||||
return IsTextInDirtyFrameVisible(aNode);
|
||||
}
|
||||
if (resultFrame->HasAnyNoncollapsedCharacters()) {
|
||||
return PR_TRUE;
|
||||
}
|
||||
if (resultFrame->GetSize().width > 0)
|
||||
return PR_TRUE; // text node has width
|
||||
resultFrame = resultFrame->GetNextContinuation();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -623,19 +623,13 @@ nsPlaintextEditor::GetTextSelectionOffsets(nsISelection *aSelection,
|
|||
}
|
||||
}
|
||||
#ifdef NS_DEBUG
|
||||
// The post content iterator might return the parent node (which is the
|
||||
// editor's root node) as the last item. Don't count the root node itself
|
||||
// as one of its children!
|
||||
if (!SameCOMIdentity(currentNode, rootNode)) {
|
||||
++nodeCount;
|
||||
}
|
||||
++nodeCount;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (endOffset == -1) {
|
||||
NS_ASSERTION(endNode == rootNode, "failed to find the end node");
|
||||
NS_ASSERTION(IsPasswordEditor() ||
|
||||
(endNodeOffset == nodeCount-1 || endNodeOffset == 0),
|
||||
NS_ASSERTION(endNodeOffset == nodeCount-1 || endNodeOffset == 0,
|
||||
"invalid end node offset");
|
||||
endOffset = endNodeOffset == 0 ? 0 : totalLength;
|
||||
}
|
||||
|
@ -868,55 +862,57 @@ NS_IMETHODIMP nsPlaintextEditor::InsertLineBreak()
|
|||
shell->MaybeInvalidateCaretPosition();
|
||||
|
||||
nsTextRulesInfo ruleInfo(nsTextEditRules::kInsertBreak);
|
||||
ruleInfo.maxLength = mMaxTextLength;
|
||||
PRBool cancel, handled;
|
||||
res = mRules->WillDoAction(selection, &ruleInfo, &cancel, &handled);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (!cancel && !handled)
|
||||
{
|
||||
// get the (collapsed) selection location
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
PRInt32 selOffset;
|
||||
res = GetStartNodeAndOffset(selection, getter_AddRefs(selNode), &selOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// don't put text in places that can't have it
|
||||
if (!IsTextNode(selNode) && !CanContainTag(selNode, NS_LITERAL_STRING("#text")))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// we need to get the doc
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
res = GetDocument(getter_AddRefs(doc));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
NS_ENSURE_TRUE(doc, NS_ERROR_NULL_POINTER);
|
||||
|
||||
// don't spaz my selection in subtransactions
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(this);
|
||||
|
||||
// insert a linefeed character
|
||||
res = InsertTextImpl(NS_LITERAL_STRING("\n"), address_of(selNode),
|
||||
&selOffset, doc);
|
||||
if (!selNode) res = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
|
||||
// create the new BR node
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
res = DeleteSelectionAndCreateNode(NS_LITERAL_STRING("br"), getter_AddRefs(newNode));
|
||||
if (!newNode) res = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
// set the selection to the correct location
|
||||
res = selection->Collapse(selNode, selOffset);
|
||||
|
||||
// set the selection to the new node
|
||||
nsCOMPtr<nsIDOMNode>parent;
|
||||
res = newNode->GetParentNode(getter_AddRefs(parent));
|
||||
if (!parent) res = NS_ERROR_NULL_POINTER; // don't return here, so DidDoAction is called
|
||||
if (NS_SUCCEEDED(res))
|
||||
{
|
||||
// see if we're at the end of the editor range
|
||||
nsCOMPtr<nsIDOMNode> endNode;
|
||||
PRInt32 endOffset;
|
||||
res = GetEndNodeAndOffset(selection, getter_AddRefs(endNode), &endOffset);
|
||||
|
||||
if (NS_SUCCEEDED(res) && endNode == selNode && endOffset == selOffset)
|
||||
PRInt32 offsetInParent=-1; // we use the -1 as a marker to see if we need to compute this or not
|
||||
nsCOMPtr<nsIDOMNode>nextNode;
|
||||
newNode->GetNextSibling(getter_AddRefs(nextNode));
|
||||
if (nextNode)
|
||||
{
|
||||
// SetInterlinePosition(PR_TRUE) means we want the caret to stick to the content on the "right".
|
||||
// We want the caret to stick to whatever is past the break. This is
|
||||
// because the break is on the same line we were on, but the next content
|
||||
// will be on the following line.
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
||||
selPriv->SetInterlinePosition(PR_TRUE);
|
||||
nsCOMPtr<nsIDOMCharacterData>nextTextNode = do_QueryInterface(nextNode);
|
||||
if (!nextTextNode) {
|
||||
nextNode = do_QueryInterface(newNode); // is this QI needed?
|
||||
}
|
||||
else {
|
||||
offsetInParent=0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
nextNode = do_QueryInterface(newNode); // is this QI needed?
|
||||
}
|
||||
|
||||
if (-1==offsetInParent)
|
||||
{
|
||||
nextNode->GetParentNode(getter_AddRefs(parent));
|
||||
res = GetChildOffset(nextNode, parent, offsetInParent);
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
// SetInterlinePosition(PR_TRUE) means we want the caret to stick to the content on the "right".
|
||||
// We want the caret to stick to whatever is past the break. This is
|
||||
// because the break is on the same line we were on, but the next content
|
||||
// will be on the following line.
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
|
||||
selPriv->SetInterlinePosition(PR_TRUE);
|
||||
res = selection->Collapse(parent, offsetInParent+1); // +1 to insert just after the break
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res = selection->Collapse(nextNode, offsetInParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -267,9 +267,6 @@ nsTextEditRules::AfterEdit(PRInt32 action, nsIEditor::EDirection aDirection)
|
|||
// insure trailing br node
|
||||
res = CreateTrailingBRIfNeeded();
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// collapse the selection to the trailing BR if it's at the end of our text node
|
||||
CollapseSelectionToTrailingBRIfNeeded(selection);
|
||||
|
||||
/* After inserting text the cursor Bidi level must be set to the level of the inserted text.
|
||||
* This is difficult, because we cannot know what the level is until after the Bidi algorithm
|
||||
|
@ -312,7 +309,7 @@ nsTextEditRules::WillDoAction(nsISelection *aSelection,
|
|||
switch (info->action)
|
||||
{
|
||||
case kInsertBreak:
|
||||
return WillInsertBreak(aSelection, aCancel, aHandled, info->maxLength);
|
||||
return WillInsertBreak(aSelection, aCancel, aHandled);
|
||||
case kInsertText:
|
||||
case kInsertTextIME:
|
||||
return WillInsertText(info->action,
|
||||
|
@ -424,10 +421,7 @@ nsTextEditRules::DidInsert(nsISelection *aSelection, nsresult aResult)
|
|||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::WillInsertBreak(nsISelection *aSelection,
|
||||
PRBool *aCancel,
|
||||
PRBool *aHandled,
|
||||
PRInt32 aMaxLength)
|
||||
nsTextEditRules::WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled)
|
||||
{
|
||||
if (!aSelection || !aCancel || !aHandled) { return NS_ERROR_NULL_POINTER; }
|
||||
CANCEL_OPERATION_IF_READONLY_OR_DISABLED
|
||||
|
@ -437,24 +431,11 @@ nsTextEditRules::WillInsertBreak(nsISelection *aSelection,
|
|||
}
|
||||
else
|
||||
{
|
||||
// handle docs with a max length
|
||||
// NOTE, this function copies inString into outString for us.
|
||||
NS_NAMED_LITERAL_STRING(inString, "\n");
|
||||
nsAutoString outString;
|
||||
PRBool didTruncate;
|
||||
nsresult res = TruncateInsertionIfNeeded(aSelection, &inString, &outString,
|
||||
aMaxLength, &didTruncate);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (didTruncate) {
|
||||
*aCancel = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
*aCancel = PR_FALSE;
|
||||
|
||||
// if the selection isn't collapsed, delete it.
|
||||
PRBool bCollapsed;
|
||||
res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
nsresult res = aSelection->GetIsCollapsed(&bCollapsed);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
if (!bCollapsed)
|
||||
{
|
||||
|
@ -474,12 +455,6 @@ nsTextEditRules::WillInsertBreak(nsISelection *aSelection,
|
|||
|
||||
nsresult
|
||||
nsTextEditRules::DidInsertBreak(nsISelection *aSelection, nsresult aResult)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsTextEditRules::CollapseSelectionToTrailingBRIfNeeded(nsISelection* aSelection)
|
||||
{
|
||||
// we only need to execute the stuff below if we are a plaintext editor.
|
||||
// html editors have a different mechanism for putting in mozBR's
|
||||
|
@ -488,40 +463,40 @@ nsTextEditRules::CollapseSelectionToTrailingBRIfNeeded(nsISelection* aSelection)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// if we are at the end of the textarea, we need to set the
|
||||
// selection to stick to the mozBR at the end of the textarea.
|
||||
// if we are at the end of the document, we need to insert
|
||||
// a special mozBR following the normal br, and then set the
|
||||
// selection to stick to the mozBR.
|
||||
PRInt32 selOffset;
|
||||
nsCOMPtr<nsIDOMNode> selNode;
|
||||
nsresult res;
|
||||
res = mEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(selNode), &selOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(selNode);
|
||||
if (!nodeAsText) return NS_OK; // nothing to do if we're not at a text node
|
||||
|
||||
PRUint32 length;
|
||||
res = nodeAsText->GetLength(&length);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// nothing to do if we're not at the end of the text node
|
||||
if (selOffset != length) return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> parentNode;
|
||||
PRInt32 parentOffset;
|
||||
res = nsEditor::GetNodeLocation(selNode, address_of(parentNode),
|
||||
&parentOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// confirm we are at end of document
|
||||
if (selOffset == 0) return NS_OK; // can't be after a br if we are at offset 0
|
||||
nsIDOMElement *rootElem = mEditor->GetRoot();
|
||||
|
||||
nsCOMPtr<nsIDOMNode> root = do_QueryInterface(rootElem);
|
||||
NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
|
||||
if (parentNode != root) return NS_OK;
|
||||
if (selNode != root) return NS_OK; // must be inside text node or somewhere other than end of root
|
||||
|
||||
nsCOMPtr<nsIDOMNode> nextNode = mEditor->GetChildAt(parentNode,
|
||||
parentOffset + 1);
|
||||
if (nextNode && nsTextEditUtils::IsMozBR(nextNode))
|
||||
nsCOMPtr<nsIDOMNode> temp = mEditor->GetChildAt(selNode, selOffset);
|
||||
if (temp) return NS_OK; // can't be at end if there is a node after us.
|
||||
|
||||
nsCOMPtr<nsIDOMNode> nearNode = mEditor->GetChildAt(selNode, selOffset-1);
|
||||
if (nearNode && nsTextEditUtils::IsBreak(nearNode) && !nsTextEditUtils::IsMozBR(nearNode))
|
||||
{
|
||||
res = aSelection->Collapse(parentNode, parentOffset + 1);
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
|
||||
// need to insert special moz BR. Why? Because if we don't
|
||||
// the user will see no new line for the break. Also, things
|
||||
// like table cells won't grow in height.
|
||||
nsCOMPtr<nsIDOMNode> brNode;
|
||||
res = CreateMozBR(selNode, selOffset, address_of(brNode));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
res = nsEditor::GetNodeLocation(brNode, address_of(selNode), &selOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
selPrivate->SetInterlinePosition(PR_TRUE);
|
||||
res = aSelection->Collapse(selNode, selOffset);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
return res;
|
||||
|
@ -658,7 +633,7 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|||
|
||||
// handle docs with a max length
|
||||
// NOTE, this function copies inString into outString for us.
|
||||
nsresult res = TruncateInsertionIfNeeded(aSelection, inString, outString, aMaxLength, nsnull);
|
||||
nsresult res = TruncateInsertionIfNeeded(aSelection, inString, outString, aMaxLength);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
PRUint32 start = 0;
|
||||
|
@ -773,32 +748,143 @@ nsTextEditRules::WillInsertText(PRInt32 aAction,
|
|||
nsCOMPtr<nsIDOMNode> curNode = selNode;
|
||||
PRInt32 curOffset = selOffset;
|
||||
|
||||
// is our text going to be PREformatted?
|
||||
// We remember this so that we know how to handle tabs.
|
||||
PRBool isPRE;
|
||||
res = mEditor->IsPreformatted(selNode, &isPRE);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
|
||||
// don't spaz my selection in subtransactions
|
||||
nsAutoTxnsConserveSelection dontSpazMySelection(mEditor);
|
||||
nsString tString(*outString);
|
||||
const PRUnichar *unicodeBuf = tString.get();
|
||||
nsCOMPtr<nsIDOMNode> unused;
|
||||
PRInt32 pos = 0;
|
||||
|
||||
res = mEditor->InsertTextImpl(*outString, address_of(curNode),
|
||||
&curOffset, doc);
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
// for efficiency, break out the pre case separately. This is because
|
||||
// it's a lot cheaper to search the input string for only newlines than
|
||||
// it is to search for both tabs and newlines.
|
||||
if (isPRE)
|
||||
{
|
||||
while (unicodeBuf && (pos != -1) && ((PRUint32)pos < tString.Length()))
|
||||
{
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = tString.FindChar(nsCRT::LF, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
subStrLen = tString.Length() - oldPos;
|
||||
pos = tString.Length();
|
||||
}
|
||||
|
||||
nsDependentSubstring subStr(tString, oldPos, subStrLen);
|
||||
|
||||
// is it a return?
|
||||
if (subStr.EqualsLiteral(LFSTR))
|
||||
{
|
||||
if (IsSingleLineEditor())
|
||||
{
|
||||
NS_ASSERTION((mEditor->mNewlineHandling == nsIPlaintextEditor::eNewlinesPasteIntact),
|
||||
"Newline improperly getting into single-line edit field!");
|
||||
res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
|
||||
|
||||
// If the newline is the last character in the string, and the BR we
|
||||
// just inserted is the last node in the content tree, we need to add
|
||||
// a mozBR so that a blank line is created.
|
||||
|
||||
if (NS_SUCCEEDED(res) && curNode && pos == (PRInt32)(tString.Length() - 1))
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> nextChild = mEditor->GetChildAt(curNode, curOffset);
|
||||
|
||||
if (!nextChild)
|
||||
{
|
||||
// We must be at the end since there isn't a nextChild.
|
||||
//
|
||||
// curNode and curOffset should be set to the position after
|
||||
// the BR we added above, so just create a mozBR at that position.
|
||||
//
|
||||
// Note that we don't update curOffset after we've created/inserted
|
||||
// the mozBR since we never want the selection to be placed after it.
|
||||
|
||||
res = CreateMozBR(curNode, curOffset, address_of(unused));
|
||||
}
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char specialChars[] = {TAB, nsCRT::LF, 0};
|
||||
while (unicodeBuf && (pos != -1) && ((PRUint32)pos < tString.Length()))
|
||||
{
|
||||
PRInt32 oldPos = pos;
|
||||
PRInt32 subStrLen;
|
||||
pos = tString.FindCharInSet(specialChars, oldPos);
|
||||
|
||||
if (pos != -1)
|
||||
{
|
||||
subStrLen = pos - oldPos;
|
||||
// if first char is newline, then use just it
|
||||
if (subStrLen == 0)
|
||||
subStrLen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
subStrLen = tString.Length() - oldPos;
|
||||
pos = tString.Length();
|
||||
}
|
||||
|
||||
nsDependentSubstring subStr(tString, oldPos, subStrLen);
|
||||
|
||||
// is it a tab?
|
||||
if (subStr.EqualsLiteral("\t"))
|
||||
{
|
||||
res = mEditor->InsertTextImpl(NS_LITERAL_STRING(" "), address_of(curNode), &curOffset, doc);
|
||||
pos++;
|
||||
}
|
||||
// is it a return?
|
||||
else if (subStr.EqualsLiteral(LFSTR))
|
||||
{
|
||||
res = mEditor->CreateBRImpl(address_of(curNode), &curOffset, address_of(unused), nsIEditor::eNone);
|
||||
pos++;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = mEditor->InsertTextImpl(subStr, address_of(curNode), &curOffset, doc);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
}
|
||||
}
|
||||
outString->Assign(tString);
|
||||
|
||||
if (curNode)
|
||||
{
|
||||
aSelection->Collapse(curNode, curOffset);
|
||||
|
||||
// Make the caret attach to the inserted text, unless this text ends with a LF,
|
||||
// in which case make the caret attach to the next line.
|
||||
PRBool endsWithLF =
|
||||
!outString->IsEmpty() && outString->Last() == nsCRT::LF;
|
||||
PRBool endsWithLF = !tString.IsEmpty() && tString.get()[tString.Length() - 1] == nsCRT::LF;
|
||||
nsCOMPtr<nsISelectionPrivate>selPrivate(do_QueryInterface(aSelection));
|
||||
selPrivate->SetInterlinePosition(endsWithLF);
|
||||
|
||||
// If the last character is a linefeed character, make sure that we inject
|
||||
// a BR element for correct caret positioning.
|
||||
if (endsWithLF) {
|
||||
nsCOMPtr<nsIDOMNode> mozBR;
|
||||
res = CreateMozBR(curNode, curOffset, address_of(mozBR));
|
||||
NS_ENSURE_SUCCESS(res, res);
|
||||
curNode = mozBR;
|
||||
curOffset = 0;
|
||||
}
|
||||
aSelection->Collapse(curNode, curOffset);
|
||||
}
|
||||
}
|
||||
ASSERT_PASSWORD_LENGTHS_EQUAL()
|
||||
|
@ -1272,16 +1358,12 @@ nsresult
|
|||
nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection,
|
||||
const nsAString *aInString,
|
||||
nsAString *aOutString,
|
||||
PRInt32 aMaxLength,
|
||||
PRBool *aTruncated)
|
||||
PRInt32 aMaxLength)
|
||||
{
|
||||
if (!aSelection || !aInString || !aOutString) {return NS_ERROR_NULL_POINTER;}
|
||||
|
||||
nsresult res = NS_OK;
|
||||
*aOutString = *aInString;
|
||||
if (aTruncated) {
|
||||
*aTruncated = PR_FALSE;
|
||||
}
|
||||
|
||||
if ((-1 != aMaxLength) && IsPlaintextEditor() && !mEditor->IsIMEComposing() )
|
||||
{
|
||||
|
@ -1314,9 +1396,6 @@ nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection,
|
|||
if (resultingDocLength >= aMaxLength)
|
||||
{
|
||||
aOutString->Truncate();
|
||||
if (aTruncated) {
|
||||
*aTruncated = PR_TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1324,9 +1403,6 @@ nsTextEditRules::TruncateInsertionIfNeeded(nsISelection *aSelection,
|
|||
if (inCount + resultingDocLength > aMaxLength)
|
||||
{
|
||||
aOutString->Truncate(aMaxLength - resultingDocLength);
|
||||
if (aTruncated) {
|
||||
*aTruncated = PR_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -160,8 +160,7 @@ protected:
|
|||
nsresult DidInsertText(nsISelection *aSelection, nsresult aResult);
|
||||
nsresult GetTopEnclosingPre(nsIDOMNode *aNode, nsIDOMNode** aOutPreNode);
|
||||
|
||||
nsresult WillInsertBreak(nsISelection *aSelection, PRBool *aCancel,
|
||||
PRBool *aHandled, PRInt32 aMaxLength);
|
||||
nsresult WillInsertBreak(nsISelection *aSelection, PRBool *aCancel, PRBool *aHandled);
|
||||
nsresult DidInsertBreak(nsISelection *aSelection, nsresult aResult);
|
||||
|
||||
nsresult WillInsert(nsISelection *aSelection, PRBool *aCancel);
|
||||
|
@ -219,8 +218,7 @@ protected:
|
|||
nsresult TruncateInsertionIfNeeded(nsISelection *aSelection,
|
||||
const nsAString *aInString,
|
||||
nsAString *aOutString,
|
||||
PRInt32 aMaxLength,
|
||||
PRBool *aTruncated);
|
||||
PRInt32 aMaxLength);
|
||||
|
||||
/** Remove IME composition text from password buffer */
|
||||
nsresult RemoveIMETextFromPWBuf(PRUint32 &aStart, nsAString *aIMEString);
|
||||
|
@ -235,8 +233,6 @@ protected:
|
|||
|
||||
nsresult HideLastPWInput();
|
||||
|
||||
nsresult CollapseSelectionToTrailingBRIfNeeded(nsISelection *aSelection);
|
||||
|
||||
PRBool IsPasswordEditor() const
|
||||
{
|
||||
return mEditor ? mEditor->IsPasswordEditor() : PR_FALSE;
|
||||
|
|
|
@ -47,7 +47,6 @@ include $(topsrcdir)/config/rules.mk
|
|||
_TEST_FILES = \
|
||||
test_bug471722.html \
|
||||
test_bug569988.html \
|
||||
test_bug590554.html \
|
||||
$(NULL)
|
||||
|
||||
# disables the key handling test on gtk2 because gtk2 overrides some key events
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=590554
|
||||
-->
|
||||
|
||||
<head>
|
||||
<title>Test for Bug 590554</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 590554 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var t = document.querySelector("textarea");
|
||||
t.focus();
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
is(t.value, "\n", "Pressing enter should work the first time");
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
is(t.value, "\n", "Pressing enter should not work the second time");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<textarea maxlength="1"></textarea>
|
||||
</body>
|
||||
</html>
|
|
@ -287,23 +287,13 @@ function runTests()
|
|||
synthesizeKey("VK_TAB", { });
|
||||
check(aDescription + "Tab",
|
||||
true, true, !aIsTabbable && !aIsReadonly);
|
||||
is(aElement.value, !aIsTabbable && !aIsReadonly ? "a\t" : "a",
|
||||
// The tab char is converted to 4 space characters because textarea/input
|
||||
// elements are not preformatted editor.
|
||||
is(aElement.value, !aIsTabbable && !aIsReadonly ? "a " : "a",
|
||||
aDescription + "Tab");
|
||||
is(fm.focusedElement, aElement,
|
||||
aDescription + "focus moved unexpectedly (Tab)");
|
||||
|
||||
// If the editor is not tabbable, make sure that it accepts tab characters
|
||||
// even if it's empty.
|
||||
if (!aIsTabbable && !aIsReadonly) {
|
||||
reset("");
|
||||
synthesizeKey("VK_TAB", {});
|
||||
check(aDescription + "Tab on empty textarea",
|
||||
true, true, !aIsReadonly);
|
||||
is(aElement.value, "\t", aDescription + "Tab on empty textarea");
|
||||
is(fm.focusedElement, aElement,
|
||||
aDescription + "focus moved unexpectedly (Tab on empty textarea");
|
||||
}
|
||||
|
||||
reset("a");
|
||||
synthesizeKey("VK_TAB", { shiftKey: true });
|
||||
check(aDescription + "Shift+Tab", true, true, false);
|
||||
|
|
|
@ -92,9 +92,6 @@ _TEST_FILES = \
|
|||
bug106855-1.html \
|
||||
bug106855-2.html \
|
||||
bug106855-1-ref.html \
|
||||
bug240933-1.html \
|
||||
bug240933-2.html \
|
||||
bug240933-1-ref.html \
|
||||
bug482484.html \
|
||||
bug482484-ref.html \
|
||||
bug512295-1.html \
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
<!DOCTYPE HTML><html>
|
||||
<body>
|
||||
<textarea id="t" rows="4">
|
||||
|
||||
</textarea>
|
||||
<script>
|
||||
document.getElementById("t").focus();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,14 +0,0 @@
|
|||
<!DOCTYPE HTML><html><head>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<textarea id="t" rows="4"></textarea>
|
||||
<script>
|
||||
var area = document.getElementById('t');
|
||||
area.focus();
|
||||
|
||||
sendKey('VK_ENTER'); // press Enter once
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE HTML><html><head>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<textarea id="t" rows="4"></textarea>
|
||||
<script>
|
||||
var area = document.getElementById('t');
|
||||
area.focus();
|
||||
|
||||
sendKey('VK_ENTER'); // press Enter twice
|
||||
sendKey('VK_ENTER');
|
||||
sendKey('VK_BACK_SPACE'); // press Backspace once
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -88,8 +88,6 @@ function endTest() {
|
|||
var tests = [
|
||||
[ 'bug106855-1.html' , 'bug106855-1-ref.html' ] ,
|
||||
[ 'bug106855-2.html' , 'bug106855-1-ref.html' ] ,
|
||||
[ 'bug240933-1.html' , 'bug240933-1-ref.html' ] ,
|
||||
[ 'bug240933-2.html' , 'bug240933-1-ref.html' ] ,
|
||||
[ 'bug482484.html' , 'bug482484-ref.html' ] ,
|
||||
[ 'bug512295-1.html' , 'bug512295-1-ref.html' ] ,
|
||||
[ 'bug512295-2.html' , 'bug512295-2-ref.html' ] ,
|
||||
|
|
|
@ -998,27 +998,51 @@ nsTextControlFrame::DOMPointToOffset(nsIDOMNode* aNode,
|
|||
if (!length || aNodeOffset < 0)
|
||||
return NS_OK;
|
||||
|
||||
NS_ASSERTION(length <= 2, "We should have one text node and one mozBR at most");
|
||||
PRInt32 i, textOffset = 0;
|
||||
PRInt32 lastIndex = (PRInt32)length - 1;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> firstNode;
|
||||
rv = nodeList->Item(0, getter_AddRefs(firstNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(firstNode);
|
||||
for (i = 0; i < (PRInt32)length; i++) {
|
||||
if (rootNode == aNode && i == aNodeOffset) {
|
||||
*aResult = textOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(aNode);
|
||||
if (nodeAsText || (aNode == rootNode && aNodeOffset == 0)) {
|
||||
// Selection is somewhere inside the text node; the offset is aNodeOffset
|
||||
*aResult = aNodeOffset;
|
||||
} else {
|
||||
// Selection is on the mozBR node, so offset should be set to the length
|
||||
// of the text node.
|
||||
if (textNode) {
|
||||
rv = textNode->GetLength(&length);
|
||||
nsCOMPtr<nsIDOMNode> item;
|
||||
rv = nodeList->Item(i, getter_AddRefs(item));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
|
||||
|
||||
if (domText) {
|
||||
PRUint32 textLength = 0;
|
||||
|
||||
rv = domText->GetLength(&textLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aResult = PRInt32(length);
|
||||
|
||||
if (item == aNode) {
|
||||
NS_ASSERTION((aNodeOffset >= 0 && aNodeOffset <= (PRInt32)textLength),
|
||||
"Invalid aNodeOffset!");
|
||||
*aResult = textOffset + aNodeOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
textOffset += textLength;
|
||||
}
|
||||
else {
|
||||
// Must be a BR node. If it's not the last BR node
|
||||
// under the root, count it as a newline.
|
||||
|
||||
if (i != lastIndex)
|
||||
++textOffset;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ASSERTION((aNode == rootNode && aNodeOffset == (PRInt32)length),
|
||||
"Invalid node offset!");
|
||||
|
||||
*aResult = textOffset;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1050,25 +1074,71 @@ nsTextControlFrame::OffsetToDOMPoint(PRInt32 aOffset,
|
|||
rv = nodeList->GetLength(&length);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ASSERTION(length <= 2, "We should have one text node and one mozBR at most");
|
||||
|
||||
nsCOMPtr<nsIDOMNode> firstNode;
|
||||
rv = nodeList->Item(0, getter_AddRefs(firstNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(firstNode);
|
||||
|
||||
if (length == 0 || aOffset < 0) {
|
||||
NS_IF_ADDREF(*aResult = rootNode);
|
||||
*aPosition = 0;
|
||||
} else if (textNode) {
|
||||
NS_IF_ADDREF(*aResult = firstNode);
|
||||
*aPosition = aOffset;
|
||||
} else {
|
||||
NS_IF_ADDREF(*aResult = rootNode);
|
||||
if (!length || aOffset < 0) {
|
||||
*aPosition = 0;
|
||||
*aResult = rootNode;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
PRInt32 textOffset = 0;
|
||||
PRUint32 lastIndex = length - 1;
|
||||
|
||||
for (PRUint32 i=0; i<length; i++) {
|
||||
nsCOMPtr<nsIDOMNode> item;
|
||||
rv = nodeList->Item(i, getter_AddRefs(item));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(item, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIDOMText> domText(do_QueryInterface(item));
|
||||
|
||||
if (domText) {
|
||||
PRUint32 textLength = 0;
|
||||
|
||||
rv = domText->GetLength(&textLength);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Check if aOffset falls within this range.
|
||||
if (aOffset >= textOffset && aOffset <= textOffset+(PRInt32)textLength) {
|
||||
*aPosition = aOffset - textOffset;
|
||||
*aResult = item;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
textOffset += textLength;
|
||||
|
||||
// If there aren't any more siblings after this text node,
|
||||
// return the point at the end of this text node!
|
||||
|
||||
if (i == lastIndex) {
|
||||
*aPosition = textLength;
|
||||
*aResult = item;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Must be a BR node, count it as a newline.
|
||||
|
||||
if (aOffset == textOffset || i == lastIndex) {
|
||||
// We've found the correct position, or aOffset takes us
|
||||
// beyond the last child under rootNode, just return the point
|
||||
// under rootNode that is in front of this br.
|
||||
|
||||
*aPosition = i;
|
||||
*aResult = rootNode;
|
||||
NS_ADDREF(*aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
++textOffset;
|
||||
}
|
||||
}
|
||||
|
||||
NS_ERROR("We should never get here!");
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -5219,7 +5219,6 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
|
|||
{
|
||||
PRBool eatingNonRenderableWS = PR_FALSE;
|
||||
PRBool done = PR_FALSE;
|
||||
PRBool jumpedLine = PR_FALSE;
|
||||
|
||||
while (!done) {
|
||||
PRBool movingInFrameDirection =
|
||||
|
@ -5231,6 +5230,7 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
|
|||
done = current->PeekOffsetCharacter(movingInFrameDirection, &offset);
|
||||
|
||||
if (!done) {
|
||||
PRBool jumpedLine;
|
||||
result =
|
||||
current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
|
||||
aPos->mJumpLines, aPos->mScrollViewStop,
|
||||
|
@ -5251,15 +5251,6 @@ nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
|
|||
aPos->mResultContent = range.content;
|
||||
// Output offset is relative to content, not frame
|
||||
aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
|
||||
// If we're dealing with a text frame and moving backward positions us at
|
||||
// the end of that line, decrease the offset by one to make sure that
|
||||
// we're placed before the linefeed character on the previous line.
|
||||
if (offset < 0 && jumpedLine &&
|
||||
aPos->mDirection == eDirPrevious &&
|
||||
current->GetStyleText()->NewlineIsSignificant() &&
|
||||
current->HasTerminalNewline()) {
|
||||
--aPos->mContentOffset;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1635,14 +1635,6 @@ public:
|
|||
PRUint32 aSkippedMaxLength = PR_UINT32_MAX)
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
* Returns true if the frame contains any non-collapsed characters.
|
||||
* This method is only available for text frames, and it will return false
|
||||
* for all other frame types.
|
||||
*/
|
||||
virtual PRBool HasAnyNoncollapsedCharacters()
|
||||
{ return PR_FALSE; }
|
||||
|
||||
/**
|
||||
* Accessor functions to get/set the associated view object
|
||||
*
|
||||
|
|
|
@ -460,8 +460,6 @@ protected:
|
|||
PRBool aForInsertionPoint);
|
||||
|
||||
void ClearFrameOffsetCache();
|
||||
|
||||
virtual PRBool HasAnyNoncollapsedCharacters();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5062,13 +5062,6 @@ nsTextFrame::GetCharacterOffsetAtFramePointInternal(const nsPoint &aPoint,
|
|||
// intrinsic widths.
|
||||
selectedOffset =
|
||||
provider.GetStart().GetOriginalOffset() + provider.GetOriginalLength();
|
||||
// If we're at the end of a preformatted line which has a terminating
|
||||
// linefeed, we want to reduce the offset by one to make sure that the
|
||||
// selection is placed before the linefeed character.
|
||||
if (GetStyleText()->NewlineIsSignificant() &&
|
||||
HasTerminalNewline()) {
|
||||
--selectedOffset;
|
||||
}
|
||||
}
|
||||
|
||||
offsets.content = GetContent();
|
||||
|
@ -5432,7 +5425,8 @@ IsAcceptableCaretPosition(const gfxSkipCharsIterator& aIter, gfxTextRun* aTextRu
|
|||
PRUint32 index = aIter.GetSkippedOffset();
|
||||
if (!aTextRun->IsClusterStart(index))
|
||||
return PR_FALSE;
|
||||
return PR_TRUE;
|
||||
return !(aFrame->GetStyleText()->NewlineIsSignificant() &&
|
||||
aTextRun->GetChar(index) == '\n');
|
||||
}
|
||||
|
||||
PRBool
|
||||
|
@ -5457,8 +5451,8 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||
PRInt32 startOffset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset);
|
||||
|
||||
if (!aForward) {
|
||||
// If at the beginning of the line, look at the previous continuation
|
||||
for (PRInt32 i = NS_MIN(trimmed.GetEnd(), startOffset) - 1;
|
||||
PRInt32 i;
|
||||
for (i = NS_MIN(trimmed.GetEnd(), startOffset) - 1;
|
||||
i >= trimmed.mStart; --i) {
|
||||
iter.SetOriginalOffset(i);
|
||||
if (IsAcceptableCaretPosition(iter, mTextRun, this)) {
|
||||
|
@ -5468,19 +5462,16 @@ nsTextFrame::PeekOffsetCharacter(PRBool aForward, PRInt32* aOffset)
|
|||
}
|
||||
*aOffset = 0;
|
||||
} else {
|
||||
// If we're at the end of a line, look at the next continuation
|
||||
iter.SetOriginalOffset(startOffset);
|
||||
if (iter.GetSkippedOffset() <= PRUint32(trimmed.GetEnd()) &&
|
||||
!(iter.GetSkippedOffset() < PRUint32(trimmed.GetEnd()) &&
|
||||
GetStyleText()->NewlineIsSignificant() &&
|
||||
mTextRun->GetChar(iter.GetSkippedOffset()) == '\n')) {
|
||||
for (PRInt32 i = startOffset + 1; i <= trimmed.GetEnd(); ++i) {
|
||||
iter.SetOriginalOffset(i);
|
||||
if (i == trimmed.GetEnd() ||
|
||||
IsAcceptableCaretPosition(iter, mTextRun, this)) {
|
||||
*aOffset = i - mContentOffset;
|
||||
return PR_TRUE;
|
||||
}
|
||||
PRInt32 i;
|
||||
for (i = startOffset + 1; i <= trimmed.GetEnd(); ++i) {
|
||||
iter.SetOriginalOffset(i);
|
||||
// XXX we can't necessarily stop at the end of this frame,
|
||||
// but we really have no choice right now. We need to do a deeper
|
||||
// fix/restructuring of PeekOffsetCharacter
|
||||
if (i == trimmed.GetEnd() ||
|
||||
IsAcceptableCaretPosition(iter, mTextRun, this)) {
|
||||
*aOffset = i - mContentOffset;
|
||||
return PR_TRUE;
|
||||
}
|
||||
}
|
||||
*aOffset = contentLength;
|
||||
|
@ -7131,14 +7122,3 @@ nsTextFrame::IsAtEndOfLine() const
|
|||
{
|
||||
return (GetStateBits() & TEXT_END_OF_LINE) != 0;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsTextFrame::HasAnyNoncollapsedCharacters()
|
||||
{
|
||||
gfxSkipCharsIterator iter = EnsureTextRun();
|
||||
PRInt32 offset = GetContentOffset(),
|
||||
offsetEnd = GetContentEnd();
|
||||
PRInt32 skippedOffset = iter.ConvertOriginalToSkipped(offset);
|
||||
PRInt32 skippedOffsetEnd = iter.ConvertOriginalToSkipped(offsetEnd);
|
||||
return skippedOffset != skippedOffsetEnd;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ _TEST_FILES = \
|
|||
plugin_clipping_lib.js \
|
||||
plugin_focus_helper.html \
|
||||
test_backspace_delete.xul \
|
||||
test_bug240933.html \
|
||||
test_bug263683.html \
|
||||
test_bug288789.html \
|
||||
test_bug290397.html \
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=240933
|
||||
-->
|
||||
|
||||
<head>
|
||||
<title>Test for Bug 240933</title>
|
||||
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=240933">
|
||||
Mozilla Bug 240933
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 240933 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SimpleTest.waitForFocus(function() {
|
||||
var t = document.getElementById("t");
|
||||
synthesizeMouse(t, t.clientWidth / 2, 5, {}, window);
|
||||
is(t.selectionStart, 3, "The selection should be set before the newline");
|
||||
is(t.selectionEnd, 3, "The selection should be set before the newline");
|
||||
|
||||
t = document.getElementById("ta");
|
||||
t.focus();
|
||||
var val = t.value;
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
is(t.value, val + "\n", "Pressing enter right after focusing the textarea should work");
|
||||
|
||||
t = document.getElementById("tb");
|
||||
t.focus();
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
is(t.value, "\n", "Pressing enter for the first time should work");
|
||||
synthesizeKey("VK_ENTER", {});
|
||||
is(t.value, "\n\n", "Pressing enter for the second time should work");
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
is(t.value, "\n", "Pressing backspace for the first time should work");
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
is(t.value, "", "Pressing backspace for the second time should work");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
|
||||
<textarea id="t" rows="10" cols="10">abc
|
||||
</textarea>
|
||||
<textarea id="ta" rows="10" cols="10">
|
||||
test
|
||||
|
||||
</textarea>
|
||||
<textarea id="tb" rows="10" cols="10"></textarea>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -18,11 +18,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=288789
|
|||
|
||||
אaב
|
||||
|
||||
</textarea>
|
||||
<textarea id="tb">
|
||||
|
||||
abc
|
||||
|
||||
</textarea>
|
||||
</div>
|
||||
<pre id="test">
|
||||
|
@ -55,59 +50,9 @@ function test() {
|
|||
|
||||
textarea.focus();
|
||||
collapse(0);
|
||||
ok(true, "Testing forward movement in RTL mode");
|
||||
for (var i = 0; i < textarea.textContent.length; ++i) {
|
||||
if (i == 0) {
|
||||
testRight(i);
|
||||
}
|
||||
if (textarea.textContent[i] == 'a') {
|
||||
testLeft(i);
|
||||
} else {
|
||||
testLeft(i + 1);
|
||||
}
|
||||
if (i == textarea.textContent.length - 1) {
|
||||
testLeft(i + 1);
|
||||
}
|
||||
}
|
||||
ok(true, "Testing backward movement in RTL mode");
|
||||
for (var i = textarea.textContent.length; i > 0; --i) {
|
||||
if (i == textarea.textContent.length) {
|
||||
testLeft(i);
|
||||
}
|
||||
if (i > 0 && textarea.textContent[i - 1] == 'a') {
|
||||
testRight(i);
|
||||
} else {
|
||||
testRight(i - 1);
|
||||
}
|
||||
if (i == 1) {
|
||||
testRight(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
textarea = $("tb");
|
||||
textarea.focus();
|
||||
collapse(0);
|
||||
ok(true, "Testing forward movement in LTR mode");
|
||||
for (var i = 0; i < textarea.textContent.length; ++i) {
|
||||
if (i == 0) {
|
||||
testLeft(i);
|
||||
}
|
||||
testRight(i + 1);
|
||||
if (i == textarea.textContent.length - 1) {
|
||||
testRight(i + 1);
|
||||
}
|
||||
}
|
||||
ok(true, "Testing backward movement in LTR mode");
|
||||
for (var i = textarea.textContent.length; i > 0; --i) {
|
||||
if (i == textarea.textContent.length) {
|
||||
testRight(i);
|
||||
}
|
||||
testLeft(i - 1);
|
||||
if (i == 1) {
|
||||
testLeft(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
testLeft(1);
|
||||
collapse(5);
|
||||
testRight(4);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -68,13 +68,13 @@ function test() {
|
|||
editor.innerHTML = "<pre>aa\nbb</pre>";
|
||||
sel.collapse(editor.firstChild.firstChild, 0);
|
||||
testRight(editor.firstChild.firstChild, 1);
|
||||
// at the end of the first line, before the \n
|
||||
testRight(editor.firstChild.firstChild, 2);
|
||||
// at the 'bb' but HINTLEFT so appears at the end of the first line
|
||||
testRight(editor.firstChild.firstChild, 3);
|
||||
testRight(editor.firstChild.firstChild, 3);
|
||||
testRight(editor.firstChild.firstChild, 4);
|
||||
testLeft(editor.firstChild.firstChild, 3);
|
||||
// at the end of the first line, before the \n
|
||||
testLeft(editor.firstChild.firstChild, 2);
|
||||
// at the 'bb' but HINTLEFT so appears at the end of the first line
|
||||
testLeft(editor.firstChild.firstChild, 3);
|
||||
testLeft(editor.firstChild.firstChild, 1);
|
||||
testLeft(editor.firstChild.firstChild, 0);
|
||||
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body onload="setup()">
|
||||
<textarea id="ta" dir="rtl">
|
||||
|
||||
אaב
|
||||
|
||||
</textarea>
|
||||
<textarea id="tb">
|
||||
|
||||
abc
|
||||
|
||||
</textarea>
|
||||
|
||||
<div id="coords1"></div>
|
||||
<div id="coords2"></div>
|
||||
|
||||
<script>
|
||||
function setup() {
|
||||
document.getElementById("coords1").innerHTML = document.getElementById("ta").selectionStart;
|
||||
document.getElementById("coords2").innerHTML = document.getElementById("tb").selectionStart;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<textarea id="ta" dir="rtl">
|
||||
|
||||
אaב
|
||||
|
||||
</textarea>
|
||||
<textarea id="tb">
|
||||
|
||||
abc
|
||||
|
||||
</textarea>
|
||||
|
||||
<div id="coords1">6</div>
|
||||
<div id="coords2">6</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,29 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body onload="setup()">
|
||||
<textarea id="ta" dir="rtl">
|
||||
|
||||
אaב
|
||||
|
||||
</textarea>
|
||||
<textarea id="tb">
|
||||
|
||||
abc
|
||||
|
||||
</textarea>
|
||||
|
||||
<div id="coords1"></div>
|
||||
<div id="coords2"></div>
|
||||
|
||||
<script>
|
||||
function setup() {
|
||||
document.getElementById("ta").selectionStart = 3;
|
||||
document.getElementById("ta").selectionEnd = 3;
|
||||
document.getElementById("coords1").innerHTML = document.getElementById("ta").selectionStart;
|
||||
document.getElementById("tb").selectionStart = 3;
|
||||
document.getElementById("tb").selectionEnd = 3;
|
||||
document.getElementById("coords2").innerHTML = document.getElementById("tb").selectionStart;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,19 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<textarea id="ta" dir="rtl">
|
||||
|
||||
אaב
|
||||
|
||||
</textarea>
|
||||
<textarea id="tb">
|
||||
|
||||
abc
|
||||
|
||||
</textarea>
|
||||
|
||||
<div id="coords1">3</div>
|
||||
<div id="coords2">3</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -205,8 +205,6 @@ random == 99850-1b.html 99850-1-ref.html # bug 471629
|
|||
== 236539-1.html 236539-1-ref.html
|
||||
== 240029-1.html 240029-1-ref.html
|
||||
== 240470-1.html 240470-1-ref.html
|
||||
== 240933-1.html 240933-1-ref.html
|
||||
== 240933-2.html 240933-2-ref.html
|
||||
== 243266-1.html 243266-1-ref.html
|
||||
== 243302-1.html 243302-1-ref.html
|
||||
== 243519-1.html 243519-1-ref.html
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body onload="document.querySelector('textarea').focus();">
|
||||
<textarea>foo</textarea>
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body onload="document.querySelector('textarea').focus();">
|
||||
<textarea>foo
|
||||
</textarea>
|
||||
</body>
|
||||
</html>
|
|
@ -18,4 +18,3 @@ include xul/reftest.list
|
|||
== emptypasswd-2.html emptypasswd-ref.html
|
||||
== caret_on_positioned.html caret_on_positioned-ref.html
|
||||
== spellcheck-1.html spellcheck-ref.html
|
||||
!= caret_on_textarea_lastline.html caret_on_textarea_lastline-ref.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче