1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/editor/txtsvc/src/nsTextServicesDocument.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3851 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <stddef.h> // for nullptr 1.10 + 1.11 +#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc 1.12 +#include "mozilla/mozalloc.h" // for operator new, etc 1.13 +#include "nsAString.h" // for nsAString_internal::Length, etc 1.14 +#include "nsAutoPtr.h" // for nsRefPtr 1.15 +#include "nsContentUtils.h" // for nsContentUtils 1.16 +#include "nsDebug.h" // for NS_ENSURE_TRUE, etc 1.17 +#include "nsDependentSubstring.h" // for Substring 1.18 +#include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc 1.19 +#include "nsFilteredContentIterator.h" // for nsFilteredContentIterator 1.20 +#include "nsIContent.h" // for nsIContent, etc 1.21 +#include "nsIContentIterator.h" // for nsIContentIterator 1.22 +#include "nsID.h" // for NS_GET_IID 1.23 +#include "nsIDOMDocument.h" // for nsIDOMDocument 1.24 +#include "nsIDOMElement.h" // for nsIDOMElement 1.25 +#include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument 1.26 +#include "nsIDOMHTMLElement.h" // for nsIDOMHTMLElement 1.27 +#include "nsIDOMNode.h" // for nsIDOMNode, etc 1.28 +#include "nsIDOMRange.h" // for nsIDOMRange, etc 1.29 +#include "nsIEditor.h" // for nsIEditor, etc 1.30 +#include "nsINode.h" // for nsINode 1.31 +#include "nsIPlaintextEditor.h" // for nsIPlaintextEditor 1.32 +#include "nsISelection.h" // for nsISelection 1.33 +#include "nsISelectionController.h" // for nsISelectionController, etc 1.34 +#include "nsISupportsBase.h" // for nsISupports 1.35 +#include "nsISupportsUtils.h" // for NS_IF_ADDREF, NS_ADDREF, etc 1.36 +#include "nsITextServicesFilter.h" // for nsITextServicesFilter 1.37 +#include "nsIWordBreaker.h" // for nsWordRange, nsIWordBreaker 1.38 +#include "nsRange.h" // for nsRange 1.39 +#include "nsStaticAtom.h" // for NS_STATIC_ATOM, etc 1.40 +#include "nsString.h" // for nsString, nsAutoString 1.41 +#include "nsTextServicesDocument.h" 1.42 +#include "nscore.h" // for nsresult, NS_IMETHODIMP, etc 1.43 + 1.44 +#define LOCK_DOC(doc) 1.45 +#define UNLOCK_DOC(doc) 1.46 + 1.47 +using namespace mozilla; 1.48 + 1.49 +class OffsetEntry 1.50 +{ 1.51 +public: 1.52 + OffsetEntry(nsIDOMNode *aNode, int32_t aOffset, int32_t aLength) 1.53 + : mNode(aNode), mNodeOffset(0), mStrOffset(aOffset), mLength(aLength), 1.54 + mIsInsertedText(false), mIsValid(true) 1.55 + { 1.56 + if (mStrOffset < 1) 1.57 + mStrOffset = 0; 1.58 + 1.59 + if (mLength < 1) 1.60 + mLength = 0; 1.61 + } 1.62 + 1.63 + virtual ~OffsetEntry() 1.64 + { 1.65 + mNode = 0; 1.66 + mNodeOffset = 0; 1.67 + mStrOffset = 0; 1.68 + mLength = 0; 1.69 + mIsValid = false; 1.70 + } 1.71 + 1.72 + nsIDOMNode *mNode; 1.73 + int32_t mNodeOffset; 1.74 + int32_t mStrOffset; 1.75 + int32_t mLength; 1.76 + bool mIsInsertedText; 1.77 + bool mIsValid; 1.78 +}; 1.79 + 1.80 +#define TS_ATOM(name_, value_) nsIAtom* nsTextServicesDocument::name_ = 0; 1.81 +#include "nsTSAtomList.h" // IWYU pragma: keep 1.82 +#undef TS_ATOM 1.83 + 1.84 +nsTextServicesDocument::nsTextServicesDocument() 1.85 +{ 1.86 + mRefCnt = 0; 1.87 + 1.88 + mSelStartIndex = -1; 1.89 + mSelStartOffset = -1; 1.90 + mSelEndIndex = -1; 1.91 + mSelEndOffset = -1; 1.92 + 1.93 + mIteratorStatus = eIsDone; 1.94 +} 1.95 + 1.96 +nsTextServicesDocument::~nsTextServicesDocument() 1.97 +{ 1.98 + ClearOffsetTable(&mOffsetTable); 1.99 +} 1.100 + 1.101 +#define TS_ATOM(name_, value_) NS_STATIC_ATOM_BUFFER(name_##_buffer, value_) 1.102 +#include "nsTSAtomList.h" // IWYU pragma: keep 1.103 +#undef TS_ATOM 1.104 + 1.105 +/* static */ 1.106 +void 1.107 +nsTextServicesDocument::RegisterAtoms() 1.108 +{ 1.109 + static const nsStaticAtom ts_atoms[] = { 1.110 +#define TS_ATOM(name_, value_) NS_STATIC_ATOM(name_##_buffer, &name_), 1.111 +#include "nsTSAtomList.h" // IWYU pragma: keep 1.112 +#undef TS_ATOM 1.113 + }; 1.114 + 1.115 + NS_RegisterStaticAtoms(ts_atoms); 1.116 +} 1.117 + 1.118 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsTextServicesDocument) 1.119 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsTextServicesDocument) 1.120 + 1.121 +NS_INTERFACE_MAP_BEGIN(nsTextServicesDocument) 1.122 + NS_INTERFACE_MAP_ENTRY(nsITextServicesDocument) 1.123 + NS_INTERFACE_MAP_ENTRY(nsIEditActionListener) 1.124 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITextServicesDocument) 1.125 + NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsTextServicesDocument) 1.126 +NS_INTERFACE_MAP_END 1.127 + 1.128 +NS_IMPL_CYCLE_COLLECTION(nsTextServicesDocument, 1.129 + mDOMDocument, 1.130 + mSelCon, 1.131 + mIterator, 1.132 + mPrevTextBlock, 1.133 + mNextTextBlock, 1.134 + mExtent, 1.135 + mTxtSvcFilter) 1.136 + 1.137 +NS_IMETHODIMP 1.138 +nsTextServicesDocument::InitWithEditor(nsIEditor *aEditor) 1.139 +{ 1.140 + nsresult result = NS_OK; 1.141 + nsCOMPtr<nsISelectionController> selCon; 1.142 + nsCOMPtr<nsIDOMDocument> doc; 1.143 + 1.144 + NS_ENSURE_TRUE(aEditor, NS_ERROR_NULL_POINTER); 1.145 + 1.146 + LOCK_DOC(this); 1.147 + 1.148 + // Check to see if we already have an mSelCon. If we do, it 1.149 + // better be the same one the editor uses! 1.150 + 1.151 + result = aEditor->GetSelectionController(getter_AddRefs(selCon)); 1.152 + 1.153 + if (NS_FAILED(result)) 1.154 + { 1.155 + UNLOCK_DOC(this); 1.156 + return result; 1.157 + } 1.158 + 1.159 + if (!selCon || (mSelCon && selCon != mSelCon)) 1.160 + { 1.161 + UNLOCK_DOC(this); 1.162 + return NS_ERROR_FAILURE; 1.163 + } 1.164 + 1.165 + if (!mSelCon) 1.166 + mSelCon = selCon; 1.167 + 1.168 + // Check to see if we already have an mDOMDocument. If we do, it 1.169 + // better be the same one the editor uses! 1.170 + 1.171 + result = aEditor->GetDocument(getter_AddRefs(doc)); 1.172 + 1.173 + if (NS_FAILED(result)) 1.174 + { 1.175 + UNLOCK_DOC(this); 1.176 + return result; 1.177 + } 1.178 + 1.179 + if (!doc || (mDOMDocument && doc != mDOMDocument)) 1.180 + { 1.181 + UNLOCK_DOC(this); 1.182 + return NS_ERROR_FAILURE; 1.183 + } 1.184 + 1.185 + if (!mDOMDocument) 1.186 + { 1.187 + mDOMDocument = doc; 1.188 + 1.189 + result = CreateDocumentContentIterator(getter_AddRefs(mIterator)); 1.190 + 1.191 + if (NS_FAILED(result)) 1.192 + { 1.193 + UNLOCK_DOC(this); 1.194 + return result; 1.195 + } 1.196 + 1.197 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.198 + 1.199 + result = FirstBlock(); 1.200 + 1.201 + if (NS_FAILED(result)) 1.202 + { 1.203 + UNLOCK_DOC(this); 1.204 + return result; 1.205 + } 1.206 + } 1.207 + 1.208 + mEditor = do_GetWeakReference(aEditor); 1.209 + 1.210 + result = aEditor->AddEditActionListener(this); 1.211 + 1.212 + UNLOCK_DOC(this); 1.213 + 1.214 + return result; 1.215 +} 1.216 + 1.217 +NS_IMETHODIMP 1.218 +nsTextServicesDocument::GetDocument(nsIDOMDocument **aDoc) 1.219 +{ 1.220 + NS_ENSURE_TRUE(aDoc, NS_ERROR_NULL_POINTER); 1.221 + 1.222 + *aDoc = nullptr; // init out param 1.223 + NS_ENSURE_TRUE(mDOMDocument, NS_ERROR_NOT_INITIALIZED); 1.224 + 1.225 + *aDoc = mDOMDocument; 1.226 + NS_ADDREF(*aDoc); 1.227 + 1.228 + return NS_OK; 1.229 +} 1.230 + 1.231 +NS_IMETHODIMP 1.232 +nsTextServicesDocument::SetExtent(nsIDOMRange* aDOMRange) 1.233 +{ 1.234 + NS_ENSURE_ARG_POINTER(aDOMRange); 1.235 + NS_ENSURE_TRUE(mDOMDocument, NS_ERROR_FAILURE); 1.236 + 1.237 + LOCK_DOC(this); 1.238 + 1.239 + // We need to store a copy of aDOMRange since we don't 1.240 + // know where it came from. 1.241 + 1.242 + nsresult result = aDOMRange->CloneRange(getter_AddRefs(mExtent)); 1.243 + 1.244 + if (NS_FAILED(result)) 1.245 + { 1.246 + UNLOCK_DOC(this); 1.247 + return result; 1.248 + } 1.249 + 1.250 + // Create a new iterator based on our new extent range. 1.251 + 1.252 + result = CreateContentIterator(mExtent, getter_AddRefs(mIterator)); 1.253 + 1.254 + if (NS_FAILED(result)) 1.255 + { 1.256 + UNLOCK_DOC(this); 1.257 + return result; 1.258 + } 1.259 + 1.260 + // Now position the iterator at the start of the first block 1.261 + // in the range. 1.262 + 1.263 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.264 + 1.265 + result = FirstBlock(); 1.266 + 1.267 + UNLOCK_DOC(this); 1.268 + 1.269 + return result; 1.270 +} 1.271 + 1.272 +NS_IMETHODIMP 1.273 +nsTextServicesDocument::ExpandRangeToWordBoundaries(nsIDOMRange *aRange) 1.274 +{ 1.275 + NS_ENSURE_ARG_POINTER(aRange); 1.276 + 1.277 + // Get the end points of the range. 1.278 + 1.279 + nsCOMPtr<nsIDOMNode> rngStartNode, rngEndNode; 1.280 + int32_t rngStartOffset, rngEndOffset; 1.281 + 1.282 + nsresult result = GetRangeEndPoints(aRange, 1.283 + getter_AddRefs(rngStartNode), 1.284 + &rngStartOffset, 1.285 + getter_AddRefs(rngEndNode), 1.286 + &rngEndOffset); 1.287 + 1.288 + NS_ENSURE_SUCCESS(result, result); 1.289 + 1.290 + // Create a content iterator based on the range. 1.291 + 1.292 + nsCOMPtr<nsIContentIterator> iter; 1.293 + result = CreateContentIterator(aRange, getter_AddRefs(iter)); 1.294 + 1.295 + NS_ENSURE_SUCCESS(result, result); 1.296 + 1.297 + // Find the first text node in the range. 1.298 + 1.299 + TSDIteratorStatus iterStatus; 1.300 + 1.301 + result = FirstTextNode(iter, &iterStatus); 1.302 + NS_ENSURE_SUCCESS(result, result); 1.303 + 1.304 + if (iterStatus == nsTextServicesDocument::eIsDone) 1.305 + { 1.306 + // No text was found so there's no adjustment necessary! 1.307 + return NS_OK; 1.308 + } 1.309 + 1.310 + nsINode *firstText = iter->GetCurrentNode(); 1.311 + NS_ENSURE_TRUE(firstText, NS_ERROR_FAILURE); 1.312 + 1.313 + // Find the last text node in the range. 1.314 + 1.315 + result = LastTextNode(iter, &iterStatus); 1.316 + NS_ENSURE_SUCCESS(result, result); 1.317 + 1.318 + if (iterStatus == nsTextServicesDocument::eIsDone) 1.319 + { 1.320 + // We should never get here because a first text block 1.321 + // was found above. 1.322 + NS_ASSERTION(false, "Found a first without a last!"); 1.323 + return NS_ERROR_FAILURE; 1.324 + } 1.325 + 1.326 + nsINode *lastText = iter->GetCurrentNode(); 1.327 + NS_ENSURE_TRUE(lastText, NS_ERROR_FAILURE); 1.328 + 1.329 + // Now make sure our end points are in terms of text nodes in the range! 1.330 + 1.331 + nsCOMPtr<nsIDOMNode> firstTextNode = do_QueryInterface(firstText); 1.332 + NS_ENSURE_TRUE(firstTextNode, NS_ERROR_FAILURE); 1.333 + 1.334 + if (rngStartNode != firstTextNode) 1.335 + { 1.336 + // The range includes the start of the first text node! 1.337 + rngStartNode = firstTextNode; 1.338 + rngStartOffset = 0; 1.339 + } 1.340 + 1.341 + nsCOMPtr<nsIDOMNode> lastTextNode = do_QueryInterface(lastText); 1.342 + NS_ENSURE_TRUE(lastTextNode, NS_ERROR_FAILURE); 1.343 + 1.344 + if (rngEndNode != lastTextNode) 1.345 + { 1.346 + // The range includes the end of the last text node! 1.347 + rngEndNode = lastTextNode; 1.348 + nsAutoString str; 1.349 + result = lastTextNode->GetNodeValue(str); 1.350 + rngEndOffset = str.Length(); 1.351 + } 1.352 + 1.353 + // Create a doc iterator so that we can scan beyond 1.354 + // the bounds of the extent range. 1.355 + 1.356 + nsCOMPtr<nsIContentIterator> docIter; 1.357 + result = CreateDocumentContentIterator(getter_AddRefs(docIter)); 1.358 + NS_ENSURE_SUCCESS(result, result); 1.359 + 1.360 + // Grab all the text in the block containing our 1.361 + // first text node. 1.362 + 1.363 + result = docIter->PositionAt(firstText); 1.364 + NS_ENSURE_SUCCESS(result, result); 1.365 + 1.366 + iterStatus = nsTextServicesDocument::eValid; 1.367 + 1.368 + nsTArray<OffsetEntry*> offsetTable; 1.369 + nsAutoString blockStr; 1.370 + 1.371 + result = CreateOffsetTable(&offsetTable, docIter, &iterStatus, 1.372 + nullptr, &blockStr); 1.373 + if (NS_FAILED(result)) 1.374 + { 1.375 + ClearOffsetTable(&offsetTable); 1.376 + return result; 1.377 + } 1.378 + 1.379 + nsCOMPtr<nsIDOMNode> wordStartNode, wordEndNode; 1.380 + int32_t wordStartOffset, wordEndOffset; 1.381 + 1.382 + result = FindWordBounds(&offsetTable, &blockStr, 1.383 + rngStartNode, rngStartOffset, 1.384 + getter_AddRefs(wordStartNode), &wordStartOffset, 1.385 + getter_AddRefs(wordEndNode), &wordEndOffset); 1.386 + 1.387 + ClearOffsetTable(&offsetTable); 1.388 + 1.389 + NS_ENSURE_SUCCESS(result, result); 1.390 + 1.391 + rngStartNode = wordStartNode; 1.392 + rngStartOffset = wordStartOffset; 1.393 + 1.394 + // Grab all the text in the block containing our 1.395 + // last text node. 1.396 + 1.397 + result = docIter->PositionAt(lastText); 1.398 + NS_ENSURE_SUCCESS(result, result); 1.399 + 1.400 + iterStatus = nsTextServicesDocument::eValid; 1.401 + 1.402 + result = CreateOffsetTable(&offsetTable, docIter, &iterStatus, 1.403 + nullptr, &blockStr); 1.404 + if (NS_FAILED(result)) 1.405 + { 1.406 + ClearOffsetTable(&offsetTable); 1.407 + return result; 1.408 + } 1.409 + 1.410 + result = FindWordBounds(&offsetTable, &blockStr, 1.411 + rngEndNode, rngEndOffset, 1.412 + getter_AddRefs(wordStartNode), &wordStartOffset, 1.413 + getter_AddRefs(wordEndNode), &wordEndOffset); 1.414 + 1.415 + ClearOffsetTable(&offsetTable); 1.416 + 1.417 + NS_ENSURE_SUCCESS(result, result); 1.418 + 1.419 + // To prevent expanding the range too much, we only change 1.420 + // rngEndNode and rngEndOffset if it isn't already at the start of the 1.421 + // word and isn't equivalent to rngStartNode and rngStartOffset. 1.422 + 1.423 + if (rngEndNode != wordStartNode || rngEndOffset != wordStartOffset || 1.424 + (rngEndNode == rngStartNode && rngEndOffset == rngStartOffset)) 1.425 + { 1.426 + rngEndNode = wordEndNode; 1.427 + rngEndOffset = wordEndOffset; 1.428 + } 1.429 + 1.430 + // Now adjust the range so that it uses our new 1.431 + // end points. 1.432 + 1.433 + result = aRange->SetEnd(rngEndNode, rngEndOffset); 1.434 + NS_ENSURE_SUCCESS(result, result); 1.435 + 1.436 + return aRange->SetStart(rngStartNode, rngStartOffset); 1.437 +} 1.438 + 1.439 +NS_IMETHODIMP 1.440 +nsTextServicesDocument::SetFilter(nsITextServicesFilter *aFilter) 1.441 +{ 1.442 + // Hang on to the filter so we can set it into the filtered iterator. 1.443 + mTxtSvcFilter = aFilter; 1.444 + 1.445 + return NS_OK; 1.446 +} 1.447 + 1.448 +NS_IMETHODIMP 1.449 +nsTextServicesDocument::GetCurrentTextBlock(nsString *aStr) 1.450 +{ 1.451 + nsresult result; 1.452 + 1.453 + NS_ENSURE_TRUE(aStr, NS_ERROR_NULL_POINTER); 1.454 + 1.455 + aStr->Truncate(); 1.456 + 1.457 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.458 + 1.459 + LOCK_DOC(this); 1.460 + 1.461 + result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus, 1.462 + mExtent, aStr); 1.463 + 1.464 + UNLOCK_DOC(this); 1.465 + 1.466 + return result; 1.467 +} 1.468 + 1.469 +NS_IMETHODIMP 1.470 +nsTextServicesDocument::FirstBlock() 1.471 +{ 1.472 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.473 + 1.474 + LOCK_DOC(this); 1.475 + 1.476 + nsresult result = FirstTextNode(mIterator, &mIteratorStatus); 1.477 + 1.478 + if (NS_FAILED(result)) 1.479 + { 1.480 + UNLOCK_DOC(this); 1.481 + return result; 1.482 + } 1.483 + 1.484 + // Keep track of prev and next blocks, just in case 1.485 + // the text service blows away the current block. 1.486 + 1.487 + if (mIteratorStatus == nsTextServicesDocument::eValid) 1.488 + { 1.489 + mPrevTextBlock = nullptr; 1.490 + result = GetFirstTextNodeInNextBlock(getter_AddRefs(mNextTextBlock)); 1.491 + } 1.492 + else 1.493 + { 1.494 + // There's no text block in the document! 1.495 + 1.496 + mPrevTextBlock = nullptr; 1.497 + mNextTextBlock = nullptr; 1.498 + } 1.499 + 1.500 + UNLOCK_DOC(this); 1.501 + 1.502 + return result; 1.503 +} 1.504 + 1.505 +NS_IMETHODIMP 1.506 +nsTextServicesDocument::LastSelectedBlock(TSDBlockSelectionStatus *aSelStatus, 1.507 + int32_t *aSelOffset, 1.508 + int32_t *aSelLength) 1.509 +{ 1.510 + nsresult result = NS_OK; 1.511 + 1.512 + NS_ENSURE_TRUE(aSelStatus && aSelOffset && aSelLength, NS_ERROR_NULL_POINTER); 1.513 + 1.514 + LOCK_DOC(this); 1.515 + 1.516 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.517 + 1.518 + *aSelStatus = nsITextServicesDocument::eBlockNotFound; 1.519 + *aSelOffset = *aSelLength = -1; 1.520 + 1.521 + if (!mSelCon || !mIterator) 1.522 + { 1.523 + UNLOCK_DOC(this); 1.524 + return NS_ERROR_FAILURE; 1.525 + } 1.526 + 1.527 + nsCOMPtr<nsISelection> selection; 1.528 + bool isCollapsed = false; 1.529 + 1.530 + result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); 1.531 + 1.532 + if (NS_FAILED(result)) 1.533 + { 1.534 + UNLOCK_DOC(this); 1.535 + return result; 1.536 + } 1.537 + 1.538 + result = selection->GetIsCollapsed(&isCollapsed); 1.539 + 1.540 + if (NS_FAILED(result)) 1.541 + { 1.542 + UNLOCK_DOC(this); 1.543 + return result; 1.544 + } 1.545 + 1.546 + nsCOMPtr<nsIContentIterator> iter; 1.547 + nsCOMPtr<nsIDOMRange> range; 1.548 + nsCOMPtr<nsIDOMNode> parent; 1.549 + int32_t i, rangeCount, offset; 1.550 + 1.551 + if (isCollapsed) 1.552 + { 1.553 + // We have a caret. Check if the caret is in a text node. 1.554 + // If it is, make the text node's block the current block. 1.555 + // If the caret isn't in a text node, search forwards in 1.556 + // the document, till we find a text node. 1.557 + 1.558 + result = selection->GetRangeAt(0, getter_AddRefs(range)); 1.559 + 1.560 + if (NS_FAILED(result)) 1.561 + { 1.562 + UNLOCK_DOC(this); 1.563 + return result; 1.564 + } 1.565 + 1.566 + if (!range) 1.567 + { 1.568 + UNLOCK_DOC(this); 1.569 + return NS_ERROR_FAILURE; 1.570 + } 1.571 + 1.572 + result = range->GetStartContainer(getter_AddRefs(parent)); 1.573 + 1.574 + if (NS_FAILED(result)) 1.575 + { 1.576 + UNLOCK_DOC(this); 1.577 + return result; 1.578 + } 1.579 + 1.580 + if (!parent) 1.581 + { 1.582 + UNLOCK_DOC(this); 1.583 + return NS_ERROR_FAILURE; 1.584 + } 1.585 + 1.586 + result = range->GetStartOffset(&offset); 1.587 + 1.588 + if (NS_FAILED(result)) 1.589 + { 1.590 + UNLOCK_DOC(this); 1.591 + return result; 1.592 + } 1.593 + 1.594 + if (IsTextNode(parent)) 1.595 + { 1.596 + // The caret is in a text node. Find the beginning 1.597 + // of the text block containing this text node and 1.598 + // return. 1.599 + 1.600 + nsCOMPtr<nsIContent> content(do_QueryInterface(parent)); 1.601 + 1.602 + if (!content) 1.603 + { 1.604 + UNLOCK_DOC(this); 1.605 + return NS_ERROR_FAILURE; 1.606 + } 1.607 + 1.608 + result = mIterator->PositionAt(content); 1.609 + 1.610 + if (NS_FAILED(result)) 1.611 + { 1.612 + UNLOCK_DOC(this); 1.613 + return result; 1.614 + } 1.615 + 1.616 + result = FirstTextNodeInCurrentBlock(mIterator); 1.617 + 1.618 + if (NS_FAILED(result)) 1.619 + { 1.620 + UNLOCK_DOC(this); 1.621 + return result; 1.622 + } 1.623 + 1.624 + mIteratorStatus = nsTextServicesDocument::eValid; 1.625 + 1.626 + result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus, 1.627 + mExtent, nullptr); 1.628 + 1.629 + if (NS_FAILED(result)) 1.630 + { 1.631 + UNLOCK_DOC(this); 1.632 + return result; 1.633 + } 1.634 + 1.635 + result = GetSelection(aSelStatus, aSelOffset, aSelLength); 1.636 + 1.637 + if (NS_FAILED(result)) 1.638 + { 1.639 + UNLOCK_DOC(this); 1.640 + return result; 1.641 + } 1.642 + 1.643 + if (*aSelStatus == nsITextServicesDocument::eBlockContains) 1.644 + result = SetSelectionInternal(*aSelOffset, *aSelLength, false); 1.645 + } 1.646 + else 1.647 + { 1.648 + // The caret isn't in a text node. Create an iterator 1.649 + // based on a range that extends from the current caret 1.650 + // position to the end of the document, then walk forwards 1.651 + // till you find a text node, then find the beginning of it's block. 1.652 + 1.653 + result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, false, getter_AddRefs(range)); 1.654 + 1.655 + if (NS_FAILED(result)) 1.656 + { 1.657 + UNLOCK_DOC(this); 1.658 + return result; 1.659 + } 1.660 + 1.661 + result = range->GetCollapsed(&isCollapsed); 1.662 + 1.663 + if (NS_FAILED(result)) 1.664 + { 1.665 + UNLOCK_DOC(this); 1.666 + return result; 1.667 + } 1.668 + 1.669 + if (isCollapsed) 1.670 + { 1.671 + // If we get here, the range is collapsed because there is nothing after 1.672 + // the caret! Just return NS_OK; 1.673 + 1.674 + UNLOCK_DOC(this); 1.675 + return NS_OK; 1.676 + } 1.677 + 1.678 + result = CreateContentIterator(range, getter_AddRefs(iter)); 1.679 + 1.680 + if (NS_FAILED(result)) 1.681 + { 1.682 + UNLOCK_DOC(this); 1.683 + return result; 1.684 + } 1.685 + 1.686 + iter->First(); 1.687 + 1.688 + nsCOMPtr<nsIContent> content; 1.689 + while (!iter->IsDone()) 1.690 + { 1.691 + content = do_QueryInterface(iter->GetCurrentNode()); 1.692 + 1.693 + if (IsTextNode(content)) 1.694 + break; 1.695 + 1.696 + content = nullptr; 1.697 + 1.698 + iter->Next(); 1.699 + } 1.700 + 1.701 + if (!content) 1.702 + { 1.703 + UNLOCK_DOC(this); 1.704 + return NS_OK; 1.705 + } 1.706 + 1.707 + result = mIterator->PositionAt(content); 1.708 + 1.709 + if (NS_FAILED(result)) 1.710 + { 1.711 + UNLOCK_DOC(this); 1.712 + return result; 1.713 + } 1.714 + 1.715 + result = FirstTextNodeInCurrentBlock(mIterator); 1.716 + 1.717 + if (NS_FAILED(result)) 1.718 + { 1.719 + UNLOCK_DOC(this); 1.720 + return result; 1.721 + } 1.722 + 1.723 + mIteratorStatus = nsTextServicesDocument::eValid; 1.724 + 1.725 + result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus, 1.726 + mExtent, nullptr); 1.727 + 1.728 + if (NS_FAILED(result)) 1.729 + { 1.730 + UNLOCK_DOC(this); 1.731 + return result; 1.732 + } 1.733 + 1.734 + result = GetSelection(aSelStatus, aSelOffset, aSelLength); 1.735 + 1.736 + if (NS_FAILED(result)) 1.737 + { 1.738 + UNLOCK_DOC(this); 1.739 + return result; 1.740 + } 1.741 + } 1.742 + 1.743 + UNLOCK_DOC(this); 1.744 + 1.745 + return result; 1.746 + } 1.747 + 1.748 + // If we get here, we have an uncollapsed selection! 1.749 + // Look backwards through each range in the selection till you 1.750 + // find the first text node. If you find one, find the 1.751 + // beginning of its text block, and make it the current 1.752 + // block. 1.753 + 1.754 + result = selection->GetRangeCount(&rangeCount); 1.755 + 1.756 + if (NS_FAILED(result)) 1.757 + { 1.758 + UNLOCK_DOC(this); 1.759 + return result; 1.760 + } 1.761 + 1.762 + NS_ASSERTION(rangeCount > 0, "Unexpected range count!"); 1.763 + 1.764 + if (rangeCount <= 0) 1.765 + { 1.766 + UNLOCK_DOC(this); 1.767 + return NS_OK; 1.768 + } 1.769 + 1.770 + // XXX: We may need to add some code here to make sure 1.771 + // the ranges are sorted in document appearance order! 1.772 + 1.773 + for (i = rangeCount - 1; i >= 0; i--) 1.774 + { 1.775 + // Get the i'th range from the selection. 1.776 + 1.777 + result = selection->GetRangeAt(i, getter_AddRefs(range)); 1.778 + 1.779 + if (NS_FAILED(result)) 1.780 + { 1.781 + UNLOCK_DOC(this); 1.782 + return result; 1.783 + } 1.784 + 1.785 + // Create an iterator for the range. 1.786 + 1.787 + result = CreateContentIterator(range, getter_AddRefs(iter)); 1.788 + 1.789 + if (NS_FAILED(result)) 1.790 + { 1.791 + UNLOCK_DOC(this); 1.792 + return result; 1.793 + } 1.794 + 1.795 + iter->Last(); 1.796 + 1.797 + // Now walk through the range till we find a text node. 1.798 + 1.799 + while (!iter->IsDone()) 1.800 + { 1.801 + if (iter->GetCurrentNode()->NodeType() == nsIDOMNode::TEXT_NODE) { 1.802 + // We found a text node, so position the document's 1.803 + // iterator at the beginning of the block, then get 1.804 + // the selection in terms of the string offset. 1.805 + nsCOMPtr<nsIContent> content = iter->GetCurrentNode()->AsContent(); 1.806 + 1.807 + result = mIterator->PositionAt(content); 1.808 + 1.809 + if (NS_FAILED(result)) 1.810 + { 1.811 + UNLOCK_DOC(this); 1.812 + return result; 1.813 + } 1.814 + 1.815 + result = FirstTextNodeInCurrentBlock(mIterator); 1.816 + 1.817 + if (NS_FAILED(result)) 1.818 + { 1.819 + UNLOCK_DOC(this); 1.820 + return result; 1.821 + } 1.822 + 1.823 + mIteratorStatus = nsTextServicesDocument::eValid; 1.824 + 1.825 + result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus, 1.826 + mExtent, nullptr); 1.827 + 1.828 + if (NS_FAILED(result)) 1.829 + { 1.830 + UNLOCK_DOC(this); 1.831 + return result; 1.832 + } 1.833 + 1.834 + result = GetSelection(aSelStatus, aSelOffset, aSelLength); 1.835 + 1.836 + UNLOCK_DOC(this); 1.837 + 1.838 + return result; 1.839 + 1.840 + } 1.841 + 1.842 + iter->Prev(); 1.843 + } 1.844 + } 1.845 + 1.846 + // If we get here, we didn't find any text node in the selection! 1.847 + // Create a range that extends from the end of the selection, 1.848 + // to the end of the document, then iterate forwards through 1.849 + // it till you find a text node! 1.850 + 1.851 + result = selection->GetRangeAt(rangeCount - 1, getter_AddRefs(range)); 1.852 + 1.853 + if (NS_FAILED(result)) 1.854 + { 1.855 + UNLOCK_DOC(this); 1.856 + return result; 1.857 + } 1.858 + 1.859 + if (!range) 1.860 + { 1.861 + UNLOCK_DOC(this); 1.862 + return NS_ERROR_FAILURE; 1.863 + } 1.864 + 1.865 + result = range->GetEndContainer(getter_AddRefs(parent)); 1.866 + 1.867 + if (NS_FAILED(result)) 1.868 + { 1.869 + UNLOCK_DOC(this); 1.870 + return result; 1.871 + } 1.872 + 1.873 + if (!parent) 1.874 + { 1.875 + UNLOCK_DOC(this); 1.876 + return NS_ERROR_FAILURE; 1.877 + } 1.878 + 1.879 + result = range->GetEndOffset(&offset); 1.880 + 1.881 + if (NS_FAILED(result)) 1.882 + { 1.883 + UNLOCK_DOC(this); 1.884 + return result; 1.885 + } 1.886 + 1.887 + result = CreateDocumentContentRootToNodeOffsetRange(parent, offset, false, getter_AddRefs(range)); 1.888 + 1.889 + if (NS_FAILED(result)) 1.890 + { 1.891 + UNLOCK_DOC(this); 1.892 + return result; 1.893 + } 1.894 + 1.895 + result = range->GetCollapsed(&isCollapsed); 1.896 + 1.897 + if (NS_FAILED(result)) 1.898 + { 1.899 + UNLOCK_DOC(this); 1.900 + return result; 1.901 + } 1.902 + 1.903 + if (isCollapsed) 1.904 + { 1.905 + // If we get here, the range is collapsed because there is nothing after 1.906 + // the current selection! Just return NS_OK; 1.907 + 1.908 + UNLOCK_DOC(this); 1.909 + return NS_OK; 1.910 + } 1.911 + 1.912 + result = CreateContentIterator(range, getter_AddRefs(iter)); 1.913 + 1.914 + if (NS_FAILED(result)) 1.915 + { 1.916 + UNLOCK_DOC(this); 1.917 + return result; 1.918 + } 1.919 + 1.920 + iter->First(); 1.921 + 1.922 + while (!iter->IsDone()) 1.923 + { 1.924 + if (iter->GetCurrentNode()->NodeType() == nsIDOMNode::TEXT_NODE) { 1.925 + // We found a text node! Adjust the document's iterator to point 1.926 + // to the beginning of its text block, then get the current selection. 1.927 + nsCOMPtr<nsIContent> content = iter->GetCurrentNode()->AsContent(); 1.928 + 1.929 + result = mIterator->PositionAt(content); 1.930 + 1.931 + if (NS_FAILED(result)) 1.932 + { 1.933 + UNLOCK_DOC(this); 1.934 + return result; 1.935 + } 1.936 + 1.937 + result = FirstTextNodeInCurrentBlock(mIterator); 1.938 + 1.939 + if (NS_FAILED(result)) 1.940 + { 1.941 + UNLOCK_DOC(this); 1.942 + return result; 1.943 + } 1.944 + 1.945 + 1.946 + mIteratorStatus = nsTextServicesDocument::eValid; 1.947 + 1.948 + result = CreateOffsetTable(&mOffsetTable, mIterator, &mIteratorStatus, 1.949 + mExtent, nullptr); 1.950 + 1.951 + if (NS_FAILED(result)) 1.952 + { 1.953 + UNLOCK_DOC(this); 1.954 + return result; 1.955 + } 1.956 + 1.957 + result = GetSelection(aSelStatus, aSelOffset, aSelLength); 1.958 + 1.959 + UNLOCK_DOC(this); 1.960 + 1.961 + return result; 1.962 + } 1.963 + 1.964 + iter->Next(); 1.965 + } 1.966 + 1.967 + // If we get here, we didn't find any block before or inside 1.968 + // the selection! Just return OK. 1.969 + 1.970 + UNLOCK_DOC(this); 1.971 + 1.972 + return NS_OK; 1.973 +} 1.974 + 1.975 +NS_IMETHODIMP 1.976 +nsTextServicesDocument::PrevBlock() 1.977 +{ 1.978 + nsresult result = NS_OK; 1.979 + 1.980 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.981 + 1.982 + LOCK_DOC(this); 1.983 + 1.984 + if (mIteratorStatus == nsTextServicesDocument::eIsDone) 1.985 + return NS_OK; 1.986 + 1.987 + switch (mIteratorStatus) 1.988 + { 1.989 + case nsTextServicesDocument::eValid: 1.990 + case nsTextServicesDocument::eNext: 1.991 + 1.992 + result = FirstTextNodeInPrevBlock(mIterator); 1.993 + 1.994 + if (NS_FAILED(result)) 1.995 + { 1.996 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.997 + UNLOCK_DOC(this); 1.998 + return result; 1.999 + } 1.1000 + 1.1001 + if (mIterator->IsDone()) 1.1002 + { 1.1003 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.1004 + UNLOCK_DOC(this); 1.1005 + return NS_OK; 1.1006 + } 1.1007 + 1.1008 + mIteratorStatus = nsTextServicesDocument::eValid; 1.1009 + break; 1.1010 + 1.1011 + case nsTextServicesDocument::ePrev: 1.1012 + 1.1013 + // The iterator already points to the previous 1.1014 + // block, so don't do anything. 1.1015 + 1.1016 + mIteratorStatus = nsTextServicesDocument::eValid; 1.1017 + break; 1.1018 + 1.1019 + default: 1.1020 + 1.1021 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.1022 + break; 1.1023 + } 1.1024 + 1.1025 + // Keep track of prev and next blocks, just in case 1.1026 + // the text service blows away the current block. 1.1027 + 1.1028 + if (mIteratorStatus == nsTextServicesDocument::eValid) 1.1029 + { 1.1030 + result = GetFirstTextNodeInPrevBlock(getter_AddRefs(mPrevTextBlock)); 1.1031 + result = GetFirstTextNodeInNextBlock(getter_AddRefs(mNextTextBlock)); 1.1032 + } 1.1033 + else 1.1034 + { 1.1035 + // We must be done! 1.1036 + 1.1037 + mPrevTextBlock = nullptr; 1.1038 + mNextTextBlock = nullptr; 1.1039 + } 1.1040 + 1.1041 + UNLOCK_DOC(this); 1.1042 + 1.1043 + return result; 1.1044 +} 1.1045 + 1.1046 +NS_IMETHODIMP 1.1047 +nsTextServicesDocument::NextBlock() 1.1048 +{ 1.1049 + nsresult result = NS_OK; 1.1050 + 1.1051 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.1052 + 1.1053 + LOCK_DOC(this); 1.1054 + 1.1055 + if (mIteratorStatus == nsTextServicesDocument::eIsDone) 1.1056 + return NS_OK; 1.1057 + 1.1058 + switch (mIteratorStatus) 1.1059 + { 1.1060 + case nsTextServicesDocument::eValid: 1.1061 + 1.1062 + // Advance the iterator to the next text block. 1.1063 + 1.1064 + result = FirstTextNodeInNextBlock(mIterator); 1.1065 + 1.1066 + if (NS_FAILED(result)) 1.1067 + { 1.1068 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.1069 + UNLOCK_DOC(this); 1.1070 + return result; 1.1071 + } 1.1072 + 1.1073 + if (mIterator->IsDone()) 1.1074 + { 1.1075 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.1076 + UNLOCK_DOC(this); 1.1077 + return NS_OK; 1.1078 + } 1.1079 + 1.1080 + mIteratorStatus = nsTextServicesDocument::eValid; 1.1081 + break; 1.1082 + 1.1083 + case nsTextServicesDocument::eNext: 1.1084 + 1.1085 + // The iterator already points to the next block, 1.1086 + // so don't do anything to it! 1.1087 + 1.1088 + mIteratorStatus = nsTextServicesDocument::eValid; 1.1089 + break; 1.1090 + 1.1091 + case nsTextServicesDocument::ePrev: 1.1092 + 1.1093 + // If the iterator is pointing to the previous block, 1.1094 + // we know that there is no next text block! Just 1.1095 + // fall through to the default case! 1.1096 + 1.1097 + default: 1.1098 + 1.1099 + mIteratorStatus = nsTextServicesDocument::eIsDone; 1.1100 + break; 1.1101 + } 1.1102 + 1.1103 + // Keep track of prev and next blocks, just in case 1.1104 + // the text service blows away the current block. 1.1105 + 1.1106 + if (mIteratorStatus == nsTextServicesDocument::eValid) 1.1107 + { 1.1108 + result = GetFirstTextNodeInPrevBlock(getter_AddRefs(mPrevTextBlock)); 1.1109 + result = GetFirstTextNodeInNextBlock(getter_AddRefs(mNextTextBlock)); 1.1110 + } 1.1111 + else 1.1112 + { 1.1113 + // We must be done. 1.1114 + 1.1115 + mPrevTextBlock = nullptr; 1.1116 + mNextTextBlock = nullptr; 1.1117 + } 1.1118 + 1.1119 + 1.1120 + UNLOCK_DOC(this); 1.1121 + 1.1122 + return result; 1.1123 +} 1.1124 + 1.1125 +NS_IMETHODIMP 1.1126 +nsTextServicesDocument::IsDone(bool *aIsDone) 1.1127 +{ 1.1128 + NS_ENSURE_TRUE(aIsDone, NS_ERROR_NULL_POINTER); 1.1129 + 1.1130 + *aIsDone = false; 1.1131 + 1.1132 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.1133 + 1.1134 + LOCK_DOC(this); 1.1135 + 1.1136 + *aIsDone = (mIteratorStatus == nsTextServicesDocument::eIsDone) ? true : false; 1.1137 + 1.1138 + UNLOCK_DOC(this); 1.1139 + 1.1140 + return NS_OK; 1.1141 +} 1.1142 + 1.1143 +NS_IMETHODIMP 1.1144 +nsTextServicesDocument::SetSelection(int32_t aOffset, int32_t aLength) 1.1145 +{ 1.1146 + nsresult result; 1.1147 + 1.1148 + NS_ENSURE_TRUE(mSelCon && aOffset >= 0 && aLength >= 0, NS_ERROR_FAILURE); 1.1149 + 1.1150 + LOCK_DOC(this); 1.1151 + 1.1152 + result = SetSelectionInternal(aOffset, aLength, true); 1.1153 + 1.1154 + UNLOCK_DOC(this); 1.1155 + 1.1156 + //**** KDEBUG **** 1.1157 + // printf("\n * Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.1158 + //**** KDEBUG **** 1.1159 + 1.1160 + return result; 1.1161 +} 1.1162 + 1.1163 +NS_IMETHODIMP 1.1164 +nsTextServicesDocument::ScrollSelectionIntoView() 1.1165 +{ 1.1166 + nsresult result; 1.1167 + 1.1168 + NS_ENSURE_TRUE(mSelCon, NS_ERROR_FAILURE); 1.1169 + 1.1170 + LOCK_DOC(this); 1.1171 + 1.1172 + // After ScrollSelectionIntoView(), the pending notifications might be flushed 1.1173 + // and PresShell/PresContext/Frames may be dead. See bug 418470. 1.1174 + result = mSelCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, nsISelectionController::SELECTION_FOCUS_REGION, 1.1175 + nsISelectionController::SCROLL_SYNCHRONOUS); 1.1176 + 1.1177 + UNLOCK_DOC(this); 1.1178 + 1.1179 + return result; 1.1180 +} 1.1181 + 1.1182 +NS_IMETHODIMP 1.1183 +nsTextServicesDocument::DeleteSelection() 1.1184 +{ 1.1185 + nsresult result = NS_OK; 1.1186 + 1.1187 + // We don't allow deletion during a collapsed selection! 1.1188 + nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor)); 1.1189 + NS_ASSERTION(editor, "DeleteSelection called without an editor present!"); 1.1190 + NS_ASSERTION(SelectionIsValid(), "DeleteSelection called without a valid selection!"); 1.1191 + 1.1192 + if (!editor || !SelectionIsValid()) 1.1193 + return NS_ERROR_FAILURE; 1.1194 + 1.1195 + if (SelectionIsCollapsed()) 1.1196 + return NS_OK; 1.1197 + 1.1198 + LOCK_DOC(this); 1.1199 + 1.1200 + //**** KDEBUG **** 1.1201 + // printf("\n---- Before Delete\n"); 1.1202 + // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.1203 + // PrintOffsetTable(); 1.1204 + //**** KDEBUG **** 1.1205 + 1.1206 + // If we have an mExtent, save off its current set of 1.1207 + // end points so we can compare them against mExtent's 1.1208 + // set after the deletion of the content. 1.1209 + 1.1210 + nsCOMPtr<nsIDOMNode> origStartNode, origEndNode; 1.1211 + int32_t origStartOffset = 0, origEndOffset = 0; 1.1212 + 1.1213 + if (mExtent) 1.1214 + { 1.1215 + result = GetRangeEndPoints(mExtent, 1.1216 + getter_AddRefs(origStartNode), &origStartOffset, 1.1217 + getter_AddRefs(origEndNode), &origEndOffset); 1.1218 + 1.1219 + if (NS_FAILED(result)) 1.1220 + { 1.1221 + UNLOCK_DOC(this); 1.1222 + return result; 1.1223 + } 1.1224 + } 1.1225 + 1.1226 + int32_t i, selLength; 1.1227 + OffsetEntry *entry, *newEntry; 1.1228 + 1.1229 + for (i = mSelStartIndex; i <= mSelEndIndex; i++) 1.1230 + { 1.1231 + entry = mOffsetTable[i]; 1.1232 + 1.1233 + if (i == mSelStartIndex) 1.1234 + { 1.1235 + // Calculate the length of the selection. Note that the 1.1236 + // selection length can be zero if the start of the selection 1.1237 + // is at the very end of a text node entry. 1.1238 + 1.1239 + if (entry->mIsInsertedText) 1.1240 + { 1.1241 + // Inserted text offset entries have no width when 1.1242 + // talking in terms of string offsets! If the beginning 1.1243 + // of the selection is in an inserted text offset entry, 1.1244 + // the caret is always at the end of the entry! 1.1245 + 1.1246 + selLength = 0; 1.1247 + } 1.1248 + else 1.1249 + selLength = entry->mLength - (mSelStartOffset - entry->mStrOffset); 1.1250 + 1.1251 + if (selLength > 0 && mSelStartOffset > entry->mStrOffset) 1.1252 + { 1.1253 + // Selection doesn't start at the beginning of the 1.1254 + // text node entry. We need to split this entry into 1.1255 + // two pieces, the piece before the selection, and 1.1256 + // the piece inside the selection. 1.1257 + 1.1258 + result = SplitOffsetEntry(i, selLength); 1.1259 + 1.1260 + if (NS_FAILED(result)) 1.1261 + { 1.1262 + UNLOCK_DOC(this); 1.1263 + return result; 1.1264 + } 1.1265 + 1.1266 + // Adjust selection indexes to account for new entry: 1.1267 + 1.1268 + ++mSelStartIndex; 1.1269 + ++mSelEndIndex; 1.1270 + ++i; 1.1271 + 1.1272 + entry = mOffsetTable[i]; 1.1273 + } 1.1274 + 1.1275 + 1.1276 + if (selLength > 0 && mSelStartIndex < mSelEndIndex) 1.1277 + { 1.1278 + // The entire entry is contained in the selection. Mark the 1.1279 + // entry invalid. 1.1280 + 1.1281 + entry->mIsValid = false; 1.1282 + } 1.1283 + } 1.1284 + 1.1285 + //**** KDEBUG **** 1.1286 + // printf("\n---- Middle Delete\n"); 1.1287 + // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.1288 + // PrintOffsetTable(); 1.1289 + //**** KDEBUG **** 1.1290 + 1.1291 + if (i == mSelEndIndex) 1.1292 + { 1.1293 + if (entry->mIsInsertedText) 1.1294 + { 1.1295 + // Inserted text offset entries have no width when 1.1296 + // talking in terms of string offsets! If the end 1.1297 + // of the selection is in an inserted text offset entry, 1.1298 + // the selection includes the entire entry! 1.1299 + 1.1300 + entry->mIsValid = false; 1.1301 + } 1.1302 + else 1.1303 + { 1.1304 + // Calculate the length of the selection. Note that the 1.1305 + // selection length can be zero if the end of the selection 1.1306 + // is at the very beginning of a text node entry. 1.1307 + 1.1308 + selLength = mSelEndOffset - entry->mStrOffset; 1.1309 + 1.1310 + if (selLength > 0 && mSelEndOffset < entry->mStrOffset + entry->mLength) 1.1311 + { 1.1312 + // mStrOffset is guaranteed to be inside the selection, even 1.1313 + // when mSelStartIndex == mSelEndIndex. 1.1314 + 1.1315 + result = SplitOffsetEntry(i, entry->mLength - selLength); 1.1316 + 1.1317 + if (NS_FAILED(result)) 1.1318 + { 1.1319 + UNLOCK_DOC(this); 1.1320 + return result; 1.1321 + } 1.1322 + 1.1323 + // Update the entry fields: 1.1324 + 1.1325 + newEntry = mOffsetTable[i+1]; 1.1326 + newEntry->mNodeOffset = entry->mNodeOffset; 1.1327 + } 1.1328 + 1.1329 + 1.1330 + if (selLength > 0 && mSelEndOffset == entry->mStrOffset + entry->mLength) 1.1331 + { 1.1332 + // The entire entry is contained in the selection. Mark the 1.1333 + // entry invalid. 1.1334 + 1.1335 + entry->mIsValid = false; 1.1336 + } 1.1337 + } 1.1338 + } 1.1339 + 1.1340 + if (i != mSelStartIndex && i != mSelEndIndex) 1.1341 + { 1.1342 + // The entire entry is contained in the selection. Mark the 1.1343 + // entry invalid. 1.1344 + 1.1345 + entry->mIsValid = false; 1.1346 + } 1.1347 + } 1.1348 + 1.1349 + // Make sure mIterator always points to something valid! 1.1350 + 1.1351 + AdjustContentIterator(); 1.1352 + 1.1353 + // Now delete the actual content! 1.1354 + 1.1355 + result = editor->DeleteSelection(nsIEditor::ePrevious, nsIEditor::eStrip); 1.1356 + 1.1357 + if (NS_FAILED(result)) 1.1358 + { 1.1359 + UNLOCK_DOC(this); 1.1360 + return result; 1.1361 + } 1.1362 + 1.1363 + // Now that we've actually deleted the selected content, 1.1364 + // check to see if our mExtent has changed, if so, then 1.1365 + // we have to create a new content iterator! 1.1366 + 1.1367 + if (origStartNode && origEndNode) 1.1368 + { 1.1369 + nsCOMPtr<nsIDOMNode> curStartNode, curEndNode; 1.1370 + int32_t curStartOffset = 0, curEndOffset = 0; 1.1371 + 1.1372 + result = GetRangeEndPoints(mExtent, 1.1373 + getter_AddRefs(curStartNode), &curStartOffset, 1.1374 + getter_AddRefs(curEndNode), &curEndOffset); 1.1375 + 1.1376 + if (NS_FAILED(result)) 1.1377 + { 1.1378 + UNLOCK_DOC(this); 1.1379 + return result; 1.1380 + } 1.1381 + 1.1382 + if (origStartNode != curStartNode || origEndNode != curEndNode) 1.1383 + { 1.1384 + // The range has changed, so we need to create a new content 1.1385 + // iterator based on the new range. 1.1386 + 1.1387 + nsCOMPtr<nsIContent> curContent; 1.1388 + 1.1389 + if (mIteratorStatus != nsTextServicesDocument::eIsDone) { 1.1390 + // The old iterator is still pointing to something valid, 1.1391 + // so get its current node so we can restore it after we 1.1392 + // create the new iterator! 1.1393 + 1.1394 + curContent = mIterator->GetCurrentNode() 1.1395 + ? mIterator->GetCurrentNode()->AsContent() 1.1396 + : nullptr; 1.1397 + } 1.1398 + 1.1399 + // Create the new iterator. 1.1400 + 1.1401 + result = CreateContentIterator(mExtent, getter_AddRefs(mIterator)); 1.1402 + 1.1403 + if (NS_FAILED(result)) 1.1404 + { 1.1405 + UNLOCK_DOC(this); 1.1406 + return result; 1.1407 + } 1.1408 + 1.1409 + // Now make the new iterator point to the content node 1.1410 + // the old one was pointing at. 1.1411 + 1.1412 + if (curContent) 1.1413 + { 1.1414 + result = mIterator->PositionAt(curContent); 1.1415 + 1.1416 + if (NS_FAILED(result)) 1.1417 + mIteratorStatus = eIsDone; 1.1418 + else 1.1419 + mIteratorStatus = eValid; 1.1420 + } 1.1421 + } 1.1422 + } 1.1423 + 1.1424 + entry = 0; 1.1425 + 1.1426 + // Move the caret to the end of the first valid entry. 1.1427 + // Start with mSelStartIndex since it may still be valid. 1.1428 + 1.1429 + for (i = mSelStartIndex; !entry && i >= 0; i--) 1.1430 + { 1.1431 + entry = mOffsetTable[i]; 1.1432 + 1.1433 + if (!entry->mIsValid) 1.1434 + entry = 0; 1.1435 + else 1.1436 + { 1.1437 + mSelStartIndex = mSelEndIndex = i; 1.1438 + mSelStartOffset = mSelEndOffset = entry->mStrOffset + entry->mLength; 1.1439 + } 1.1440 + } 1.1441 + 1.1442 + // If we still don't have a valid entry, move the caret 1.1443 + // to the next valid entry after the selection: 1.1444 + 1.1445 + for (i = mSelEndIndex; !entry && i < int32_t(mOffsetTable.Length()); i++) 1.1446 + { 1.1447 + entry = mOffsetTable[i]; 1.1448 + 1.1449 + if (!entry->mIsValid) 1.1450 + entry = 0; 1.1451 + else 1.1452 + { 1.1453 + mSelStartIndex = mSelEndIndex = i; 1.1454 + mSelStartOffset = mSelEndOffset = entry->mStrOffset; 1.1455 + } 1.1456 + } 1.1457 + 1.1458 + if (entry) 1.1459 + result = SetSelection(mSelStartOffset, 0); 1.1460 + else 1.1461 + { 1.1462 + // Uuughh we have no valid offset entry to place our 1.1463 + // caret ... just mark the selection invalid. 1.1464 + 1.1465 + mSelStartIndex = mSelEndIndex = -1; 1.1466 + mSelStartOffset = mSelEndOffset = -1; 1.1467 + } 1.1468 + 1.1469 + // Now remove any invalid entries from the offset table. 1.1470 + 1.1471 + result = RemoveInvalidOffsetEntries(); 1.1472 + 1.1473 + //**** KDEBUG **** 1.1474 + // printf("\n---- After Delete\n"); 1.1475 + // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.1476 + // PrintOffsetTable(); 1.1477 + //**** KDEBUG **** 1.1478 + 1.1479 + UNLOCK_DOC(this); 1.1480 + 1.1481 + return result; 1.1482 +} 1.1483 + 1.1484 +NS_IMETHODIMP 1.1485 +nsTextServicesDocument::InsertText(const nsString *aText) 1.1486 +{ 1.1487 + nsresult result = NS_OK; 1.1488 + 1.1489 + nsCOMPtr<nsIEditor> editor (do_QueryReferent(mEditor)); 1.1490 + NS_ASSERTION(editor, "InsertText called without an editor present!"); 1.1491 + 1.1492 + if (!editor || !SelectionIsValid()) 1.1493 + return NS_ERROR_FAILURE; 1.1494 + 1.1495 + NS_ENSURE_TRUE(aText, NS_ERROR_NULL_POINTER); 1.1496 + 1.1497 + // If the selection is not collapsed, we need to save 1.1498 + // off the selection offsets so we can restore the 1.1499 + // selection and delete the selected content after we've 1.1500 + // inserted the new text. This is necessary to try and 1.1501 + // retain as much of the original style of the content 1.1502 + // being deleted. 1.1503 + 1.1504 + bool collapsedSelection = SelectionIsCollapsed(); 1.1505 + int32_t savedSelOffset = mSelStartOffset; 1.1506 + int32_t savedSelLength = mSelEndOffset - mSelStartOffset; 1.1507 + 1.1508 + if (!collapsedSelection) 1.1509 + { 1.1510 + // Collapse to the start of the current selection 1.1511 + // for the insert! 1.1512 + 1.1513 + result = SetSelection(mSelStartOffset, 0); 1.1514 + 1.1515 + NS_ENSURE_SUCCESS(result, result); 1.1516 + } 1.1517 + 1.1518 + 1.1519 + LOCK_DOC(this); 1.1520 + 1.1521 + result = editor->BeginTransaction(); 1.1522 + 1.1523 + if (NS_FAILED(result)) 1.1524 + { 1.1525 + UNLOCK_DOC(this); 1.1526 + return result; 1.1527 + } 1.1528 + 1.1529 + nsCOMPtr<nsIPlaintextEditor> textEditor (do_QueryInterface(editor, &result)); 1.1530 + if (textEditor) 1.1531 + result = textEditor->InsertText(*aText); 1.1532 + 1.1533 + if (NS_FAILED(result)) 1.1534 + { 1.1535 + editor->EndTransaction(); 1.1536 + UNLOCK_DOC(this); 1.1537 + return result; 1.1538 + } 1.1539 + 1.1540 + //**** KDEBUG **** 1.1541 + // printf("\n---- Before Insert\n"); 1.1542 + // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.1543 + // PrintOffsetTable(); 1.1544 + //**** KDEBUG **** 1.1545 + 1.1546 + int32_t strLength = aText->Length(); 1.1547 + uint32_t i; 1.1548 + 1.1549 + nsCOMPtr<nsISelection> selection; 1.1550 + OffsetEntry *itEntry; 1.1551 + OffsetEntry *entry = mOffsetTable[mSelStartIndex]; 1.1552 + void *node = entry->mNode; 1.1553 + 1.1554 + NS_ASSERTION((entry->mIsValid), "Invalid insertion point!"); 1.1555 + 1.1556 + if (entry->mStrOffset == mSelStartOffset) 1.1557 + { 1.1558 + if (entry->mIsInsertedText) 1.1559 + { 1.1560 + // If the caret is in an inserted text offset entry, 1.1561 + // we simply insert the text at the end of the entry. 1.1562 + 1.1563 + entry->mLength += strLength; 1.1564 + } 1.1565 + else 1.1566 + { 1.1567 + // Insert an inserted text offset entry before the current 1.1568 + // entry! 1.1569 + 1.1570 + itEntry = new OffsetEntry(entry->mNode, entry->mStrOffset, strLength); 1.1571 + 1.1572 + if (!itEntry) 1.1573 + { 1.1574 + editor->EndTransaction(); 1.1575 + UNLOCK_DOC(this); 1.1576 + return NS_ERROR_OUT_OF_MEMORY; 1.1577 + } 1.1578 + 1.1579 + itEntry->mIsInsertedText = true; 1.1580 + itEntry->mNodeOffset = entry->mNodeOffset; 1.1581 + 1.1582 + if (!mOffsetTable.InsertElementAt(mSelStartIndex, itEntry)) 1.1583 + { 1.1584 + editor->EndTransaction(); 1.1585 + UNLOCK_DOC(this); 1.1586 + return NS_ERROR_FAILURE; 1.1587 + } 1.1588 + } 1.1589 + } 1.1590 + else if ((entry->mStrOffset + entry->mLength) == mSelStartOffset) 1.1591 + { 1.1592 + // We are inserting text at the end of the current offset entry. 1.1593 + // Look at the next valid entry in the table. If it's an inserted 1.1594 + // text entry, add to its length and adjust its node offset. If 1.1595 + // it isn't, add a new inserted text entry. 1.1596 + 1.1597 + i = mSelStartIndex + 1; 1.1598 + itEntry = 0; 1.1599 + 1.1600 + if (mOffsetTable.Length() > i) 1.1601 + { 1.1602 + itEntry = mOffsetTable[i]; 1.1603 + 1.1604 + if (!itEntry) 1.1605 + { 1.1606 + editor->EndTransaction(); 1.1607 + UNLOCK_DOC(this); 1.1608 + return NS_ERROR_FAILURE; 1.1609 + } 1.1610 + 1.1611 + // Check if the entry is a match. If it isn't, set 1.1612 + // iEntry to zero. 1.1613 + 1.1614 + if (!itEntry->mIsInsertedText || itEntry->mStrOffset != mSelStartOffset) 1.1615 + itEntry = 0; 1.1616 + } 1.1617 + 1.1618 + if (!itEntry) 1.1619 + { 1.1620 + // We didn't find an inserted text offset entry, so 1.1621 + // create one. 1.1622 + 1.1623 + itEntry = new OffsetEntry(entry->mNode, mSelStartOffset, 0); 1.1624 + 1.1625 + if (!itEntry) 1.1626 + { 1.1627 + editor->EndTransaction(); 1.1628 + UNLOCK_DOC(this); 1.1629 + return NS_ERROR_OUT_OF_MEMORY; 1.1630 + } 1.1631 + 1.1632 + itEntry->mNodeOffset = entry->mNodeOffset + entry->mLength; 1.1633 + itEntry->mIsInsertedText = true; 1.1634 + 1.1635 + if (!mOffsetTable.InsertElementAt(i, itEntry)) 1.1636 + { 1.1637 + delete itEntry; 1.1638 + return NS_ERROR_FAILURE; 1.1639 + } 1.1640 + } 1.1641 + 1.1642 + // We have a valid inserted text offset entry. Update its 1.1643 + // length, adjust the selection indexes, and make sure the 1.1644 + // caret is properly placed! 1.1645 + 1.1646 + itEntry->mLength += strLength; 1.1647 + 1.1648 + mSelStartIndex = mSelEndIndex = i; 1.1649 + 1.1650 + result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); 1.1651 + 1.1652 + if (NS_FAILED(result)) 1.1653 + { 1.1654 + editor->EndTransaction(); 1.1655 + UNLOCK_DOC(this); 1.1656 + return result; 1.1657 + } 1.1658 + 1.1659 + result = selection->Collapse(itEntry->mNode, itEntry->mNodeOffset + itEntry->mLength); 1.1660 + 1.1661 + if (NS_FAILED(result)) 1.1662 + { 1.1663 + editor->EndTransaction(); 1.1664 + UNLOCK_DOC(this); 1.1665 + return result; 1.1666 + } 1.1667 + } 1.1668 + else if ((entry->mStrOffset + entry->mLength) > mSelStartOffset) 1.1669 + { 1.1670 + // We are inserting text into the middle of the current offset entry. 1.1671 + // split the current entry into two parts, then insert an inserted text 1.1672 + // entry between them! 1.1673 + 1.1674 + i = entry->mLength - (mSelStartOffset - entry->mStrOffset); 1.1675 + 1.1676 + result = SplitOffsetEntry(mSelStartIndex, i); 1.1677 + 1.1678 + if (NS_FAILED(result)) 1.1679 + { 1.1680 + editor->EndTransaction(); 1.1681 + UNLOCK_DOC(this); 1.1682 + return result; 1.1683 + } 1.1684 + 1.1685 + itEntry = new OffsetEntry(entry->mNode, mSelStartOffset, strLength); 1.1686 + 1.1687 + if (!itEntry) 1.1688 + { 1.1689 + editor->EndTransaction(); 1.1690 + UNLOCK_DOC(this); 1.1691 + return NS_ERROR_OUT_OF_MEMORY; 1.1692 + } 1.1693 + 1.1694 + itEntry->mIsInsertedText = true; 1.1695 + itEntry->mNodeOffset = entry->mNodeOffset + entry->mLength; 1.1696 + 1.1697 + if (!mOffsetTable.InsertElementAt(mSelStartIndex + 1, itEntry)) 1.1698 + { 1.1699 + editor->EndTransaction(); 1.1700 + UNLOCK_DOC(this); 1.1701 + return NS_ERROR_FAILURE; 1.1702 + } 1.1703 + 1.1704 + mSelEndIndex = ++mSelStartIndex; 1.1705 + } 1.1706 + 1.1707 + // We've just finished inserting an inserted text offset entry. 1.1708 + // update all entries with the same mNode pointer that follow 1.1709 + // it in the table! 1.1710 + 1.1711 + for (i = mSelStartIndex + 1; i < mOffsetTable.Length(); i++) 1.1712 + { 1.1713 + entry = mOffsetTable[i]; 1.1714 + 1.1715 + if (entry->mNode == node) 1.1716 + { 1.1717 + if (entry->mIsValid) 1.1718 + entry->mNodeOffset += strLength; 1.1719 + } 1.1720 + else 1.1721 + break; 1.1722 + } 1.1723 + 1.1724 + //**** KDEBUG **** 1.1725 + // printf("\n---- After Insert\n"); 1.1726 + // printf("Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.1727 + // PrintOffsetTable(); 1.1728 + //**** KDEBUG **** 1.1729 + 1.1730 + if (!collapsedSelection) 1.1731 + { 1.1732 + result = SetSelection(savedSelOffset, savedSelLength); 1.1733 + 1.1734 + if (NS_FAILED(result)) 1.1735 + { 1.1736 + editor->EndTransaction(); 1.1737 + UNLOCK_DOC(this); 1.1738 + return result; 1.1739 + } 1.1740 + 1.1741 + result = DeleteSelection(); 1.1742 + 1.1743 + if (NS_FAILED(result)) 1.1744 + { 1.1745 + editor->EndTransaction(); 1.1746 + UNLOCK_DOC(this); 1.1747 + return result; 1.1748 + } 1.1749 + } 1.1750 + 1.1751 + result = editor->EndTransaction(); 1.1752 + 1.1753 + UNLOCK_DOC(this); 1.1754 + 1.1755 + return result; 1.1756 +} 1.1757 + 1.1758 +NS_IMETHODIMP 1.1759 +nsTextServicesDocument::DidInsertNode(nsIDOMNode *aNode, 1.1760 + nsIDOMNode *aParent, 1.1761 + int32_t aPosition, 1.1762 + nsresult aResult) 1.1763 +{ 1.1764 + return NS_OK; 1.1765 +} 1.1766 + 1.1767 +NS_IMETHODIMP 1.1768 +nsTextServicesDocument::DidDeleteNode(nsIDOMNode *aChild, nsresult aResult) 1.1769 +{ 1.1770 + NS_ENSURE_SUCCESS(aResult, NS_OK); 1.1771 + 1.1772 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.1773 + 1.1774 + //**** KDEBUG **** 1.1775 + // printf("** DeleteNode: 0x%.8x\n", aChild); 1.1776 + // fflush(stdout); 1.1777 + //**** KDEBUG **** 1.1778 + 1.1779 + LOCK_DOC(this); 1.1780 + 1.1781 + int32_t nodeIndex = 0; 1.1782 + bool hasEntry = false; 1.1783 + OffsetEntry *entry; 1.1784 + 1.1785 + nsresult result = NodeHasOffsetEntry(&mOffsetTable, aChild, &hasEntry, &nodeIndex); 1.1786 + 1.1787 + if (NS_FAILED(result)) 1.1788 + { 1.1789 + UNLOCK_DOC(this); 1.1790 + return result; 1.1791 + } 1.1792 + 1.1793 + if (!hasEntry) 1.1794 + { 1.1795 + // It's okay if the node isn't in the offset table, the 1.1796 + // editor could be cleaning house. 1.1797 + 1.1798 + UNLOCK_DOC(this); 1.1799 + return NS_OK; 1.1800 + } 1.1801 + 1.1802 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(mIterator->GetCurrentNode()); 1.1803 + 1.1804 + if (node && node == aChild && 1.1805 + mIteratorStatus != nsTextServicesDocument::eIsDone) 1.1806 + { 1.1807 + // XXX: This should never really happen because 1.1808 + // AdjustContentIterator() should have been called prior 1.1809 + // to the delete to try and position the iterator on the 1.1810 + // next valid text node in the offset table, and if there 1.1811 + // wasn't a next, it would've set mIteratorStatus to eIsDone. 1.1812 + 1.1813 + NS_ERROR("DeleteNode called for current iterator node."); 1.1814 + } 1.1815 + 1.1816 + int32_t tcount = mOffsetTable.Length(); 1.1817 + 1.1818 + while (nodeIndex < tcount) 1.1819 + { 1.1820 + entry = mOffsetTable[nodeIndex]; 1.1821 + 1.1822 + if (!entry) 1.1823 + { 1.1824 + UNLOCK_DOC(this); 1.1825 + return NS_ERROR_FAILURE; 1.1826 + } 1.1827 + 1.1828 + if (entry->mNode == aChild) 1.1829 + { 1.1830 + entry->mIsValid = false; 1.1831 + } 1.1832 + 1.1833 + nodeIndex++; 1.1834 + } 1.1835 + 1.1836 + UNLOCK_DOC(this); 1.1837 + 1.1838 + return NS_OK; 1.1839 +} 1.1840 + 1.1841 +NS_IMETHODIMP 1.1842 +nsTextServicesDocument::DidSplitNode(nsIDOMNode *aExistingRightNode, 1.1843 + int32_t aOffset, 1.1844 + nsIDOMNode *aNewLeftNode, 1.1845 + nsresult aResult) 1.1846 +{ 1.1847 + //**** KDEBUG **** 1.1848 + // printf("** SplitNode: 0x%.8x %d 0x%.8x\n", aExistingRightNode, aOffset, aNewLeftNode); 1.1849 + // fflush(stdout); 1.1850 + //**** KDEBUG **** 1.1851 + return NS_OK; 1.1852 +} 1.1853 + 1.1854 +NS_IMETHODIMP 1.1855 +nsTextServicesDocument::DidJoinNodes(nsIDOMNode *aLeftNode, 1.1856 + nsIDOMNode *aRightNode, 1.1857 + nsIDOMNode *aParent, 1.1858 + nsresult aResult) 1.1859 +{ 1.1860 + NS_ENSURE_SUCCESS(aResult, NS_OK); 1.1861 + 1.1862 + int32_t i; 1.1863 + uint16_t type; 1.1864 + nsresult result; 1.1865 + 1.1866 + //**** KDEBUG **** 1.1867 + // printf("** JoinNodes: 0x%.8x 0x%.8x 0x%.8x\n", aLeftNode, aRightNode, aParent); 1.1868 + // fflush(stdout); 1.1869 + //**** KDEBUG **** 1.1870 + 1.1871 + // Make sure that both nodes are text nodes -- otherwise we don't care. 1.1872 + 1.1873 + result = aLeftNode->GetNodeType(&type); 1.1874 + NS_ENSURE_SUCCESS(result, NS_OK); 1.1875 + if (nsIDOMNode::TEXT_NODE != type) { 1.1876 + return NS_OK; 1.1877 + } 1.1878 + 1.1879 + result = aRightNode->GetNodeType(&type); 1.1880 + NS_ENSURE_SUCCESS(result, NS_OK); 1.1881 + if (nsIDOMNode::TEXT_NODE != type) { 1.1882 + return NS_OK; 1.1883 + } 1.1884 + 1.1885 + // Note: The editor merges the contents of the left node into the 1.1886 + // contents of the right. 1.1887 + 1.1888 + int32_t leftIndex = 0; 1.1889 + int32_t rightIndex = 0; 1.1890 + bool leftHasEntry = false; 1.1891 + bool rightHasEntry = false; 1.1892 + 1.1893 + result = NodeHasOffsetEntry(&mOffsetTable, aLeftNode, &leftHasEntry, &leftIndex); 1.1894 + 1.1895 + NS_ENSURE_SUCCESS(result, result); 1.1896 + 1.1897 + if (!leftHasEntry) 1.1898 + { 1.1899 + // It's okay if the node isn't in the offset table, the 1.1900 + // editor could be cleaning house. 1.1901 + return NS_OK; 1.1902 + } 1.1903 + 1.1904 + result = NodeHasOffsetEntry(&mOffsetTable, aRightNode, &rightHasEntry, &rightIndex); 1.1905 + 1.1906 + NS_ENSURE_SUCCESS(result, result); 1.1907 + 1.1908 + if (!rightHasEntry) 1.1909 + { 1.1910 + // It's okay if the node isn't in the offset table, the 1.1911 + // editor could be cleaning house. 1.1912 + return NS_OK; 1.1913 + } 1.1914 + 1.1915 + NS_ASSERTION(leftIndex < rightIndex, "Indexes out of order."); 1.1916 + 1.1917 + if (leftIndex > rightIndex) 1.1918 + { 1.1919 + // Don't know how to handle this situation. 1.1920 + return NS_ERROR_FAILURE; 1.1921 + } 1.1922 + 1.1923 + LOCK_DOC(this); 1.1924 + 1.1925 + OffsetEntry *entry = mOffsetTable[rightIndex]; 1.1926 + NS_ASSERTION(entry->mNodeOffset == 0, "Unexpected offset value for rightIndex."); 1.1927 + 1.1928 + // Run through the table and change all entries referring to 1.1929 + // the left node so that they now refer to the right node: 1.1930 + 1.1931 + nsAutoString str; 1.1932 + result = aLeftNode->GetNodeValue(str); 1.1933 + int32_t nodeLength = str.Length(); 1.1934 + 1.1935 + for (i = leftIndex; i < rightIndex; i++) 1.1936 + { 1.1937 + entry = mOffsetTable[i]; 1.1938 + 1.1939 + if (entry->mNode == aLeftNode) 1.1940 + { 1.1941 + if (entry->mIsValid) 1.1942 + entry->mNode = aRightNode; 1.1943 + } 1.1944 + else 1.1945 + break; 1.1946 + } 1.1947 + 1.1948 + // Run through the table and adjust the node offsets 1.1949 + // for all entries referring to the right node. 1.1950 + 1.1951 + for (i = rightIndex; i < int32_t(mOffsetTable.Length()); i++) 1.1952 + { 1.1953 + entry = mOffsetTable[i]; 1.1954 + 1.1955 + if (entry->mNode == aRightNode) 1.1956 + { 1.1957 + if (entry->mIsValid) 1.1958 + entry->mNodeOffset += nodeLength; 1.1959 + } 1.1960 + else 1.1961 + break; 1.1962 + } 1.1963 + 1.1964 + // Now check to see if the iterator is pointing to the 1.1965 + // left node. If it is, make it point to the right node! 1.1966 + 1.1967 + nsCOMPtr<nsIContent> leftContent = do_QueryInterface(aLeftNode); 1.1968 + nsCOMPtr<nsIContent> rightContent = do_QueryInterface(aRightNode); 1.1969 + 1.1970 + if (!leftContent || !rightContent) 1.1971 + { 1.1972 + UNLOCK_DOC(this); 1.1973 + return NS_ERROR_FAILURE; 1.1974 + } 1.1975 + 1.1976 + if (mIterator->GetCurrentNode() == leftContent) 1.1977 + result = mIterator->PositionAt(rightContent); 1.1978 + 1.1979 + UNLOCK_DOC(this); 1.1980 + 1.1981 + return NS_OK; 1.1982 +} 1.1983 + 1.1984 +nsresult 1.1985 +nsTextServicesDocument::CreateContentIterator(nsIDOMRange *aRange, nsIContentIterator **aIterator) 1.1986 +{ 1.1987 + nsresult result; 1.1988 + 1.1989 + NS_ENSURE_TRUE(aRange && aIterator, NS_ERROR_NULL_POINTER); 1.1990 + 1.1991 + *aIterator = 0; 1.1992 + 1.1993 + // Create a nsFilteredContentIterator 1.1994 + // This class wraps the ContentIterator in order to give itself a chance 1.1995 + // to filter out certain content nodes 1.1996 + nsFilteredContentIterator* filter = new nsFilteredContentIterator(mTxtSvcFilter); 1.1997 + *aIterator = static_cast<nsIContentIterator *>(filter); 1.1998 + if (*aIterator) { 1.1999 + NS_IF_ADDREF(*aIterator); 1.2000 + result = filter ? NS_OK : NS_ERROR_FAILURE; 1.2001 + } else { 1.2002 + delete filter; 1.2003 + result = NS_ERROR_FAILURE; 1.2004 + } 1.2005 + NS_ENSURE_SUCCESS(result, result); 1.2006 + 1.2007 + NS_ENSURE_TRUE(*aIterator, NS_ERROR_NULL_POINTER); 1.2008 + 1.2009 + result = (*aIterator)->Init(aRange); 1.2010 + 1.2011 + if (NS_FAILED(result)) 1.2012 + { 1.2013 + NS_RELEASE((*aIterator)); 1.2014 + *aIterator = 0; 1.2015 + return result; 1.2016 + } 1.2017 + 1.2018 + return NS_OK; 1.2019 +} 1.2020 + 1.2021 +nsresult 1.2022 +nsTextServicesDocument::GetDocumentContentRootNode(nsIDOMNode **aNode) 1.2023 +{ 1.2024 + nsresult result; 1.2025 + 1.2026 + NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER); 1.2027 + 1.2028 + *aNode = 0; 1.2029 + 1.2030 + NS_ENSURE_TRUE(mDOMDocument, NS_ERROR_FAILURE); 1.2031 + 1.2032 + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDOMDocument); 1.2033 + 1.2034 + if (htmlDoc) 1.2035 + { 1.2036 + // For HTML documents, the content root node is the body. 1.2037 + 1.2038 + nsCOMPtr<nsIDOMHTMLElement> bodyElement; 1.2039 + 1.2040 + result = htmlDoc->GetBody(getter_AddRefs(bodyElement)); 1.2041 + 1.2042 + NS_ENSURE_SUCCESS(result, result); 1.2043 + 1.2044 + NS_ENSURE_TRUE(bodyElement, NS_ERROR_FAILURE); 1.2045 + 1.2046 + result = bodyElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode); 1.2047 + } 1.2048 + else 1.2049 + { 1.2050 + // For non-HTML documents, the content root node will be the document element. 1.2051 + 1.2052 + nsCOMPtr<nsIDOMElement> docElement; 1.2053 + 1.2054 + result = mDOMDocument->GetDocumentElement(getter_AddRefs(docElement)); 1.2055 + 1.2056 + NS_ENSURE_SUCCESS(result, result); 1.2057 + 1.2058 + NS_ENSURE_TRUE(docElement, NS_ERROR_FAILURE); 1.2059 + 1.2060 + result = docElement->QueryInterface(NS_GET_IID(nsIDOMNode), (void **)aNode); 1.2061 + } 1.2062 + 1.2063 + return result; 1.2064 +} 1.2065 + 1.2066 +nsresult 1.2067 +nsTextServicesDocument::CreateDocumentContentRange(nsIDOMRange **aRange) 1.2068 +{ 1.2069 + *aRange = nullptr; 1.2070 + 1.2071 + nsCOMPtr<nsIDOMNode> node; 1.2072 + nsresult rv = GetDocumentContentRootNode(getter_AddRefs(node)); 1.2073 + NS_ENSURE_SUCCESS(rv, rv); 1.2074 + NS_ENSURE_TRUE(node, NS_ERROR_NULL_POINTER); 1.2075 + 1.2076 + nsCOMPtr<nsINode> nativeNode = do_QueryInterface(node); 1.2077 + NS_ENSURE_STATE(nativeNode); 1.2078 + 1.2079 + nsRefPtr<nsRange> range = new nsRange(nativeNode); 1.2080 + 1.2081 + rv = range->SelectNodeContents(node); 1.2082 + NS_ENSURE_SUCCESS(rv, rv); 1.2083 + 1.2084 + range.forget(aRange); 1.2085 + return NS_OK; 1.2086 +} 1.2087 + 1.2088 +nsresult 1.2089 +nsTextServicesDocument::CreateDocumentContentRootToNodeOffsetRange(nsIDOMNode *aParent, int32_t aOffset, bool aToStart, nsIDOMRange **aRange) 1.2090 +{ 1.2091 + NS_ENSURE_TRUE(aParent && aRange, NS_ERROR_NULL_POINTER); 1.2092 + 1.2093 + *aRange = 0; 1.2094 + 1.2095 + NS_ASSERTION(aOffset >= 0, "Invalid offset!"); 1.2096 + 1.2097 + if (aOffset < 0) 1.2098 + return NS_ERROR_FAILURE; 1.2099 + 1.2100 + nsCOMPtr<nsIDOMNode> bodyNode; 1.2101 + nsresult rv = GetDocumentContentRootNode(getter_AddRefs(bodyNode)); 1.2102 + NS_ENSURE_SUCCESS(rv, rv); 1.2103 + NS_ENSURE_TRUE(bodyNode, NS_ERROR_NULL_POINTER); 1.2104 + 1.2105 + nsCOMPtr<nsIDOMNode> startNode; 1.2106 + nsCOMPtr<nsIDOMNode> endNode; 1.2107 + int32_t startOffset, endOffset; 1.2108 + 1.2109 + if (aToStart) { 1.2110 + // The range should begin at the start of the document 1.2111 + // and extend up until (aParent, aOffset). 1.2112 + 1.2113 + startNode = bodyNode; 1.2114 + startOffset = 0; 1.2115 + endNode = aParent; 1.2116 + endOffset = aOffset; 1.2117 + } else { 1.2118 + // The range should begin at (aParent, aOffset) and 1.2119 + // extend to the end of the document. 1.2120 + 1.2121 + startNode = aParent; 1.2122 + startOffset = aOffset; 1.2123 + endNode = bodyNode; 1.2124 + 1.2125 + nsCOMPtr<nsINode> body = do_QueryInterface(bodyNode); 1.2126 + endOffset = body ? int32_t(body->GetChildCount()) : 0; 1.2127 + } 1.2128 + 1.2129 + return nsRange::CreateRange(startNode, startOffset, endNode, endOffset, 1.2130 + aRange); 1.2131 +} 1.2132 + 1.2133 +nsresult 1.2134 +nsTextServicesDocument::CreateDocumentContentIterator(nsIContentIterator **aIterator) 1.2135 +{ 1.2136 + nsresult result; 1.2137 + 1.2138 + NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER); 1.2139 + 1.2140 + nsCOMPtr<nsIDOMRange> range; 1.2141 + 1.2142 + result = CreateDocumentContentRange(getter_AddRefs(range)); 1.2143 + 1.2144 + NS_ENSURE_SUCCESS(result, result); 1.2145 + 1.2146 + result = CreateContentIterator(range, aIterator); 1.2147 + 1.2148 + return result; 1.2149 +} 1.2150 + 1.2151 +nsresult 1.2152 +nsTextServicesDocument::AdjustContentIterator() 1.2153 +{ 1.2154 + nsresult result = NS_OK; 1.2155 + 1.2156 + NS_ENSURE_TRUE(mIterator, NS_ERROR_FAILURE); 1.2157 + 1.2158 + nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mIterator->GetCurrentNode())); 1.2159 + 1.2160 + NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); 1.2161 + 1.2162 + nsIDOMNode *nodePtr = node.get(); 1.2163 + int32_t tcount = mOffsetTable.Length(); 1.2164 + 1.2165 + nsIDOMNode *prevValidNode = 0; 1.2166 + nsIDOMNode *nextValidNode = 0; 1.2167 + bool foundEntry = false; 1.2168 + OffsetEntry *entry; 1.2169 + 1.2170 + for (int32_t i = 0; i < tcount && !nextValidNode; i++) 1.2171 + { 1.2172 + entry = mOffsetTable[i]; 1.2173 + 1.2174 + NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); 1.2175 + 1.2176 + if (entry->mNode == nodePtr) 1.2177 + { 1.2178 + if (entry->mIsValid) 1.2179 + { 1.2180 + // The iterator is still pointing to something valid! 1.2181 + // Do nothing! 1.2182 + 1.2183 + return NS_OK; 1.2184 + } 1.2185 + else 1.2186 + { 1.2187 + // We found an invalid entry that points to 1.2188 + // the current iterator node. Stop looking for 1.2189 + // a previous valid node! 1.2190 + 1.2191 + foundEntry = true; 1.2192 + } 1.2193 + } 1.2194 + 1.2195 + if (entry->mIsValid) 1.2196 + { 1.2197 + if (!foundEntry) 1.2198 + prevValidNode = entry->mNode; 1.2199 + else 1.2200 + nextValidNode = entry->mNode; 1.2201 + } 1.2202 + } 1.2203 + 1.2204 + nsCOMPtr<nsIContent> content; 1.2205 + 1.2206 + if (prevValidNode) 1.2207 + content = do_QueryInterface(prevValidNode); 1.2208 + else if (nextValidNode) 1.2209 + content = do_QueryInterface(nextValidNode); 1.2210 + 1.2211 + if (content) 1.2212 + { 1.2213 + result = mIterator->PositionAt(content); 1.2214 + 1.2215 + if (NS_FAILED(result)) 1.2216 + mIteratorStatus = eIsDone; 1.2217 + else 1.2218 + mIteratorStatus = eValid; 1.2219 + 1.2220 + return result; 1.2221 + } 1.2222 + 1.2223 + // If we get here, there aren't any valid entries 1.2224 + // in the offset table! Try to position the iterator 1.2225 + // on the next text block first, then previous if 1.2226 + // one doesn't exist! 1.2227 + 1.2228 + if (mNextTextBlock) 1.2229 + { 1.2230 + result = mIterator->PositionAt(mNextTextBlock); 1.2231 + 1.2232 + if (NS_FAILED(result)) 1.2233 + { 1.2234 + mIteratorStatus = eIsDone; 1.2235 + return result; 1.2236 + } 1.2237 + 1.2238 + mIteratorStatus = eNext; 1.2239 + } 1.2240 + else if (mPrevTextBlock) 1.2241 + { 1.2242 + result = mIterator->PositionAt(mPrevTextBlock); 1.2243 + 1.2244 + if (NS_FAILED(result)) 1.2245 + { 1.2246 + mIteratorStatus = eIsDone; 1.2247 + return result; 1.2248 + } 1.2249 + 1.2250 + mIteratorStatus = ePrev; 1.2251 + } 1.2252 + else 1.2253 + mIteratorStatus = eIsDone; 1.2254 + 1.2255 + return NS_OK; 1.2256 +} 1.2257 + 1.2258 +bool 1.2259 +nsTextServicesDocument::DidSkip(nsIContentIterator* aFilteredIter) 1.2260 +{ 1.2261 + // We can assume here that the Iterator is a nsFilteredContentIterator because 1.2262 + // all the iterator are created in CreateContentIterator which create a 1.2263 + // nsFilteredContentIterator 1.2264 + // So if the iterator bailed on one of the "filtered" content nodes then we 1.2265 + // consider that to be a block and bail with true 1.2266 + if (aFilteredIter) { 1.2267 + nsFilteredContentIterator* filter = static_cast<nsFilteredContentIterator *>(aFilteredIter); 1.2268 + if (filter && filter->DidSkip()) { 1.2269 + return true; 1.2270 + } 1.2271 + } 1.2272 + return false; 1.2273 +} 1.2274 + 1.2275 +void 1.2276 +nsTextServicesDocument::ClearDidSkip(nsIContentIterator* aFilteredIter) 1.2277 +{ 1.2278 + // Clear filter's skip flag 1.2279 + if (aFilteredIter) { 1.2280 + nsFilteredContentIterator* filter = static_cast<nsFilteredContentIterator *>(aFilteredIter); 1.2281 + filter->ClearDidSkip(); 1.2282 + } 1.2283 +} 1.2284 + 1.2285 +bool 1.2286 +nsTextServicesDocument::IsBlockNode(nsIContent *aContent) 1.2287 +{ 1.2288 + if (!aContent) { 1.2289 + NS_ERROR("How did a null pointer get passed to IsBlockNode?"); 1.2290 + return false; 1.2291 + } 1.2292 + 1.2293 + nsIAtom *atom = aContent->Tag(); 1.2294 + 1.2295 + return (sAAtom != atom && 1.2296 + sAddressAtom != atom && 1.2297 + sBigAtom != atom && 1.2298 + sBAtom != atom && 1.2299 + sCiteAtom != atom && 1.2300 + sCodeAtom != atom && 1.2301 + sDfnAtom != atom && 1.2302 + sEmAtom != atom && 1.2303 + sFontAtom != atom && 1.2304 + sIAtom != atom && 1.2305 + sKbdAtom != atom && 1.2306 + sKeygenAtom != atom && 1.2307 + sNobrAtom != atom && 1.2308 + sSAtom != atom && 1.2309 + sSampAtom != atom && 1.2310 + sSmallAtom != atom && 1.2311 + sSpacerAtom != atom && 1.2312 + sSpanAtom != atom && 1.2313 + sStrikeAtom != atom && 1.2314 + sStrongAtom != atom && 1.2315 + sSubAtom != atom && 1.2316 + sSupAtom != atom && 1.2317 + sTtAtom != atom && 1.2318 + sUAtom != atom && 1.2319 + sVarAtom != atom && 1.2320 + sWbrAtom != atom); 1.2321 +} 1.2322 + 1.2323 +bool 1.2324 +nsTextServicesDocument::HasSameBlockNodeParent(nsIContent *aContent1, nsIContent *aContent2) 1.2325 +{ 1.2326 + nsIContent* p1 = aContent1->GetParent(); 1.2327 + nsIContent* p2 = aContent2->GetParent(); 1.2328 + 1.2329 + // Quick test: 1.2330 + 1.2331 + if (p1 == p2) 1.2332 + return true; 1.2333 + 1.2334 + // Walk up the parent hierarchy looking for closest block boundary node: 1.2335 + 1.2336 + while (p1 && !IsBlockNode(p1)) 1.2337 + { 1.2338 + p1 = p1->GetParent(); 1.2339 + } 1.2340 + 1.2341 + while (p2 && !IsBlockNode(p2)) 1.2342 + { 1.2343 + p2 = p2->GetParent(); 1.2344 + } 1.2345 + 1.2346 + return p1 == p2; 1.2347 +} 1.2348 + 1.2349 +bool 1.2350 +nsTextServicesDocument::IsTextNode(nsIContent *aContent) 1.2351 +{ 1.2352 + NS_ENSURE_TRUE(aContent, false); 1.2353 + return nsIDOMNode::TEXT_NODE == aContent->NodeType(); 1.2354 +} 1.2355 + 1.2356 +bool 1.2357 +nsTextServicesDocument::IsTextNode(nsIDOMNode *aNode) 1.2358 +{ 1.2359 + NS_ENSURE_TRUE(aNode, false); 1.2360 + 1.2361 + nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); 1.2362 + return IsTextNode(content); 1.2363 +} 1.2364 + 1.2365 +nsresult 1.2366 +nsTextServicesDocument::SetSelectionInternal(int32_t aOffset, int32_t aLength, bool aDoUpdate) 1.2367 +{ 1.2368 + nsresult result = NS_OK; 1.2369 + 1.2370 + NS_ENSURE_TRUE(mSelCon && aOffset >= 0 && aLength >= 0, NS_ERROR_FAILURE); 1.2371 + 1.2372 + nsIDOMNode *sNode = 0, *eNode = 0; 1.2373 + int32_t i, sOffset = 0, eOffset = 0; 1.2374 + OffsetEntry *entry; 1.2375 + 1.2376 + // Find start of selection in node offset terms: 1.2377 + 1.2378 + for (i = 0; !sNode && i < int32_t(mOffsetTable.Length()); i++) 1.2379 + { 1.2380 + entry = mOffsetTable[i]; 1.2381 + if (entry->mIsValid) 1.2382 + { 1.2383 + if (entry->mIsInsertedText) 1.2384 + { 1.2385 + // Caret can only be placed at the end of an 1.2386 + // inserted text offset entry, if the offsets 1.2387 + // match exactly! 1.2388 + 1.2389 + if (entry->mStrOffset == aOffset) 1.2390 + { 1.2391 + sNode = entry->mNode; 1.2392 + sOffset = entry->mNodeOffset + entry->mLength; 1.2393 + } 1.2394 + } 1.2395 + else if (aOffset >= entry->mStrOffset) 1.2396 + { 1.2397 + bool foundEntry = false; 1.2398 + int32_t strEndOffset = entry->mStrOffset + entry->mLength; 1.2399 + 1.2400 + if (aOffset < strEndOffset) 1.2401 + foundEntry = true; 1.2402 + else if (aOffset == strEndOffset) 1.2403 + { 1.2404 + // Peek after this entry to see if we have any 1.2405 + // inserted text entries belonging to the same 1.2406 + // entry->mNode. If so, we have to place the selection 1.2407 + // after it! 1.2408 + 1.2409 + if ((i+1) < int32_t(mOffsetTable.Length())) 1.2410 + { 1.2411 + OffsetEntry *nextEntry = mOffsetTable[i+1]; 1.2412 + 1.2413 + if (!nextEntry->mIsValid || nextEntry->mStrOffset != aOffset) 1.2414 + { 1.2415 + // Next offset entry isn't an exact match, so we'll 1.2416 + // just use the current entry. 1.2417 + foundEntry = true; 1.2418 + } 1.2419 + } 1.2420 + } 1.2421 + 1.2422 + if (foundEntry) 1.2423 + { 1.2424 + sNode = entry->mNode; 1.2425 + sOffset = entry->mNodeOffset + aOffset - entry->mStrOffset; 1.2426 + } 1.2427 + } 1.2428 + 1.2429 + if (sNode) 1.2430 + { 1.2431 + mSelStartIndex = i; 1.2432 + mSelStartOffset = aOffset; 1.2433 + } 1.2434 + } 1.2435 + } 1.2436 + 1.2437 + NS_ENSURE_TRUE(sNode, NS_ERROR_FAILURE); 1.2438 + 1.2439 + // XXX: If we ever get a SetSelection() method in nsIEditor, we should 1.2440 + // use it. 1.2441 + 1.2442 + nsCOMPtr<nsISelection> selection; 1.2443 + 1.2444 + if (aDoUpdate) 1.2445 + { 1.2446 + result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); 1.2447 + 1.2448 + NS_ENSURE_SUCCESS(result, result); 1.2449 + 1.2450 + result = selection->Collapse(sNode, sOffset); 1.2451 + 1.2452 + NS_ENSURE_SUCCESS(result, result); 1.2453 + } 1.2454 + 1.2455 + if (aLength <= 0) 1.2456 + { 1.2457 + // We have a collapsed selection. (Caret) 1.2458 + 1.2459 + mSelEndIndex = mSelStartIndex; 1.2460 + mSelEndOffset = mSelStartOffset; 1.2461 + 1.2462 + //**** KDEBUG **** 1.2463 + // printf("\n* Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.2464 + //**** KDEBUG **** 1.2465 + 1.2466 + return NS_OK; 1.2467 + } 1.2468 + 1.2469 + // Find the end of the selection in node offset terms: 1.2470 + 1.2471 + int32_t endOffset = aOffset + aLength; 1.2472 + 1.2473 + for (i = mOffsetTable.Length() - 1; !eNode && i >= 0; i--) 1.2474 + { 1.2475 + entry = mOffsetTable[i]; 1.2476 + 1.2477 + if (entry->mIsValid) 1.2478 + { 1.2479 + if (entry->mIsInsertedText) 1.2480 + { 1.2481 + if (entry->mStrOffset == eOffset) 1.2482 + { 1.2483 + // If the selection ends on an inserted text offset entry, 1.2484 + // the selection includes the entire entry! 1.2485 + 1.2486 + eNode = entry->mNode; 1.2487 + eOffset = entry->mNodeOffset + entry->mLength; 1.2488 + } 1.2489 + } 1.2490 + else if (endOffset >= entry->mStrOffset && endOffset <= entry->mStrOffset + entry->mLength) 1.2491 + { 1.2492 + eNode = entry->mNode; 1.2493 + eOffset = entry->mNodeOffset + endOffset - entry->mStrOffset; 1.2494 + } 1.2495 + 1.2496 + if (eNode) 1.2497 + { 1.2498 + mSelEndIndex = i; 1.2499 + mSelEndOffset = endOffset; 1.2500 + } 1.2501 + } 1.2502 + } 1.2503 + 1.2504 + if (aDoUpdate && eNode) 1.2505 + { 1.2506 + result = selection->Extend(eNode, eOffset); 1.2507 + 1.2508 + NS_ENSURE_SUCCESS(result, result); 1.2509 + } 1.2510 + 1.2511 + //**** KDEBUG **** 1.2512 + // printf("\n * Sel: (%2d, %4d) (%2d, %4d)\n", mSelStartIndex, mSelStartOffset, mSelEndIndex, mSelEndOffset); 1.2513 + //**** KDEBUG **** 1.2514 + 1.2515 + return result; 1.2516 +} 1.2517 + 1.2518 +nsresult 1.2519 +nsTextServicesDocument::GetSelection(nsITextServicesDocument::TSDBlockSelectionStatus *aSelStatus, int32_t *aSelOffset, int32_t *aSelLength) 1.2520 +{ 1.2521 + nsresult result; 1.2522 + 1.2523 + NS_ENSURE_TRUE(aSelStatus && aSelOffset && aSelLength, NS_ERROR_NULL_POINTER); 1.2524 + 1.2525 + *aSelStatus = nsITextServicesDocument::eBlockNotFound; 1.2526 + *aSelOffset = -1; 1.2527 + *aSelLength = -1; 1.2528 + 1.2529 + NS_ENSURE_TRUE(mDOMDocument && mSelCon, NS_ERROR_FAILURE); 1.2530 + 1.2531 + if (mIteratorStatus == nsTextServicesDocument::eIsDone) 1.2532 + return NS_OK; 1.2533 + 1.2534 + nsCOMPtr<nsISelection> selection; 1.2535 + bool isCollapsed; 1.2536 + 1.2537 + result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); 1.2538 + 1.2539 + NS_ENSURE_SUCCESS(result, result); 1.2540 + 1.2541 + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); 1.2542 + 1.2543 + result = selection->GetIsCollapsed(&isCollapsed); 1.2544 + 1.2545 + NS_ENSURE_SUCCESS(result, result); 1.2546 + 1.2547 + // XXX: If we expose this method publicly, we need to 1.2548 + // add LOCK_DOC/UNLOCK_DOC calls! 1.2549 + 1.2550 + // LOCK_DOC(this); 1.2551 + 1.2552 + if (isCollapsed) 1.2553 + result = GetCollapsedSelection(aSelStatus, aSelOffset, aSelLength); 1.2554 + else 1.2555 + result = GetUncollapsedSelection(aSelStatus, aSelOffset, aSelLength); 1.2556 + 1.2557 + // UNLOCK_DOC(this); 1.2558 + 1.2559 + return result; 1.2560 +} 1.2561 + 1.2562 +nsresult 1.2563 +nsTextServicesDocument::GetCollapsedSelection(nsITextServicesDocument::TSDBlockSelectionStatus *aSelStatus, int32_t *aSelOffset, int32_t *aSelLength) 1.2564 +{ 1.2565 + nsCOMPtr<nsISelection> selection; 1.2566 + nsresult result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); 1.2567 + NS_ENSURE_SUCCESS(result, result); 1.2568 + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); 1.2569 + 1.2570 + // The calling function should have done the GetIsCollapsed() 1.2571 + // check already. Just assume it's collapsed! 1.2572 + *aSelStatus = nsITextServicesDocument::eBlockOutside; 1.2573 + *aSelOffset = *aSelLength = -1; 1.2574 + 1.2575 + int32_t tableCount = mOffsetTable.Length(); 1.2576 + 1.2577 + if (tableCount == 0) 1.2578 + return NS_OK; 1.2579 + 1.2580 + // Get pointers to the first and last offset entries 1.2581 + // in the table. 1.2582 + 1.2583 + OffsetEntry* eStart = mOffsetTable[0]; 1.2584 + OffsetEntry* eEnd; 1.2585 + if (tableCount > 1) 1.2586 + eEnd = mOffsetTable[tableCount - 1]; 1.2587 + else 1.2588 + eEnd = eStart; 1.2589 + 1.2590 + int32_t eStartOffset = eStart->mNodeOffset; 1.2591 + int32_t eEndOffset = eEnd->mNodeOffset + eEnd->mLength; 1.2592 + 1.2593 + nsCOMPtr<nsIDOMRange> range; 1.2594 + result = selection->GetRangeAt(0, getter_AddRefs(range)); 1.2595 + NS_ENSURE_SUCCESS(result, result); 1.2596 + 1.2597 + nsCOMPtr<nsIDOMNode> domParent; 1.2598 + result = range->GetStartContainer(getter_AddRefs(domParent)); 1.2599 + NS_ENSURE_SUCCESS(result, result); 1.2600 + 1.2601 + nsCOMPtr<nsINode> parent = do_QueryInterface(domParent); 1.2602 + MOZ_ASSERT(parent); 1.2603 + 1.2604 + int32_t offset; 1.2605 + result = range->GetStartOffset(&offset); 1.2606 + NS_ENSURE_SUCCESS(result, result); 1.2607 + 1.2608 + int32_t e1s1 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset, 1.2609 + domParent, offset); 1.2610 + int32_t e2s1 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset, 1.2611 + domParent, offset); 1.2612 + 1.2613 + if (e1s1 > 0 || e2s1 < 0) { 1.2614 + // We're done if the caret is outside the current text block. 1.2615 + return NS_OK; 1.2616 + } 1.2617 + 1.2618 + if (parent->NodeType() == nsIDOMNode::TEXT_NODE) { 1.2619 + // Good news, the caret is in a text node. Look 1.2620 + // through the offset table for the entry that 1.2621 + // matches its parent and offset. 1.2622 + 1.2623 + for (int32_t i = 0; i < tableCount; i++) { 1.2624 + OffsetEntry* entry = mOffsetTable[i]; 1.2625 + NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); 1.2626 + 1.2627 + if (entry->mNode == domParent.get() && 1.2628 + entry->mNodeOffset <= offset && offset <= (entry->mNodeOffset + entry->mLength)) 1.2629 + { 1.2630 + *aSelStatus = nsITextServicesDocument::eBlockContains; 1.2631 + *aSelOffset = entry->mStrOffset + (offset - entry->mNodeOffset); 1.2632 + *aSelLength = 0; 1.2633 + 1.2634 + return NS_OK; 1.2635 + } 1.2636 + } 1.2637 + 1.2638 + // If we get here, we didn't find a text node entry 1.2639 + // in our offset table that matched. 1.2640 + 1.2641 + return NS_ERROR_FAILURE; 1.2642 + } 1.2643 + 1.2644 + // The caret is in our text block, but it's positioned in some 1.2645 + // non-text node (ex. <b>). Create a range based on the start 1.2646 + // and end of the text block, then create an iterator based on 1.2647 + // this range, with its initial position set to the closest 1.2648 + // child of this non-text node. Then look for the closest text 1.2649 + // node. 1.2650 + 1.2651 + result = CreateRange(eStart->mNode, eStartOffset, eEnd->mNode, eEndOffset, getter_AddRefs(range)); 1.2652 + NS_ENSURE_SUCCESS(result, result); 1.2653 + 1.2654 + nsCOMPtr<nsIContentIterator> iter; 1.2655 + result = CreateContentIterator(range, getter_AddRefs(iter)); 1.2656 + NS_ENSURE_SUCCESS(result, result); 1.2657 + 1.2658 + nsIContent* saveNode; 1.2659 + if (parent->HasChildren()) { 1.2660 + // XXX: We need to make sure that all of parent's 1.2661 + // children are in the text block. 1.2662 + 1.2663 + // If the parent has children, position the iterator 1.2664 + // on the child that is to the left of the offset. 1.2665 + 1.2666 + uint32_t childIndex = (uint32_t)offset; 1.2667 + 1.2668 + if (childIndex > 0) { 1.2669 + uint32_t numChildren = parent->GetChildCount(); 1.2670 + NS_ASSERTION(childIndex <= numChildren, "Invalid selection offset!"); 1.2671 + 1.2672 + if (childIndex > numChildren) { 1.2673 + childIndex = numChildren; 1.2674 + } 1.2675 + 1.2676 + childIndex -= 1; 1.2677 + } 1.2678 + 1.2679 + nsIContent* content = parent->GetChildAt(childIndex); 1.2680 + NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); 1.2681 + 1.2682 + result = iter->PositionAt(content); 1.2683 + NS_ENSURE_SUCCESS(result, result); 1.2684 + 1.2685 + saveNode = content; 1.2686 + } else { 1.2687 + // The parent has no children, so position the iterator 1.2688 + // on the parent. 1.2689 + NS_ENSURE_TRUE(parent->IsContent(), NS_ERROR_FAILURE); 1.2690 + nsCOMPtr<nsIContent> content = parent->AsContent(); 1.2691 + 1.2692 + result = iter->PositionAt(content); 1.2693 + NS_ENSURE_SUCCESS(result, result); 1.2694 + 1.2695 + saveNode = content; 1.2696 + } 1.2697 + 1.2698 + // Now iterate to the left, towards the beginning of 1.2699 + // the text block, to find the first text node you 1.2700 + // come across. 1.2701 + 1.2702 + nsIContent* node = nullptr; 1.2703 + while (!iter->IsDone()) { 1.2704 + nsINode* current = iter->GetCurrentNode(); 1.2705 + if (current->NodeType() == nsIDOMNode::TEXT_NODE) { 1.2706 + node = static_cast<nsIContent*>(current); 1.2707 + break; 1.2708 + } 1.2709 + 1.2710 + iter->Prev(); 1.2711 + } 1.2712 + 1.2713 + if (node) { 1.2714 + // We found a node, now set the offset to the end 1.2715 + // of the text node. 1.2716 + offset = node->TextLength(); 1.2717 + } else { 1.2718 + // We should never really get here, but I'm paranoid. 1.2719 + 1.2720 + // We didn't find a text node above, so iterate to 1.2721 + // the right, towards the end of the text block, looking 1.2722 + // for a text node. 1.2723 + 1.2724 + result = iter->PositionAt(saveNode); 1.2725 + NS_ENSURE_SUCCESS(result, result); 1.2726 + 1.2727 + node = nullptr; 1.2728 + while (!iter->IsDone()) { 1.2729 + nsINode* current = iter->GetCurrentNode(); 1.2730 + 1.2731 + if (current->NodeType() == nsIDOMNode::TEXT_NODE) { 1.2732 + node = static_cast<nsIContent*>(current); 1.2733 + break; 1.2734 + } 1.2735 + 1.2736 + iter->Next(); 1.2737 + } 1.2738 + 1.2739 + NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); 1.2740 + 1.2741 + // We found a text node, so set the offset to 1.2742 + // the beginning of the node. 1.2743 + 1.2744 + offset = 0; 1.2745 + } 1.2746 + 1.2747 + for (int32_t i = 0; i < tableCount; i++) { 1.2748 + OffsetEntry* entry = mOffsetTable[i]; 1.2749 + NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); 1.2750 + 1.2751 + if (entry->mNode == node->AsDOMNode() && 1.2752 + entry->mNodeOffset <= offset && offset <= (entry->mNodeOffset + entry->mLength)) 1.2753 + { 1.2754 + *aSelStatus = nsITextServicesDocument::eBlockContains; 1.2755 + *aSelOffset = entry->mStrOffset + (offset - entry->mNodeOffset); 1.2756 + *aSelLength = 0; 1.2757 + 1.2758 + // Now move the caret so that it is actually in the text node. 1.2759 + // We do this to keep things in sync. 1.2760 + // 1.2761 + // In most cases, the user shouldn't see any movement in the caret 1.2762 + // on screen. 1.2763 + 1.2764 + result = SetSelectionInternal(*aSelOffset, *aSelLength, true); 1.2765 + 1.2766 + return result; 1.2767 + } 1.2768 + } 1.2769 + 1.2770 + return NS_ERROR_FAILURE; 1.2771 +} 1.2772 + 1.2773 +nsresult 1.2774 +nsTextServicesDocument::GetUncollapsedSelection(nsITextServicesDocument::TSDBlockSelectionStatus *aSelStatus, int32_t *aSelOffset, int32_t *aSelLength) 1.2775 +{ 1.2776 + nsresult result; 1.2777 + 1.2778 + nsCOMPtr<nsISelection> selection; 1.2779 + nsCOMPtr<nsIDOMRange> range; 1.2780 + OffsetEntry *entry; 1.2781 + 1.2782 + result = mSelCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection)); 1.2783 + 1.2784 + NS_ENSURE_SUCCESS(result, result); 1.2785 + 1.2786 + NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE); 1.2787 + 1.2788 + // It is assumed that the calling function has made sure that the 1.2789 + // selection is not collapsed, and that the input params to this 1.2790 + // method are initialized to some defaults. 1.2791 + 1.2792 + nsCOMPtr<nsIDOMNode> startParent, endParent; 1.2793 + int32_t startOffset, endOffset; 1.2794 + int32_t rangeCount, tableCount, i; 1.2795 + int32_t e1s1, e1s2, e2s1, e2s2; 1.2796 + 1.2797 + OffsetEntry *eStart, *eEnd; 1.2798 + int32_t eStartOffset, eEndOffset; 1.2799 + 1.2800 + tableCount = mOffsetTable.Length(); 1.2801 + 1.2802 + // Get pointers to the first and last offset entries 1.2803 + // in the table. 1.2804 + 1.2805 + eStart = mOffsetTable[0]; 1.2806 + 1.2807 + if (tableCount > 1) 1.2808 + eEnd = mOffsetTable[tableCount - 1]; 1.2809 + else 1.2810 + eEnd = eStart; 1.2811 + 1.2812 + eStartOffset = eStart->mNodeOffset; 1.2813 + eEndOffset = eEnd->mNodeOffset + eEnd->mLength; 1.2814 + 1.2815 + result = selection->GetRangeCount(&rangeCount); 1.2816 + 1.2817 + NS_ENSURE_SUCCESS(result, result); 1.2818 + 1.2819 + // Find the first range in the selection that intersects 1.2820 + // the current text block. 1.2821 + 1.2822 + for (i = 0; i < rangeCount; i++) 1.2823 + { 1.2824 + result = selection->GetRangeAt(i, getter_AddRefs(range)); 1.2825 + 1.2826 + NS_ENSURE_SUCCESS(result, result); 1.2827 + 1.2828 + result = GetRangeEndPoints(range, 1.2829 + getter_AddRefs(startParent), &startOffset, 1.2830 + getter_AddRefs(endParent), &endOffset); 1.2831 + 1.2832 + NS_ENSURE_SUCCESS(result, result); 1.2833 + 1.2834 + e1s2 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset, 1.2835 + endParent, endOffset); 1.2836 + e2s1 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset, 1.2837 + startParent, startOffset); 1.2838 + 1.2839 + // Break out of the loop if the text block intersects the current range. 1.2840 + 1.2841 + if (e1s2 <= 0 && e2s1 >= 0) 1.2842 + break; 1.2843 + } 1.2844 + 1.2845 + // We're done if we didn't find an intersecting range. 1.2846 + 1.2847 + if (rangeCount < 1 || e1s2 > 0 || e2s1 < 0) 1.2848 + { 1.2849 + *aSelStatus = nsITextServicesDocument::eBlockOutside; 1.2850 + *aSelOffset = *aSelLength = -1; 1.2851 + return NS_OK; 1.2852 + } 1.2853 + 1.2854 + // Now that we have an intersecting range, find out more info: 1.2855 + 1.2856 + e1s1 = nsContentUtils::ComparePoints(eStart->mNode, eStartOffset, 1.2857 + startParent, startOffset); 1.2858 + e2s2 = nsContentUtils::ComparePoints(eEnd->mNode, eEndOffset, 1.2859 + endParent, endOffset); 1.2860 + 1.2861 + if (rangeCount > 1) 1.2862 + { 1.2863 + // There are multiple selection ranges, we only deal 1.2864 + // with the first one that intersects the current, 1.2865 + // text block, so mark this a as a partial. 1.2866 + 1.2867 + *aSelStatus = nsITextServicesDocument::eBlockPartial; 1.2868 + } 1.2869 + else if (e1s1 > 0 && e2s2 < 0) 1.2870 + { 1.2871 + // The range extends beyond the start and 1.2872 + // end of the current text block. 1.2873 + 1.2874 + *aSelStatus = nsITextServicesDocument::eBlockInside; 1.2875 + } 1.2876 + else if (e1s1 <= 0 && e2s2 >= 0) 1.2877 + { 1.2878 + // The current text block contains the entire 1.2879 + // range. 1.2880 + 1.2881 + *aSelStatus = nsITextServicesDocument::eBlockContains; 1.2882 + } 1.2883 + else 1.2884 + { 1.2885 + // The range partially intersects the block. 1.2886 + 1.2887 + *aSelStatus = nsITextServicesDocument::eBlockPartial; 1.2888 + } 1.2889 + 1.2890 + // Now create a range based on the intersection of the 1.2891 + // text block and range: 1.2892 + 1.2893 + nsCOMPtr<nsIDOMNode> p1, p2; 1.2894 + int32_t o1, o2; 1.2895 + 1.2896 + // The start of the range will be the rightmost 1.2897 + // start node. 1.2898 + 1.2899 + if (e1s1 >= 0) 1.2900 + { 1.2901 + p1 = do_QueryInterface(eStart->mNode); 1.2902 + o1 = eStartOffset; 1.2903 + } 1.2904 + else 1.2905 + { 1.2906 + p1 = startParent; 1.2907 + o1 = startOffset; 1.2908 + } 1.2909 + 1.2910 + // The end of the range will be the leftmost 1.2911 + // end node. 1.2912 + 1.2913 + if (e2s2 <= 0) 1.2914 + { 1.2915 + p2 = do_QueryInterface(eEnd->mNode); 1.2916 + o2 = eEndOffset; 1.2917 + } 1.2918 + else 1.2919 + { 1.2920 + p2 = endParent; 1.2921 + o2 = endOffset; 1.2922 + } 1.2923 + 1.2924 + result = CreateRange(p1, o1, p2, o2, getter_AddRefs(range)); 1.2925 + 1.2926 + NS_ENSURE_SUCCESS(result, result); 1.2927 + 1.2928 + // Now iterate over this range to figure out the selection's 1.2929 + // block offset and length. 1.2930 + 1.2931 + nsCOMPtr<nsIContentIterator> iter; 1.2932 + 1.2933 + result = CreateContentIterator(range, getter_AddRefs(iter)); 1.2934 + 1.2935 + NS_ENSURE_SUCCESS(result, result); 1.2936 + 1.2937 + // Find the first text node in the range. 1.2938 + 1.2939 + bool found; 1.2940 + nsCOMPtr<nsIContent> content; 1.2941 + 1.2942 + iter->First(); 1.2943 + 1.2944 + if (!IsTextNode(p1)) 1.2945 + { 1.2946 + found = false; 1.2947 + 1.2948 + while (!iter->IsDone()) 1.2949 + { 1.2950 + content = do_QueryInterface(iter->GetCurrentNode()); 1.2951 + 1.2952 + if (IsTextNode(content)) 1.2953 + { 1.2954 + p1 = do_QueryInterface(content); 1.2955 + 1.2956 + NS_ENSURE_TRUE(p1, NS_ERROR_FAILURE); 1.2957 + 1.2958 + o1 = 0; 1.2959 + found = true; 1.2960 + 1.2961 + break; 1.2962 + } 1.2963 + 1.2964 + iter->Next(); 1.2965 + } 1.2966 + 1.2967 + NS_ENSURE_TRUE(found, NS_ERROR_FAILURE); 1.2968 + } 1.2969 + 1.2970 + // Find the last text node in the range. 1.2971 + 1.2972 + iter->Last(); 1.2973 + 1.2974 + if (! IsTextNode(p2)) 1.2975 + { 1.2976 + found = false; 1.2977 + 1.2978 + while (!iter->IsDone()) 1.2979 + { 1.2980 + content = do_QueryInterface(iter->GetCurrentNode()); 1.2981 + 1.2982 + if (IsTextNode(content)) 1.2983 + { 1.2984 + p2 = do_QueryInterface(content); 1.2985 + 1.2986 + NS_ENSURE_TRUE(p2, NS_ERROR_FAILURE); 1.2987 + 1.2988 + nsString str; 1.2989 + 1.2990 + result = p2->GetNodeValue(str); 1.2991 + 1.2992 + NS_ENSURE_SUCCESS(result, result); 1.2993 + 1.2994 + o2 = str.Length(); 1.2995 + found = true; 1.2996 + 1.2997 + break; 1.2998 + } 1.2999 + 1.3000 + iter->Prev(); 1.3001 + } 1.3002 + 1.3003 + NS_ENSURE_TRUE(found, NS_ERROR_FAILURE); 1.3004 + } 1.3005 + 1.3006 + found = false; 1.3007 + *aSelLength = 0; 1.3008 + 1.3009 + for (i = 0; i < tableCount; i++) 1.3010 + { 1.3011 + entry = mOffsetTable[i]; 1.3012 + 1.3013 + NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); 1.3014 + 1.3015 + if (!found) 1.3016 + { 1.3017 + if (entry->mNode == p1.get() && 1.3018 + entry->mNodeOffset <= o1 && o1 <= (entry->mNodeOffset + entry->mLength)) 1.3019 + { 1.3020 + *aSelOffset = entry->mStrOffset + (o1 - entry->mNodeOffset); 1.3021 + 1.3022 + if (p1 == p2 && 1.3023 + entry->mNodeOffset <= o2 && o2 <= (entry->mNodeOffset + entry->mLength)) 1.3024 + { 1.3025 + // The start and end of the range are in the same offset 1.3026 + // entry. Calculate the length of the range then we're done. 1.3027 + 1.3028 + *aSelLength = o2 - o1; 1.3029 + break; 1.3030 + } 1.3031 + else 1.3032 + { 1.3033 + // Add the length of the sub string in this offset entry 1.3034 + // that follows the start of the range. 1.3035 + 1.3036 + *aSelLength = entry->mLength - (o1 - entry->mNodeOffset); 1.3037 + } 1.3038 + 1.3039 + found = true; 1.3040 + } 1.3041 + } 1.3042 + else // found 1.3043 + { 1.3044 + if (entry->mNode == p2.get() && 1.3045 + entry->mNodeOffset <= o2 && o2 <= (entry->mNodeOffset + entry->mLength)) 1.3046 + { 1.3047 + // We found the end of the range. Calculate the length of the 1.3048 + // sub string that is before the end of the range, then we're done. 1.3049 + 1.3050 + *aSelLength += o2 - entry->mNodeOffset; 1.3051 + break; 1.3052 + } 1.3053 + else 1.3054 + { 1.3055 + // The entire entry must be in the range. 1.3056 + 1.3057 + *aSelLength += entry->mLength; 1.3058 + } 1.3059 + } 1.3060 + } 1.3061 + 1.3062 + return result; 1.3063 +} 1.3064 + 1.3065 +bool 1.3066 +nsTextServicesDocument::SelectionIsCollapsed() 1.3067 +{ 1.3068 + return(mSelStartIndex == mSelEndIndex && mSelStartOffset == mSelEndOffset); 1.3069 +} 1.3070 + 1.3071 +bool 1.3072 +nsTextServicesDocument::SelectionIsValid() 1.3073 +{ 1.3074 + return(mSelStartIndex >= 0); 1.3075 +} 1.3076 + 1.3077 +nsresult 1.3078 +nsTextServicesDocument::GetRangeEndPoints(nsIDOMRange *aRange, 1.3079 + nsIDOMNode **aStartParent, int32_t *aStartOffset, 1.3080 + nsIDOMNode **aEndParent, int32_t *aEndOffset) 1.3081 +{ 1.3082 + nsresult result; 1.3083 + 1.3084 + NS_ENSURE_TRUE(aRange && aStartParent && aStartOffset && aEndParent && aEndOffset, NS_ERROR_NULL_POINTER); 1.3085 + 1.3086 + result = aRange->GetStartContainer(aStartParent); 1.3087 + 1.3088 + NS_ENSURE_SUCCESS(result, result); 1.3089 + 1.3090 + NS_ENSURE_TRUE(aStartParent, NS_ERROR_FAILURE); 1.3091 + 1.3092 + result = aRange->GetStartOffset(aStartOffset); 1.3093 + 1.3094 + NS_ENSURE_SUCCESS(result, result); 1.3095 + 1.3096 + result = aRange->GetEndContainer(aEndParent); 1.3097 + 1.3098 + NS_ENSURE_SUCCESS(result, result); 1.3099 + 1.3100 + NS_ENSURE_TRUE(aEndParent, NS_ERROR_FAILURE); 1.3101 + 1.3102 + result = aRange->GetEndOffset(aEndOffset); 1.3103 + 1.3104 + return result; 1.3105 +} 1.3106 + 1.3107 + 1.3108 +nsresult 1.3109 +nsTextServicesDocument::CreateRange(nsIDOMNode *aStartParent, int32_t aStartOffset, 1.3110 + nsIDOMNode *aEndParent, int32_t aEndOffset, 1.3111 + nsIDOMRange **aRange) 1.3112 +{ 1.3113 + return nsRange::CreateRange(aStartParent, aStartOffset, aEndParent, 1.3114 + aEndOffset, aRange); 1.3115 +} 1.3116 + 1.3117 +nsresult 1.3118 +nsTextServicesDocument::FirstTextNode(nsIContentIterator *aIterator, 1.3119 + TSDIteratorStatus *aIteratorStatus) 1.3120 +{ 1.3121 + if (aIteratorStatus) 1.3122 + *aIteratorStatus = nsTextServicesDocument::eIsDone; 1.3123 + 1.3124 + aIterator->First(); 1.3125 + 1.3126 + while (!aIterator->IsDone()) { 1.3127 + if (aIterator->GetCurrentNode()->NodeType() == nsIDOMNode::TEXT_NODE) { 1.3128 + if (aIteratorStatus) 1.3129 + *aIteratorStatus = nsTextServicesDocument::eValid; 1.3130 + break; 1.3131 + } 1.3132 + 1.3133 + aIterator->Next(); 1.3134 + } 1.3135 + 1.3136 + return NS_OK; 1.3137 +} 1.3138 + 1.3139 +nsresult 1.3140 +nsTextServicesDocument::LastTextNode(nsIContentIterator *aIterator, 1.3141 + TSDIteratorStatus *aIteratorStatus) 1.3142 +{ 1.3143 + if (aIteratorStatus) 1.3144 + *aIteratorStatus = nsTextServicesDocument::eIsDone; 1.3145 + 1.3146 + aIterator->Last(); 1.3147 + 1.3148 + while (!aIterator->IsDone()) { 1.3149 + if (aIterator->GetCurrentNode()->NodeType() == nsIDOMNode::TEXT_NODE) { 1.3150 + if (aIteratorStatus) 1.3151 + *aIteratorStatus = nsTextServicesDocument::eValid; 1.3152 + break; 1.3153 + } 1.3154 + 1.3155 + aIterator->Prev(); 1.3156 + } 1.3157 + 1.3158 + return NS_OK; 1.3159 +} 1.3160 + 1.3161 +nsresult 1.3162 +nsTextServicesDocument::FirstTextNodeInCurrentBlock(nsIContentIterator *iter) 1.3163 +{ 1.3164 + NS_ENSURE_TRUE(iter, NS_ERROR_NULL_POINTER); 1.3165 + 1.3166 + ClearDidSkip(iter); 1.3167 + 1.3168 + nsCOMPtr<nsIContent> last; 1.3169 + 1.3170 + // Walk backwards over adjacent text nodes until 1.3171 + // we hit a block boundary: 1.3172 + 1.3173 + while (!iter->IsDone()) 1.3174 + { 1.3175 + nsCOMPtr<nsIContent> content = iter->GetCurrentNode()->IsContent() 1.3176 + ? iter->GetCurrentNode()->AsContent() 1.3177 + : nullptr; 1.3178 + 1.3179 + if (IsTextNode(content)) 1.3180 + { 1.3181 + if (!last || HasSameBlockNodeParent(content, last)) 1.3182 + last = content; 1.3183 + else 1.3184 + { 1.3185 + // We're done, the current text node is in a 1.3186 + // different block. 1.3187 + break; 1.3188 + } 1.3189 + } 1.3190 + else if (last && IsBlockNode(content)) 1.3191 + break; 1.3192 + 1.3193 + iter->Prev(); 1.3194 + 1.3195 + if (DidSkip(iter)) 1.3196 + break; 1.3197 + } 1.3198 + 1.3199 + if (last) 1.3200 + iter->PositionAt(last); 1.3201 + 1.3202 + // XXX: What should we return if last is null? 1.3203 + 1.3204 + return NS_OK; 1.3205 +} 1.3206 + 1.3207 +nsresult 1.3208 +nsTextServicesDocument::FirstTextNodeInPrevBlock(nsIContentIterator *aIterator) 1.3209 +{ 1.3210 + nsCOMPtr<nsIContent> content; 1.3211 + nsresult result; 1.3212 + 1.3213 + NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER); 1.3214 + 1.3215 + // XXX: What if mIterator is not currently on a text node? 1.3216 + 1.3217 + // Make sure mIterator is pointing to the first text node in the 1.3218 + // current block: 1.3219 + 1.3220 + result = FirstTextNodeInCurrentBlock(aIterator); 1.3221 + 1.3222 + NS_ENSURE_SUCCESS(result, NS_ERROR_FAILURE); 1.3223 + 1.3224 + // Point mIterator to the first node before the first text node: 1.3225 + 1.3226 + aIterator->Prev(); 1.3227 + 1.3228 + if (aIterator->IsDone()) 1.3229 + return NS_ERROR_FAILURE; 1.3230 + 1.3231 + // Now find the first text node of the next block: 1.3232 + 1.3233 + return FirstTextNodeInCurrentBlock(aIterator); 1.3234 +} 1.3235 + 1.3236 +nsresult 1.3237 +nsTextServicesDocument::FirstTextNodeInNextBlock(nsIContentIterator *aIterator) 1.3238 +{ 1.3239 + nsCOMPtr<nsIContent> prev; 1.3240 + bool crossedBlockBoundary = false; 1.3241 + 1.3242 + NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER); 1.3243 + 1.3244 + ClearDidSkip(aIterator); 1.3245 + 1.3246 + while (!aIterator->IsDone()) 1.3247 + { 1.3248 + nsCOMPtr<nsIContent> content = aIterator->GetCurrentNode()->IsContent() 1.3249 + ? aIterator->GetCurrentNode()->AsContent() 1.3250 + : nullptr; 1.3251 + 1.3252 + if (IsTextNode(content)) 1.3253 + { 1.3254 + if (!crossedBlockBoundary && (!prev || HasSameBlockNodeParent(prev, content))) 1.3255 + prev = content; 1.3256 + else 1.3257 + break; 1.3258 + } 1.3259 + else if (!crossedBlockBoundary && IsBlockNode(content)) 1.3260 + crossedBlockBoundary = true; 1.3261 + 1.3262 + aIterator->Next(); 1.3263 + 1.3264 + if (!crossedBlockBoundary && DidSkip(aIterator)) 1.3265 + crossedBlockBoundary = true; 1.3266 + } 1.3267 + 1.3268 + return NS_OK; 1.3269 +} 1.3270 + 1.3271 +nsresult 1.3272 +nsTextServicesDocument::GetFirstTextNodeInPrevBlock(nsIContent **aContent) 1.3273 +{ 1.3274 + nsresult result; 1.3275 + 1.3276 + NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER); 1.3277 + 1.3278 + *aContent = 0; 1.3279 + 1.3280 + // Save the iterator's current content node so we can restore 1.3281 + // it when we are done: 1.3282 + 1.3283 + nsINode* node = mIterator->GetCurrentNode(); 1.3284 + 1.3285 + result = FirstTextNodeInPrevBlock(mIterator); 1.3286 + 1.3287 + if (NS_FAILED(result)) 1.3288 + { 1.3289 + // Try to restore the iterator before returning. 1.3290 + mIterator->PositionAt(node); 1.3291 + return result; 1.3292 + } 1.3293 + 1.3294 + if (!mIterator->IsDone()) 1.3295 + { 1.3296 + nsCOMPtr<nsIContent> current = mIterator->GetCurrentNode()->IsContent() 1.3297 + ? mIterator->GetCurrentNode()->AsContent() 1.3298 + : nullptr; 1.3299 + current.forget(aContent); 1.3300 + } 1.3301 + 1.3302 + // Restore the iterator: 1.3303 + 1.3304 + return mIterator->PositionAt(node); 1.3305 +} 1.3306 + 1.3307 +nsresult 1.3308 +nsTextServicesDocument::GetFirstTextNodeInNextBlock(nsIContent **aContent) 1.3309 +{ 1.3310 + nsresult result; 1.3311 + 1.3312 + NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER); 1.3313 + 1.3314 + *aContent = 0; 1.3315 + 1.3316 + // Save the iterator's current content node so we can restore 1.3317 + // it when we are done: 1.3318 + 1.3319 + nsINode* node = mIterator->GetCurrentNode(); 1.3320 + 1.3321 + result = FirstTextNodeInNextBlock(mIterator); 1.3322 + 1.3323 + if (NS_FAILED(result)) 1.3324 + { 1.3325 + // Try to restore the iterator before returning. 1.3326 + mIterator->PositionAt(node); 1.3327 + return result; 1.3328 + } 1.3329 + 1.3330 + if (!mIterator->IsDone()) 1.3331 + { 1.3332 + nsCOMPtr<nsIContent> current = mIterator->GetCurrentNode()->IsContent() 1.3333 + ? mIterator->GetCurrentNode()->AsContent() 1.3334 + : nullptr; 1.3335 + current.forget(aContent); 1.3336 + } 1.3337 + 1.3338 + // Restore the iterator: 1.3339 + return mIterator->PositionAt(node); 1.3340 +} 1.3341 + 1.3342 +nsresult 1.3343 +nsTextServicesDocument::CreateOffsetTable(nsTArray<OffsetEntry*> *aOffsetTable, 1.3344 + nsIContentIterator *aIterator, 1.3345 + TSDIteratorStatus *aIteratorStatus, 1.3346 + nsIDOMRange *aIterRange, 1.3347 + nsString *aStr) 1.3348 +{ 1.3349 + nsresult result = NS_OK; 1.3350 + 1.3351 + nsCOMPtr<nsIContent> first; 1.3352 + nsCOMPtr<nsIContent> prev; 1.3353 + 1.3354 + NS_ENSURE_TRUE(aIterator, NS_ERROR_NULL_POINTER); 1.3355 + 1.3356 + ClearOffsetTable(aOffsetTable); 1.3357 + 1.3358 + if (aStr) 1.3359 + aStr->Truncate(); 1.3360 + 1.3361 + if (*aIteratorStatus == nsTextServicesDocument::eIsDone) 1.3362 + return NS_OK; 1.3363 + 1.3364 + // If we have an aIterRange, retrieve the endpoints so 1.3365 + // they can be used in the while loop below to trim entries 1.3366 + // for text nodes that are partially selected by aIterRange. 1.3367 + 1.3368 + nsCOMPtr<nsIDOMNode> rngStartNode, rngEndNode; 1.3369 + int32_t rngStartOffset = 0, rngEndOffset = 0; 1.3370 + 1.3371 + if (aIterRange) 1.3372 + { 1.3373 + result = GetRangeEndPoints(aIterRange, 1.3374 + getter_AddRefs(rngStartNode), &rngStartOffset, 1.3375 + getter_AddRefs(rngEndNode), &rngEndOffset); 1.3376 + 1.3377 + NS_ENSURE_SUCCESS(result, result); 1.3378 + } 1.3379 + 1.3380 + // The text service could have added text nodes to the beginning 1.3381 + // of the current block and called this method again. Make sure 1.3382 + // we really are at the beginning of the current block: 1.3383 + 1.3384 + result = FirstTextNodeInCurrentBlock(aIterator); 1.3385 + 1.3386 + NS_ENSURE_SUCCESS(result, result); 1.3387 + 1.3388 + int32_t offset = 0; 1.3389 + 1.3390 + ClearDidSkip(aIterator); 1.3391 + 1.3392 + while (!aIterator->IsDone()) 1.3393 + { 1.3394 + nsCOMPtr<nsIContent> content = aIterator->GetCurrentNode()->IsContent() 1.3395 + ? aIterator->GetCurrentNode()->AsContent() 1.3396 + : nullptr; 1.3397 + 1.3398 + if (IsTextNode(content)) 1.3399 + { 1.3400 + if (!prev || HasSameBlockNodeParent(prev, content)) 1.3401 + { 1.3402 + nsCOMPtr<nsIDOMNode> node = do_QueryInterface(content); 1.3403 + 1.3404 + if (node) 1.3405 + { 1.3406 + nsString str; 1.3407 + 1.3408 + result = node->GetNodeValue(str); 1.3409 + 1.3410 + NS_ENSURE_SUCCESS(result, result); 1.3411 + 1.3412 + // Add an entry for this text node into the offset table: 1.3413 + 1.3414 + OffsetEntry *entry = new OffsetEntry(node, offset, str.Length()); 1.3415 + aOffsetTable->AppendElement(entry); 1.3416 + 1.3417 + // If one or both of the endpoints of the iteration range 1.3418 + // are in the text node for this entry, make sure the entry 1.3419 + // only accounts for the portion of the text node that is 1.3420 + // in the range. 1.3421 + 1.3422 + int32_t startOffset = 0; 1.3423 + int32_t endOffset = str.Length(); 1.3424 + bool adjustStr = false; 1.3425 + 1.3426 + if (entry->mNode == rngStartNode) 1.3427 + { 1.3428 + entry->mNodeOffset = startOffset = rngStartOffset; 1.3429 + adjustStr = true; 1.3430 + } 1.3431 + 1.3432 + if (entry->mNode == rngEndNode) 1.3433 + { 1.3434 + endOffset = rngEndOffset; 1.3435 + adjustStr = true; 1.3436 + } 1.3437 + 1.3438 + if (adjustStr) 1.3439 + { 1.3440 + entry->mLength = endOffset - startOffset; 1.3441 + str = Substring(str, startOffset, entry->mLength); 1.3442 + } 1.3443 + 1.3444 + offset += str.Length(); 1.3445 + 1.3446 + if (aStr) 1.3447 + { 1.3448 + // Append the text node's string to the output string: 1.3449 + 1.3450 + if (!first) 1.3451 + *aStr = str; 1.3452 + else 1.3453 + *aStr += str; 1.3454 + } 1.3455 + } 1.3456 + 1.3457 + prev = content; 1.3458 + 1.3459 + if (!first) 1.3460 + first = content; 1.3461 + } 1.3462 + else 1.3463 + break; 1.3464 + 1.3465 + } 1.3466 + else if (IsBlockNode(content)) 1.3467 + break; 1.3468 + 1.3469 + aIterator->Next(); 1.3470 + 1.3471 + if (DidSkip(aIterator)) 1.3472 + break; 1.3473 + } 1.3474 + 1.3475 + if (first) 1.3476 + { 1.3477 + // Always leave the iterator pointing at the first 1.3478 + // text node of the current block! 1.3479 + 1.3480 + aIterator->PositionAt(first); 1.3481 + } 1.3482 + else 1.3483 + { 1.3484 + // If we never ran across a text node, the iterator 1.3485 + // might have been pointing to something invalid to 1.3486 + // begin with. 1.3487 + 1.3488 + *aIteratorStatus = nsTextServicesDocument::eIsDone; 1.3489 + } 1.3490 + 1.3491 + return result; 1.3492 +} 1.3493 + 1.3494 +nsresult 1.3495 +nsTextServicesDocument::RemoveInvalidOffsetEntries() 1.3496 +{ 1.3497 + OffsetEntry *entry; 1.3498 + int32_t i = 0; 1.3499 + 1.3500 + while (uint32_t(i) < mOffsetTable.Length()) 1.3501 + { 1.3502 + entry = mOffsetTable[i]; 1.3503 + 1.3504 + if (!entry->mIsValid) 1.3505 + { 1.3506 + mOffsetTable.RemoveElementAt(i); 1.3507 + 1.3508 + if (mSelStartIndex >= 0 && mSelStartIndex >= i) 1.3509 + { 1.3510 + // We are deleting an entry that comes before 1.3511 + // mSelStartIndex, decrement mSelStartIndex so 1.3512 + // that it points to the correct entry! 1.3513 + 1.3514 + NS_ASSERTION(i != mSelStartIndex, "Invalid selection index."); 1.3515 + 1.3516 + --mSelStartIndex; 1.3517 + --mSelEndIndex; 1.3518 + } 1.3519 + } 1.3520 + else 1.3521 + i++; 1.3522 + } 1.3523 + 1.3524 + return NS_OK; 1.3525 +} 1.3526 + 1.3527 +nsresult 1.3528 +nsTextServicesDocument::ClearOffsetTable(nsTArray<OffsetEntry*> *aOffsetTable) 1.3529 +{ 1.3530 + uint32_t i; 1.3531 + 1.3532 + for (i = 0; i < aOffsetTable->Length(); i++) 1.3533 + { 1.3534 + delete aOffsetTable->ElementAt(i); 1.3535 + } 1.3536 + 1.3537 + aOffsetTable->Clear(); 1.3538 + 1.3539 + return NS_OK; 1.3540 +} 1.3541 + 1.3542 +nsresult 1.3543 +nsTextServicesDocument::SplitOffsetEntry(int32_t aTableIndex, int32_t aNewEntryLength) 1.3544 +{ 1.3545 + OffsetEntry *entry = mOffsetTable[aTableIndex]; 1.3546 + 1.3547 + NS_ASSERTION((aNewEntryLength > 0), "aNewEntryLength <= 0"); 1.3548 + NS_ASSERTION((aNewEntryLength < entry->mLength), "aNewEntryLength >= mLength"); 1.3549 + 1.3550 + if (aNewEntryLength < 1 || aNewEntryLength >= entry->mLength) 1.3551 + return NS_ERROR_FAILURE; 1.3552 + 1.3553 + int32_t oldLength = entry->mLength - aNewEntryLength; 1.3554 + 1.3555 + OffsetEntry *newEntry = new OffsetEntry(entry->mNode, 1.3556 + entry->mStrOffset + oldLength, 1.3557 + aNewEntryLength); 1.3558 + 1.3559 + if (!mOffsetTable.InsertElementAt(aTableIndex + 1, newEntry)) 1.3560 + { 1.3561 + delete newEntry; 1.3562 + return NS_ERROR_FAILURE; 1.3563 + } 1.3564 + 1.3565 + // Adjust entry fields: 1.3566 + 1.3567 + entry->mLength = oldLength; 1.3568 + newEntry->mNodeOffset = entry->mNodeOffset + oldLength; 1.3569 + 1.3570 + return NS_OK; 1.3571 +} 1.3572 + 1.3573 +nsresult 1.3574 +nsTextServicesDocument::NodeHasOffsetEntry(nsTArray<OffsetEntry*> *aOffsetTable, nsIDOMNode *aNode, bool *aHasEntry, int32_t *aEntryIndex) 1.3575 +{ 1.3576 + OffsetEntry *entry; 1.3577 + uint32_t i; 1.3578 + 1.3579 + NS_ENSURE_TRUE(aNode && aHasEntry && aEntryIndex, NS_ERROR_NULL_POINTER); 1.3580 + 1.3581 + for (i = 0; i < aOffsetTable->Length(); i++) 1.3582 + { 1.3583 + entry = (*aOffsetTable)[i]; 1.3584 + 1.3585 + NS_ENSURE_TRUE(entry, NS_ERROR_FAILURE); 1.3586 + 1.3587 + if (entry->mNode == aNode) 1.3588 + { 1.3589 + *aHasEntry = true; 1.3590 + *aEntryIndex = i; 1.3591 + 1.3592 + return NS_OK; 1.3593 + } 1.3594 + } 1.3595 + 1.3596 + *aHasEntry = false; 1.3597 + *aEntryIndex = -1; 1.3598 + 1.3599 + return NS_OK; 1.3600 +} 1.3601 + 1.3602 +// Spellchecker code has this. See bug 211343 1.3603 +#define IS_NBSP_CHAR(c) (((unsigned char)0xa0)==(c)) 1.3604 + 1.3605 +nsresult 1.3606 +nsTextServicesDocument::FindWordBounds(nsTArray<OffsetEntry*> *aOffsetTable, 1.3607 + nsString *aBlockStr, 1.3608 + nsIDOMNode *aNode, 1.3609 + int32_t aNodeOffset, 1.3610 + nsIDOMNode **aWordStartNode, 1.3611 + int32_t *aWordStartOffset, 1.3612 + nsIDOMNode **aWordEndNode, 1.3613 + int32_t *aWordEndOffset) 1.3614 +{ 1.3615 + // Initialize return values. 1.3616 + 1.3617 + if (aWordStartNode) 1.3618 + *aWordStartNode = nullptr; 1.3619 + if (aWordStartOffset) 1.3620 + *aWordStartOffset = 0; 1.3621 + if (aWordEndNode) 1.3622 + *aWordEndNode = nullptr; 1.3623 + if (aWordEndOffset) 1.3624 + *aWordEndOffset = 0; 1.3625 + 1.3626 + int32_t entryIndex = 0; 1.3627 + bool hasEntry = false; 1.3628 + 1.3629 + // It's assumed that aNode is a text node. The first thing 1.3630 + // we do is get its index in the offset table so we can 1.3631 + // calculate the dom point's string offset. 1.3632 + 1.3633 + nsresult result = NodeHasOffsetEntry(aOffsetTable, aNode, &hasEntry, &entryIndex); 1.3634 + NS_ENSURE_SUCCESS(result, result); 1.3635 + NS_ENSURE_TRUE(hasEntry, NS_ERROR_FAILURE); 1.3636 + 1.3637 + // Next we map aNodeOffset into a string offset. 1.3638 + 1.3639 + OffsetEntry *entry = (*aOffsetTable)[entryIndex]; 1.3640 + uint32_t strOffset = entry->mStrOffset + aNodeOffset - entry->mNodeOffset; 1.3641 + 1.3642 + // Now we use the word breaker to find the beginning and end 1.3643 + // of the word from our calculated string offset. 1.3644 + 1.3645 + const char16_t *str = aBlockStr->get(); 1.3646 + uint32_t strLen = aBlockStr->Length(); 1.3647 + 1.3648 + nsIWordBreaker* wordBreaker = nsContentUtils::WordBreaker(); 1.3649 + nsWordRange res = wordBreaker->FindWord(str, strLen, strOffset); 1.3650 + if (res.mBegin > strLen) { 1.3651 + return str ? NS_ERROR_ILLEGAL_VALUE : NS_ERROR_NULL_POINTER; 1.3652 + } 1.3653 + 1.3654 + // Strip out the NBSPs at the ends 1.3655 + while ((res.mBegin <= res.mEnd) && (IS_NBSP_CHAR(str[res.mBegin]))) 1.3656 + res.mBegin++; 1.3657 + if (str[res.mEnd] == (unsigned char)0x20) 1.3658 + { 1.3659 + uint32_t realEndWord = res.mEnd - 1; 1.3660 + while ((realEndWord > res.mBegin) && (IS_NBSP_CHAR(str[realEndWord]))) 1.3661 + realEndWord--; 1.3662 + if (realEndWord < res.mEnd - 1) 1.3663 + res.mEnd = realEndWord + 1; 1.3664 + } 1.3665 + 1.3666 + // Now that we have the string offsets for the beginning 1.3667 + // and end of the word, run through the offset table and 1.3668 + // convert them back into dom points. 1.3669 + 1.3670 + int32_t i, lastIndex = aOffsetTable->Length() - 1; 1.3671 + 1.3672 + for (i=0; i <= lastIndex; i++) 1.3673 + { 1.3674 + entry = (*aOffsetTable)[i]; 1.3675 + 1.3676 + int32_t strEndOffset = entry->mStrOffset + entry->mLength; 1.3677 + 1.3678 + // Check to see if res.mBegin is within the range covered 1.3679 + // by this entry. Note that if res.mBegin is after the last 1.3680 + // character covered by this entry, we will use the next 1.3681 + // entry if there is one. 1.3682 + 1.3683 + if (uint32_t(entry->mStrOffset) <= res.mBegin && 1.3684 + (res.mBegin < uint32_t(strEndOffset) || 1.3685 + (res.mBegin == uint32_t(strEndOffset) && i == lastIndex))) 1.3686 + { 1.3687 + if (aWordStartNode) 1.3688 + { 1.3689 + *aWordStartNode = entry->mNode; 1.3690 + NS_IF_ADDREF(*aWordStartNode); 1.3691 + } 1.3692 + 1.3693 + if (aWordStartOffset) 1.3694 + *aWordStartOffset = entry->mNodeOffset + res.mBegin - entry->mStrOffset; 1.3695 + 1.3696 + if (!aWordEndNode && !aWordEndOffset) 1.3697 + { 1.3698 + // We've found our start entry, but if we're not looking 1.3699 + // for end entries, we're done. 1.3700 + 1.3701 + break; 1.3702 + } 1.3703 + } 1.3704 + 1.3705 + // Check to see if res.mEnd is within the range covered 1.3706 + // by this entry. 1.3707 + 1.3708 + if (uint32_t(entry->mStrOffset) <= res.mEnd && res.mEnd <= uint32_t(strEndOffset)) 1.3709 + { 1.3710 + if (res.mBegin == res.mEnd && res.mEnd == uint32_t(strEndOffset) && i != lastIndex) 1.3711 + { 1.3712 + // Wait for the next round so that we use the same entry 1.3713 + // we did for aWordStartNode. 1.3714 + 1.3715 + continue; 1.3716 + } 1.3717 + 1.3718 + if (aWordEndNode) 1.3719 + { 1.3720 + *aWordEndNode = entry->mNode; 1.3721 + NS_IF_ADDREF(*aWordEndNode); 1.3722 + } 1.3723 + 1.3724 + if (aWordEndOffset) 1.3725 + *aWordEndOffset = entry->mNodeOffset + res.mEnd - entry->mStrOffset; 1.3726 + 1.3727 + break; 1.3728 + } 1.3729 + } 1.3730 + 1.3731 + 1.3732 + return NS_OK; 1.3733 +} 1.3734 + 1.3735 +#ifdef DEBUG_kin 1.3736 +void 1.3737 +nsTextServicesDocument::PrintOffsetTable() 1.3738 +{ 1.3739 + OffsetEntry *entry; 1.3740 + uint32_t i; 1.3741 + 1.3742 + for (i = 0; i < mOffsetTable.Length(); i++) 1.3743 + { 1.3744 + entry = mOffsetTable[i]; 1.3745 + printf("ENTRY %4d: %p %c %c %4d %4d %4d\n", 1.3746 + i, entry->mNode, entry->mIsValid ? 'V' : 'N', 1.3747 + entry->mIsInsertedText ? 'I' : 'B', 1.3748 + entry->mNodeOffset, entry->mStrOffset, entry->mLength); 1.3749 + } 1.3750 + 1.3751 + fflush(stdout); 1.3752 +} 1.3753 + 1.3754 +void 1.3755 +nsTextServicesDocument::PrintContentNode(nsIContent *aContent) 1.3756 +{ 1.3757 + nsString tmpStr, str; 1.3758 + 1.3759 + aContent->Tag()->ToString(tmpStr); 1.3760 + printf("%s", NS_LossyConvertUTF16toASCII(tmpStr).get()); 1.3761 + 1.3762 + if (nsIDOMNode::TEXT_NODE == aContent->NodeType()) 1.3763 + { 1.3764 + aContent->AppendTextTo(str); 1.3765 + printf(": \"%s\"", NS_LossyConvertUTF16toASCII(str).get()); 1.3766 + } 1.3767 + 1.3768 + printf("\n"); 1.3769 + fflush(stdout); 1.3770 +} 1.3771 +#endif 1.3772 + 1.3773 +NS_IMETHODIMP 1.3774 +nsTextServicesDocument::WillInsertNode(nsIDOMNode *aNode, 1.3775 + nsIDOMNode *aParent, 1.3776 + int32_t aPosition) 1.3777 +{ 1.3778 + return NS_OK; 1.3779 +} 1.3780 + 1.3781 +NS_IMETHODIMP 1.3782 +nsTextServicesDocument::WillDeleteNode(nsIDOMNode *aChild) 1.3783 +{ 1.3784 + return NS_OK; 1.3785 +} 1.3786 + 1.3787 +NS_IMETHODIMP 1.3788 +nsTextServicesDocument::WillSplitNode(nsIDOMNode *aExistingRightNode, 1.3789 + int32_t aOffset) 1.3790 +{ 1.3791 + return NS_OK; 1.3792 +} 1.3793 + 1.3794 +NS_IMETHODIMP 1.3795 +nsTextServicesDocument::WillJoinNodes(nsIDOMNode *aLeftNode, 1.3796 + nsIDOMNode *aRightNode, 1.3797 + nsIDOMNode *aParent) 1.3798 +{ 1.3799 + return NS_OK; 1.3800 +} 1.3801 + 1.3802 + 1.3803 +// ------------------------------- 1.3804 +// stubs for unused listen methods 1.3805 +// ------------------------------- 1.3806 + 1.3807 +NS_IMETHODIMP 1.3808 +nsTextServicesDocument::WillCreateNode(const nsAString& aTag, nsIDOMNode *aParent, int32_t aPosition) 1.3809 +{ 1.3810 + return NS_OK; 1.3811 +} 1.3812 + 1.3813 +NS_IMETHODIMP 1.3814 +nsTextServicesDocument::DidCreateNode(const nsAString& aTag, nsIDOMNode *aNode, nsIDOMNode *aParent, int32_t aPosition, nsresult aResult) 1.3815 +{ 1.3816 + return NS_OK; 1.3817 +} 1.3818 + 1.3819 +NS_IMETHODIMP 1.3820 +nsTextServicesDocument::WillInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString &aString) 1.3821 +{ 1.3822 + return NS_OK; 1.3823 +} 1.3824 + 1.3825 +NS_IMETHODIMP 1.3826 +nsTextServicesDocument::DidInsertText(nsIDOMCharacterData *aTextNode, int32_t aOffset, const nsAString &aString, nsresult aResult) 1.3827 +{ 1.3828 + return NS_OK; 1.3829 +} 1.3830 + 1.3831 +NS_IMETHODIMP 1.3832 +nsTextServicesDocument::WillDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength) 1.3833 +{ 1.3834 + return NS_OK; 1.3835 +} 1.3836 + 1.3837 +NS_IMETHODIMP 1.3838 +nsTextServicesDocument::DidDeleteText(nsIDOMCharacterData *aTextNode, int32_t aOffset, int32_t aLength, nsresult aResult) 1.3839 +{ 1.3840 + return NS_OK; 1.3841 +} 1.3842 + 1.3843 +NS_IMETHODIMP 1.3844 +nsTextServicesDocument::WillDeleteSelection(nsISelection *aSelection) 1.3845 +{ 1.3846 + return NS_OK; 1.3847 +} 1.3848 + 1.3849 +NS_IMETHODIMP 1.3850 +nsTextServicesDocument::DidDeleteSelection(nsISelection *aSelection) 1.3851 +{ 1.3852 + return NS_OK; 1.3853 +} 1.3854 +