TextEditRules.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "mozilla/TextEditRules.h"
  6. #include "TextEditUtils.h"
  7. #include "mozilla/Assertions.h"
  8. #include "mozilla/EditorUtils.h"
  9. #include "mozilla/LookAndFeel.h"
  10. #include "mozilla/Preferences.h"
  11. #include "mozilla/TextComposition.h"
  12. #include "mozilla/TextEditor.h"
  13. #include "mozilla/dom/Element.h"
  14. #include "mozilla/dom/NodeIterator.h"
  15. #include "mozilla/dom/Selection.h"
  16. #include "nsAString.h"
  17. #include "nsCOMPtr.h"
  18. #include "nsCRT.h"
  19. #include "nsCRTGlue.h"
  20. #include "nsComponentManagerUtils.h"
  21. #include "nsContentUtils.h"
  22. #include "nsDebug.h"
  23. #include "nsError.h"
  24. #include "nsGkAtoms.h"
  25. #include "nsIContent.h"
  26. #include "nsIDOMDocument.h"
  27. #include "nsIDOMElement.h"
  28. #include "nsIDOMNode.h"
  29. #include "nsIDOMNodeFilter.h"
  30. #include "nsIDOMNodeIterator.h"
  31. #include "nsIDOMNodeList.h"
  32. #include "nsIDOMText.h"
  33. #include "nsNameSpaceManager.h"
  34. #include "nsINode.h"
  35. #include "nsIPlaintextEditor.h"
  36. #include "nsISupportsBase.h"
  37. #include "nsLiteralString.h"
  38. #include "nsUnicharUtils.h"
  39. namespace mozilla {
  40. using namespace dom;
  41. #define CANCEL_OPERATION_IF_READONLY_OR_DISABLED \
  42. if (IsReadonly() || IsDisabled()) \
  43. { \
  44. *aCancel = true; \
  45. return NS_OK; \
  46. };
  47. /********************************************************
  48. * mozilla::TextEditRules
  49. ********************************************************/
  50. TextEditRules::TextEditRules()
  51. : mTextEditor(nullptr)
  52. , mPasswordIMEIndex(0)
  53. , mCachedSelectionOffset(0)
  54. , mActionNesting(0)
  55. , mLockRulesSniffing(false)
  56. , mDidExplicitlySetInterline(false)
  57. , mDeleteBidiImmediately(false)
  58. , mTheAction(EditAction::none)
  59. , mLastStart(0)
  60. , mLastLength(0)
  61. {
  62. InitFields();
  63. }
  64. void
  65. TextEditRules::InitFields()
  66. {
  67. mTextEditor = nullptr;
  68. mPasswordText.Truncate();
  69. mPasswordIMEText.Truncate();
  70. mPasswordIMEIndex = 0;
  71. mBogusNode = nullptr;
  72. mCachedSelectionNode = nullptr;
  73. mCachedSelectionOffset = 0;
  74. mActionNesting = 0;
  75. mLockRulesSniffing = false;
  76. mDidExplicitlySetInterline = false;
  77. mDeleteBidiImmediately = false;
  78. mTheAction = EditAction::none;
  79. mTimer = nullptr;
  80. mLastStart = 0;
  81. mLastLength = 0;
  82. }
  83. TextEditRules::~TextEditRules()
  84. {
  85. // do NOT delete mTextEditor here. We do not hold a ref count to
  86. // mTextEditor. mTextEditor owns our lifespan.
  87. if (mTimer) {
  88. mTimer->Cancel();
  89. }
  90. }
  91. NS_IMPL_CYCLE_COLLECTION(TextEditRules, mBogusNode, mCachedSelectionNode)
  92. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextEditRules)
  93. NS_INTERFACE_MAP_ENTRY(nsIEditRules)
  94. NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
  95. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIEditRules)
  96. NS_INTERFACE_MAP_END
  97. NS_IMPL_CYCLE_COLLECTING_ADDREF(TextEditRules)
  98. NS_IMPL_CYCLE_COLLECTING_RELEASE(TextEditRules)
  99. NS_IMETHODIMP
  100. TextEditRules::Init(TextEditor* aTextEditor)
  101. {
  102. if (!aTextEditor) {
  103. return NS_ERROR_NULL_POINTER;
  104. }
  105. InitFields();
  106. // We hold a non-refcounted reference back to our editor.
  107. mTextEditor = aTextEditor;
  108. RefPtr<Selection> selection = mTextEditor->GetSelection();
  109. NS_WARNING_ASSERTION(selection, "editor cannot get selection");
  110. // Put in a magic br if needed. This method handles null selection,
  111. // which should never happen anyway
  112. nsresult rv = CreateBogusNodeIfNeeded(selection);
  113. NS_ENSURE_SUCCESS(rv, rv);
  114. // If the selection hasn't been set up yet, set it up collapsed to the end of
  115. // our editable content.
  116. int32_t rangeCount;
  117. rv = selection->GetRangeCount(&rangeCount);
  118. NS_ENSURE_SUCCESS(rv, rv);
  119. if (!rangeCount) {
  120. rv = mTextEditor->EndOfDocument();
  121. NS_ENSURE_SUCCESS(rv, rv);
  122. }
  123. if (IsPlaintextEditor()) {
  124. // ensure trailing br node
  125. rv = CreateTrailingBRIfNeeded();
  126. NS_ENSURE_SUCCESS(rv, rv);
  127. }
  128. mDeleteBidiImmediately =
  129. Preferences::GetBool("bidi.edit.delete_immediately", false);
  130. return NS_OK;
  131. }
  132. NS_IMETHODIMP
  133. TextEditRules::SetInitialValue(const nsAString& aValue)
  134. {
  135. if (IsPasswordEditor()) {
  136. mPasswordText = aValue;
  137. }
  138. return NS_OK;
  139. }
  140. NS_IMETHODIMP
  141. TextEditRules::DetachEditor()
  142. {
  143. if (mTimer) {
  144. mTimer->Cancel();
  145. }
  146. mTextEditor = nullptr;
  147. return NS_OK;
  148. }
  149. NS_IMETHODIMP
  150. TextEditRules::BeforeEdit(EditAction action,
  151. nsIEditor::EDirection aDirection)
  152. {
  153. if (mLockRulesSniffing) {
  154. return NS_OK;
  155. }
  156. AutoLockRulesSniffing lockIt(this);
  157. mDidExplicitlySetInterline = false;
  158. if (!mActionNesting) {
  159. // let rules remember the top level action
  160. mTheAction = action;
  161. }
  162. mActionNesting++;
  163. // get the selection and cache the position before editing
  164. NS_ENSURE_STATE(mTextEditor);
  165. RefPtr<Selection> selection = mTextEditor->GetSelection();
  166. NS_ENSURE_STATE(selection);
  167. selection->GetAnchorNode(getter_AddRefs(mCachedSelectionNode));
  168. selection->GetAnchorOffset(&mCachedSelectionOffset);
  169. return NS_OK;
  170. }
  171. NS_IMETHODIMP
  172. TextEditRules::AfterEdit(EditAction action,
  173. nsIEditor::EDirection aDirection)
  174. {
  175. if (mLockRulesSniffing) {
  176. return NS_OK;
  177. }
  178. AutoLockRulesSniffing lockIt(this);
  179. NS_PRECONDITION(mActionNesting>0, "bad action nesting!");
  180. if (!--mActionNesting) {
  181. NS_ENSURE_STATE(mTextEditor);
  182. RefPtr<Selection> selection = mTextEditor->GetSelection();
  183. NS_ENSURE_STATE(selection);
  184. NS_ENSURE_STATE(mTextEditor);
  185. nsresult rv =
  186. mTextEditor->HandleInlineSpellCheck(action, selection,
  187. mCachedSelectionNode,
  188. mCachedSelectionOffset,
  189. nullptr, 0, nullptr, 0);
  190. NS_ENSURE_SUCCESS(rv, rv);
  191. // if only trailing <br> remaining remove it
  192. rv = RemoveRedundantTrailingBR();
  193. if (NS_FAILED(rv)) {
  194. return rv;
  195. }
  196. // detect empty doc
  197. rv = CreateBogusNodeIfNeeded(selection);
  198. NS_ENSURE_SUCCESS(rv, rv);
  199. // ensure trailing br node
  200. rv = CreateTrailingBRIfNeeded();
  201. NS_ENSURE_SUCCESS(rv, rv);
  202. // collapse the selection to the trailing BR if it's at the end of our text node
  203. CollapseSelectionToTrailingBRIfNeeded(selection);
  204. }
  205. return NS_OK;
  206. }
  207. NS_IMETHODIMP
  208. TextEditRules::WillDoAction(Selection* aSelection,
  209. RulesInfo* aInfo,
  210. bool* aCancel,
  211. bool* aHandled)
  212. {
  213. // null selection is legal
  214. MOZ_ASSERT(aInfo && aCancel && aHandled);
  215. *aCancel = false;
  216. *aHandled = false;
  217. // my kingdom for dynamic cast
  218. TextRulesInfo* info = static_cast<TextRulesInfo*>(aInfo);
  219. switch (info->action) {
  220. case EditAction::insertBreak:
  221. UndefineCaretBidiLevel(aSelection);
  222. return WillInsertBreak(aSelection, aCancel, aHandled, info->maxLength);
  223. case EditAction::insertText:
  224. case EditAction::insertIMEText:
  225. UndefineCaretBidiLevel(aSelection);
  226. return WillInsertText(info->action, aSelection, aCancel, aHandled,
  227. info->inString, info->outString, info->maxLength);
  228. case EditAction::deleteSelection:
  229. return WillDeleteSelection(aSelection, info->collapsedAction,
  230. aCancel, aHandled);
  231. case EditAction::undo:
  232. return WillUndo(aSelection, aCancel, aHandled);
  233. case EditAction::redo:
  234. return WillRedo(aSelection, aCancel, aHandled);
  235. case EditAction::setTextProperty:
  236. return WillSetTextProperty(aSelection, aCancel, aHandled);
  237. case EditAction::removeTextProperty:
  238. return WillRemoveTextProperty(aSelection, aCancel, aHandled);
  239. case EditAction::outputText:
  240. return WillOutputText(aSelection, info->outputFormat, info->outString,
  241. aCancel, aHandled);
  242. case EditAction::insertElement:
  243. // i had thought this would be html rules only. but we put pre elements
  244. // into plaintext mail when doing quoting for reply! doh!
  245. WillInsert(*aSelection, aCancel);
  246. return NS_OK;
  247. default:
  248. return NS_ERROR_FAILURE;
  249. }
  250. }
  251. NS_IMETHODIMP
  252. TextEditRules::DidDoAction(Selection* aSelection,
  253. RulesInfo* aInfo,
  254. nsresult aResult)
  255. {
  256. NS_ENSURE_STATE(mTextEditor);
  257. // don't let any txns in here move the selection around behind our back.
  258. // Note that this won't prevent explicit selection setting from working.
  259. AutoTransactionsConserveSelection dontSpazMySelection(mTextEditor);
  260. NS_ENSURE_TRUE(aSelection && aInfo, NS_ERROR_NULL_POINTER);
  261. // my kingdom for dynamic cast
  262. TextRulesInfo* info = static_cast<TextRulesInfo*>(aInfo);
  263. switch (info->action) {
  264. case EditAction::insertBreak:
  265. return DidInsertBreak(aSelection, aResult);
  266. case EditAction::insertText:
  267. case EditAction::insertIMEText:
  268. return DidInsertText(aSelection, aResult);
  269. case EditAction::deleteSelection:
  270. return DidDeleteSelection(aSelection, info->collapsedAction, aResult);
  271. case EditAction::undo:
  272. return DidUndo(aSelection, aResult);
  273. case EditAction::redo:
  274. return DidRedo(aSelection, aResult);
  275. case EditAction::setTextProperty:
  276. return DidSetTextProperty(aSelection, aResult);
  277. case EditAction::removeTextProperty:
  278. return DidRemoveTextProperty(aSelection, aResult);
  279. case EditAction::outputText:
  280. return DidOutputText(aSelection, aResult);
  281. default:
  282. // Don't fail on transactions we don't handle here!
  283. return NS_OK;
  284. }
  285. }
  286. NS_IMETHODIMP_(bool)
  287. TextEditRules::DocumentIsEmpty()
  288. {
  289. return (mBogusNode != nullptr);
  290. }
  291. void
  292. TextEditRules::WillInsert(Selection& aSelection, bool* aCancel)
  293. {
  294. MOZ_ASSERT(aCancel);
  295. if (IsReadonly() || IsDisabled()) {
  296. *aCancel = true;
  297. return;
  298. }
  299. // initialize out param
  300. *aCancel = false;
  301. // check for the magic content node and delete it if it exists
  302. if (mBogusNode) {
  303. NS_ENSURE_TRUE_VOID(mTextEditor);
  304. mTextEditor->DeleteNode(mBogusNode);
  305. mBogusNode = nullptr;
  306. }
  307. }
  308. nsresult
  309. TextEditRules::DidInsert(Selection* aSelection,
  310. nsresult aResult)
  311. {
  312. return NS_OK;
  313. }
  314. nsresult
  315. TextEditRules::WillInsertBreak(Selection* aSelection,
  316. bool* aCancel,
  317. bool* aHandled,
  318. int32_t aMaxLength)
  319. {
  320. if (!aSelection || !aCancel || !aHandled) {
  321. return NS_ERROR_NULL_POINTER;
  322. }
  323. CANCEL_OPERATION_IF_READONLY_OR_DISABLED
  324. *aHandled = false;
  325. if (IsSingleLineEditor()) {
  326. *aCancel = true;
  327. } else {
  328. // handle docs with a max length
  329. // NOTE, this function copies inString into outString for us.
  330. NS_NAMED_LITERAL_STRING(inString, "\n");
  331. nsAutoString outString;
  332. bool didTruncate;
  333. nsresult rv = TruncateInsertionIfNeeded(aSelection, &inString, &outString,
  334. aMaxLength, &didTruncate);
  335. NS_ENSURE_SUCCESS(rv, rv);
  336. if (didTruncate) {
  337. *aCancel = true;
  338. return NS_OK;
  339. }
  340. *aCancel = false;
  341. // if the selection isn't collapsed, delete it.
  342. bool bCollapsed;
  343. rv = aSelection->GetIsCollapsed(&bCollapsed);
  344. NS_ENSURE_SUCCESS(rv, rv);
  345. if (!bCollapsed) {
  346. NS_ENSURE_STATE(mTextEditor);
  347. rv = mTextEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
  348. NS_ENSURE_SUCCESS(rv, rv);
  349. }
  350. WillInsert(*aSelection, aCancel);
  351. // initialize out param
  352. // we want to ignore result of WillInsert()
  353. *aCancel = false;
  354. }
  355. return NS_OK;
  356. }
  357. nsresult
  358. TextEditRules::DidInsertBreak(Selection* aSelection,
  359. nsresult aResult)
  360. {
  361. return NS_OK;
  362. }
  363. nsresult
  364. TextEditRules::CollapseSelectionToTrailingBRIfNeeded(Selection* aSelection)
  365. {
  366. // we only need to execute the stuff below if we are a plaintext editor.
  367. // html editors have a different mechanism for putting in mozBR's
  368. // (because there are a bunch more places you have to worry about it in html)
  369. if (!IsPlaintextEditor()) {
  370. return NS_OK;
  371. }
  372. NS_ENSURE_STATE(mTextEditor);
  373. // If there is no selection ranges, we should set to the end of the editor.
  374. // This is usually performed in TextEditRules::Init(), however, if the
  375. // editor is reframed, this may be called by AfterEdit().
  376. if (!aSelection->RangeCount()) {
  377. mTextEditor->EndOfDocument();
  378. }
  379. // if we are at the end of the textarea, we need to set the
  380. // selection to stick to the mozBR at the end of the textarea.
  381. int32_t selOffset;
  382. nsCOMPtr<nsIDOMNode> selNode;
  383. nsresult rv =
  384. mTextEditor->GetStartNodeAndOffset(aSelection,
  385. getter_AddRefs(selNode), &selOffset);
  386. NS_ENSURE_SUCCESS(rv, rv);
  387. nsCOMPtr<nsIDOMText> nodeAsText = do_QueryInterface(selNode);
  388. if (!nodeAsText) {
  389. return NS_OK; // Nothing to do if we're not at a text node.
  390. }
  391. uint32_t length;
  392. rv = nodeAsText->GetLength(&length);
  393. NS_ENSURE_SUCCESS(rv, rv);
  394. // nothing to do if we're not at the end of the text node
  395. if (selOffset != int32_t(length)) {
  396. return NS_OK;
  397. }
  398. int32_t parentOffset;
  399. nsCOMPtr<nsIDOMNode> parentNode =
  400. EditorBase::GetNodeLocation(selNode, &parentOffset);
  401. NS_ENSURE_STATE(mTextEditor);
  402. nsCOMPtr<nsIDOMNode> root = do_QueryInterface(mTextEditor->GetRoot());
  403. NS_ENSURE_TRUE(root, NS_ERROR_NULL_POINTER);
  404. if (parentNode != root) {
  405. return NS_OK;
  406. }
  407. nsCOMPtr<nsIDOMNode> nextNode = mTextEditor->GetChildAt(parentNode,
  408. parentOffset + 1);
  409. if (nextNode && TextEditUtils::IsMozBR(nextNode)) {
  410. rv = aSelection->Collapse(parentNode, parentOffset + 1);
  411. NS_ENSURE_SUCCESS(rv, rv);
  412. }
  413. return NS_OK;
  414. }
  415. static inline already_AddRefed<nsINode>
  416. GetTextNode(Selection* selection)
  417. {
  418. int32_t selOffset;
  419. nsCOMPtr<nsINode> selNode;
  420. nsresult rv =
  421. EditorBase::GetStartNodeAndOffset(selection,
  422. getter_AddRefs(selNode), &selOffset);
  423. NS_ENSURE_SUCCESS(rv, nullptr);
  424. if (!EditorBase::IsTextNode(selNode)) {
  425. // This should be the root node, walk the tree looking for text nodes
  426. RefPtr<NodeIterator> iter =
  427. new NodeIterator(selNode, nsIDOMNodeFilter::SHOW_TEXT,
  428. NodeFilterHolder());
  429. while (!EditorBase::IsTextNode(selNode)) {
  430. IgnoredErrorResult rv;
  431. selNode = iter->NextNode(rv);
  432. if (!selNode) {
  433. return nullptr;
  434. }
  435. }
  436. }
  437. return selNode.forget();
  438. }
  439. #ifdef DEBUG
  440. #define ASSERT_PASSWORD_LENGTHS_EQUAL() \
  441. if (IsPasswordEditor() && mTextEditor->GetRoot()) { \
  442. int32_t txtLen; \
  443. mTextEditor->GetTextLength(&txtLen); \
  444. NS_ASSERTION(mPasswordText.Length() == uint32_t(txtLen), \
  445. "password length not equal to number of asterisks"); \
  446. }
  447. #else
  448. #define ASSERT_PASSWORD_LENGTHS_EQUAL()
  449. #endif
  450. // static
  451. void
  452. TextEditRules::HandleNewLines(nsString& aString,
  453. int32_t aNewlineHandling)
  454. {
  455. if (aNewlineHandling < 0) {
  456. int32_t caretStyle;
  457. TextEditor::GetDefaultEditorPrefs(aNewlineHandling, caretStyle);
  458. }
  459. switch(aNewlineHandling) {
  460. case nsIPlaintextEditor::eNewlinesReplaceWithSpaces:
  461. // Strip trailing newlines first so we don't wind up with trailing spaces
  462. aString.Trim(CRLF, false, true);
  463. aString.ReplaceChar(CRLF, ' ');
  464. break;
  465. case nsIPlaintextEditor::eNewlinesStrip:
  466. aString.StripChars(CRLF);
  467. break;
  468. case nsIPlaintextEditor::eNewlinesPasteToFirst:
  469. default: {
  470. int32_t firstCRLF = aString.FindCharInSet(CRLF);
  471. // we get first *non-empty* line.
  472. int32_t offset = 0;
  473. while (firstCRLF == offset) {
  474. offset++;
  475. firstCRLF = aString.FindCharInSet(CRLF, offset);
  476. }
  477. if (firstCRLF > 0) {
  478. aString.Truncate(firstCRLF);
  479. }
  480. if (offset > 0) {
  481. aString.Cut(0, offset);
  482. }
  483. break;
  484. }
  485. case nsIPlaintextEditor::eNewlinesReplaceWithCommas:
  486. aString.Trim(CRLF, true, true);
  487. aString.ReplaceChar(CRLF, ',');
  488. break;
  489. case nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace: {
  490. nsAutoString result;
  491. uint32_t offset = 0;
  492. while (offset < aString.Length()) {
  493. int32_t nextCRLF = aString.FindCharInSet(CRLF, offset);
  494. if (nextCRLF < 0) {
  495. result.Append(nsDependentSubstring(aString, offset));
  496. break;
  497. }
  498. uint32_t wsBegin = nextCRLF;
  499. // look backwards for the first non-whitespace char
  500. while (wsBegin > offset && NS_IS_SPACE(aString[wsBegin - 1])) {
  501. --wsBegin;
  502. }
  503. result.Append(nsDependentSubstring(aString, offset, wsBegin - offset));
  504. offset = nextCRLF + 1;
  505. while (offset < aString.Length() && NS_IS_SPACE(aString[offset])) {
  506. ++offset;
  507. }
  508. }
  509. aString = result;
  510. break;
  511. }
  512. case nsIPlaintextEditor::eNewlinesPasteIntact:
  513. // even if we're pasting newlines, don't paste leading/trailing ones
  514. aString.Trim(CRLF, true, true);
  515. break;
  516. }
  517. }
  518. nsresult
  519. TextEditRules::WillInsertText(EditAction aAction,
  520. Selection* aSelection,
  521. bool* aCancel,
  522. bool* aHandled,
  523. const nsAString* inString,
  524. nsAString* outString,
  525. int32_t aMaxLength)
  526. {
  527. if (!aSelection || !aCancel || !aHandled) {
  528. return NS_ERROR_NULL_POINTER;
  529. }
  530. if (inString->IsEmpty() && aAction != EditAction::insertIMEText) {
  531. // HACK: this is a fix for bug 19395
  532. // I can't outlaw all empty insertions
  533. // because IME transaction depend on them
  534. // There is more work to do to make the
  535. // world safe for IME.
  536. *aCancel = true;
  537. *aHandled = false;
  538. return NS_OK;
  539. }
  540. // initialize out param
  541. *aCancel = false;
  542. *aHandled = true;
  543. // handle docs with a max length
  544. // NOTE, this function copies inString into outString for us.
  545. bool truncated = false;
  546. nsresult rv = TruncateInsertionIfNeeded(aSelection, inString, outString,
  547. aMaxLength, &truncated);
  548. NS_ENSURE_SUCCESS(rv, rv);
  549. // If we're exceeding the maxlength when composing IME, we need to clean up
  550. // the composing text, so we shouldn't return early.
  551. if (truncated && outString->IsEmpty() &&
  552. aAction != EditAction::insertIMEText) {
  553. *aCancel = true;
  554. return NS_OK;
  555. }
  556. int32_t start = 0;
  557. int32_t end = 0;
  558. // handle password field docs
  559. if (IsPasswordEditor()) {
  560. NS_ENSURE_STATE(mTextEditor);
  561. nsContentUtils::GetSelectionInTextControl(aSelection,
  562. mTextEditor->GetRoot(),
  563. start, end);
  564. }
  565. // if the selection isn't collapsed, delete it.
  566. bool bCollapsed;
  567. rv = aSelection->GetIsCollapsed(&bCollapsed);
  568. NS_ENSURE_SUCCESS(rv, rv);
  569. if (!bCollapsed) {
  570. NS_ENSURE_STATE(mTextEditor);
  571. rv = mTextEditor->DeleteSelection(nsIEditor::eNone, nsIEditor::eStrip);
  572. NS_ENSURE_SUCCESS(rv, rv);
  573. }
  574. WillInsert(*aSelection, aCancel);
  575. // initialize out param
  576. // we want to ignore result of WillInsert()
  577. *aCancel = false;
  578. // handle password field data
  579. // this has the side effect of changing all the characters in aOutString
  580. // to the replacement character
  581. if (IsPasswordEditor() &&
  582. aAction == EditAction::insertIMEText) {
  583. RemoveIMETextFromPWBuf(start, outString);
  584. }
  585. // People have lots of different ideas about what text fields
  586. // should do with multiline pastes. See bugs 21032, 23485, 23485, 50935.
  587. // The six possible options are:
  588. // 0. paste newlines intact
  589. // 1. paste up to the first newline (default)
  590. // 2. replace newlines with spaces
  591. // 3. strip newlines
  592. // 4. replace with commas
  593. // 5. strip newlines and surrounding whitespace
  594. // So find out what we're expected to do:
  595. if (IsSingleLineEditor()) {
  596. nsAutoString tString(*outString);
  597. NS_ENSURE_STATE(mTextEditor);
  598. HandleNewLines(tString, mTextEditor->mNewlineHandling);
  599. outString->Assign(tString);
  600. }
  601. if (IsPasswordEditor()) {
  602. // manage the password buffer
  603. mPasswordText.Insert(*outString, start);
  604. if (LookAndFeel::GetEchoPassword() && !DontEchoPassword()) {
  605. HideLastPWInput();
  606. mLastStart = start;
  607. mLastLength = outString->Length();
  608. if (mTimer) {
  609. mTimer->Cancel();
  610. } else {
  611. mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  612. NS_ENSURE_SUCCESS(rv, rv);
  613. }
  614. mTimer->InitWithCallback(this, LookAndFeel::GetPasswordMaskDelay(),
  615. nsITimer::TYPE_ONE_SHOT);
  616. } else {
  617. FillBufWithPWChars(outString, outString->Length());
  618. }
  619. }
  620. // get the (collapsed) selection location
  621. NS_ENSURE_STATE(aSelection->GetRangeAt(0));
  622. nsCOMPtr<nsINode> selNode = aSelection->GetRangeAt(0)->GetStartParent();
  623. int32_t selOffset = aSelection->GetRangeAt(0)->StartOffset();
  624. NS_ENSURE_STATE(selNode);
  625. // don't put text in places that can't have it
  626. NS_ENSURE_STATE(mTextEditor);
  627. if (!mTextEditor->IsTextNode(selNode) &&
  628. !mTextEditor->CanContainTag(*selNode, *nsGkAtoms::textTagName)) {
  629. return NS_ERROR_FAILURE;
  630. }
  631. // we need to get the doc
  632. NS_ENSURE_STATE(mTextEditor);
  633. nsCOMPtr<nsIDocument> doc = mTextEditor->GetDocument();
  634. NS_ENSURE_TRUE(doc, NS_ERROR_NOT_INITIALIZED);
  635. if (aAction == EditAction::insertIMEText) {
  636. NS_ENSURE_STATE(mTextEditor);
  637. // Find better insertion point to insert text.
  638. mTextEditor->FindBetterInsertionPoint(selNode, selOffset);
  639. // If there is one or more IME selections, its minimum offset should be
  640. // the insertion point.
  641. int32_t IMESelectionOffset =
  642. mTextEditor->GetIMESelectionStartOffsetIn(selNode);
  643. if (IMESelectionOffset >= 0) {
  644. selOffset = IMESelectionOffset;
  645. }
  646. rv = mTextEditor->InsertTextImpl(*outString, address_of(selNode),
  647. &selOffset, doc);
  648. NS_ENSURE_SUCCESS(rv, rv);
  649. } else {
  650. // aAction == EditAction::insertText; find where we are
  651. nsCOMPtr<nsINode> curNode = selNode;
  652. int32_t curOffset = selOffset;
  653. // don't spaz my selection in subtransactions
  654. NS_ENSURE_STATE(mTextEditor);
  655. AutoTransactionsConserveSelection dontSpazMySelection(mTextEditor);
  656. rv = mTextEditor->InsertTextImpl(*outString, address_of(curNode),
  657. &curOffset, doc);
  658. NS_ENSURE_SUCCESS(rv, rv);
  659. if (curNode) {
  660. // Make the caret attach to the inserted text, unless this text ends with a LF,
  661. // in which case make the caret attach to the next line.
  662. bool endsWithLF =
  663. !outString->IsEmpty() && outString->Last() == nsCRT::LF;
  664. aSelection->SetInterlinePosition(endsWithLF);
  665. aSelection->Collapse(curNode, curOffset);
  666. }
  667. }
  668. ASSERT_PASSWORD_LENGTHS_EQUAL()
  669. return NS_OK;
  670. }
  671. nsresult
  672. TextEditRules::DidInsertText(Selection* aSelection,
  673. nsresult aResult)
  674. {
  675. return DidInsert(aSelection, aResult);
  676. }
  677. nsresult
  678. TextEditRules::WillSetTextProperty(Selection* aSelection,
  679. bool* aCancel,
  680. bool* aHandled)
  681. {
  682. if (!aSelection || !aCancel || !aHandled) {
  683. return NS_ERROR_NULL_POINTER;
  684. }
  685. // XXX: should probably return a success value other than NS_OK that means "not allowed"
  686. if (IsPlaintextEditor()) {
  687. *aCancel = true;
  688. }
  689. return NS_OK;
  690. }
  691. nsresult
  692. TextEditRules::DidSetTextProperty(Selection* aSelection,
  693. nsresult aResult)
  694. {
  695. return NS_OK;
  696. }
  697. nsresult
  698. TextEditRules::WillRemoveTextProperty(Selection* aSelection,
  699. bool* aCancel,
  700. bool* aHandled)
  701. {
  702. if (!aSelection || !aCancel || !aHandled) {
  703. return NS_ERROR_NULL_POINTER;
  704. }
  705. // XXX: should probably return a success value other than NS_OK that means "not allowed"
  706. if (IsPlaintextEditor()) {
  707. *aCancel = true;
  708. }
  709. return NS_OK;
  710. }
  711. nsresult
  712. TextEditRules::DidRemoveTextProperty(Selection* aSelection,
  713. nsresult aResult)
  714. {
  715. return NS_OK;
  716. }
  717. nsresult
  718. TextEditRules::WillDeleteSelection(Selection* aSelection,
  719. nsIEditor::EDirection aCollapsedAction,
  720. bool* aCancel,
  721. bool* aHandled)
  722. {
  723. if (!aSelection || !aCancel || !aHandled) {
  724. return NS_ERROR_NULL_POINTER;
  725. }
  726. CANCEL_OPERATION_IF_READONLY_OR_DISABLED
  727. // initialize out param
  728. *aCancel = false;
  729. *aHandled = false;
  730. // if there is only bogus content, cancel the operation
  731. if (mBogusNode) {
  732. *aCancel = true;
  733. return NS_OK;
  734. }
  735. // If the current selection is empty (e.g the user presses backspace with
  736. // a collapsed selection), then we want to avoid sending the selectstart
  737. // event to the user, so we hide selection changes. However, we still
  738. // want to send a single selectionchange event to the document, so we
  739. // batch the selectionchange events, such that a single event fires after
  740. // the AutoHideSelectionChanges destructor has been run.
  741. SelectionBatcher selectionBatcher(aSelection);
  742. AutoHideSelectionChanges hideSelection(aSelection);
  743. nsAutoScriptBlocker scriptBlocker;
  744. if (IsPasswordEditor()) {
  745. NS_ENSURE_STATE(mTextEditor);
  746. nsresult rv =
  747. mTextEditor->ExtendSelectionForDelete(aSelection, &aCollapsedAction);
  748. NS_ENSURE_SUCCESS(rv, rv);
  749. // manage the password buffer
  750. int32_t start, end;
  751. nsContentUtils::GetSelectionInTextControl(aSelection,
  752. mTextEditor->GetRoot(),
  753. start, end);
  754. if (LookAndFeel::GetEchoPassword()) {
  755. HideLastPWInput();
  756. mLastStart = start;
  757. mLastLength = 0;
  758. if (mTimer) {
  759. mTimer->Cancel();
  760. }
  761. }
  762. // Collapsed selection.
  763. if (end == start) {
  764. // Deleting back.
  765. if (nsIEditor::ePrevious == aCollapsedAction && 0<start) {
  766. mPasswordText.Cut(start-1, 1);
  767. }
  768. // Deleting forward.
  769. else if (nsIEditor::eNext == aCollapsedAction) {
  770. mPasswordText.Cut(start, 1);
  771. }
  772. // Otherwise nothing to do for this collapsed selection.
  773. }
  774. // Extended selection.
  775. else {
  776. mPasswordText.Cut(start, end-start);
  777. }
  778. } else {
  779. nsCOMPtr<nsIDOMNode> startNode;
  780. int32_t startOffset;
  781. NS_ENSURE_STATE(mTextEditor);
  782. nsresult rv =
  783. mTextEditor->GetStartNodeAndOffset(aSelection, getter_AddRefs(startNode),
  784. &startOffset);
  785. NS_ENSURE_SUCCESS(rv, rv);
  786. NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
  787. bool bCollapsed;
  788. rv = aSelection->GetIsCollapsed(&bCollapsed);
  789. NS_ENSURE_SUCCESS(rv, rv);
  790. if (!bCollapsed) {
  791. return NS_OK;
  792. }
  793. // Test for distance between caret and text that will be deleted
  794. rv = CheckBidiLevelForDeletion(aSelection, startNode, startOffset,
  795. aCollapsedAction, aCancel);
  796. NS_ENSURE_SUCCESS(rv, rv);
  797. if (*aCancel) {
  798. return NS_OK;
  799. }
  800. NS_ENSURE_STATE(mTextEditor);
  801. rv = mTextEditor->ExtendSelectionForDelete(aSelection, &aCollapsedAction);
  802. NS_ENSURE_SUCCESS(rv, rv);
  803. }
  804. NS_ENSURE_STATE(mTextEditor);
  805. nsresult rv =
  806. mTextEditor->DeleteSelectionImpl(aCollapsedAction, nsIEditor::eStrip);
  807. NS_ENSURE_SUCCESS(rv, rv);
  808. *aHandled = true;
  809. ASSERT_PASSWORD_LENGTHS_EQUAL()
  810. return NS_OK;
  811. }
  812. nsresult
  813. TextEditRules::DidDeleteSelection(Selection* aSelection,
  814. nsIEditor::EDirection aCollapsedAction,
  815. nsresult aResult)
  816. {
  817. nsCOMPtr<nsIDOMNode> startNode;
  818. int32_t startOffset;
  819. NS_ENSURE_STATE(mTextEditor);
  820. nsresult rv =
  821. mTextEditor->GetStartNodeAndOffset(aSelection,
  822. getter_AddRefs(startNode), &startOffset);
  823. NS_ENSURE_SUCCESS(rv, rv);
  824. NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
  825. // delete empty text nodes at selection
  826. if (mTextEditor->IsTextNode(startNode)) {
  827. nsCOMPtr<nsIDOMText> textNode = do_QueryInterface(startNode);
  828. uint32_t strLength;
  829. rv = textNode->GetLength(&strLength);
  830. NS_ENSURE_SUCCESS(rv, rv);
  831. // are we in an empty text node?
  832. if (!strLength) {
  833. rv = mTextEditor->DeleteNode(startNode);
  834. NS_ENSURE_SUCCESS(rv, rv);
  835. }
  836. }
  837. if (mDidExplicitlySetInterline) {
  838. return NS_OK;
  839. }
  840. // We prevent the caret from sticking on the left of prior BR
  841. // (i.e. the end of previous line) after this deletion. Bug 92124
  842. return aSelection->SetInterlinePosition(true);
  843. }
  844. nsresult
  845. TextEditRules::WillUndo(Selection* aSelection,
  846. bool* aCancel,
  847. bool* aHandled)
  848. {
  849. if (!aSelection || !aCancel || !aHandled) {
  850. return NS_ERROR_NULL_POINTER;
  851. }
  852. CANCEL_OPERATION_IF_READONLY_OR_DISABLED
  853. // initialize out param
  854. *aCancel = false;
  855. *aHandled = false;
  856. return NS_OK;
  857. }
  858. /**
  859. * The idea here is to see if the magic empty node has suddenly reappeared as
  860. * the result of the undo. If it has, set our state so we remember it.
  861. * There is a tradeoff between doing here and at redo, or doing it everywhere
  862. * else that might care. Since undo and redo are relatively rare, it makes
  863. * sense to take the (small) performance hit here.
  864. */
  865. nsresult
  866. TextEditRules::DidUndo(Selection* aSelection,
  867. nsresult aResult)
  868. {
  869. NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
  870. // If aResult is an error, we return it.
  871. NS_ENSURE_SUCCESS(aResult, aResult);
  872. NS_ENSURE_STATE(mTextEditor);
  873. dom::Element* theRoot = mTextEditor->GetRoot();
  874. NS_ENSURE_TRUE(theRoot, NS_ERROR_FAILURE);
  875. nsIContent* node = mTextEditor->GetLeftmostChild(theRoot);
  876. if (node && mTextEditor->IsMozEditorBogusNode(node)) {
  877. mBogusNode = do_QueryInterface(node);
  878. } else {
  879. mBogusNode = nullptr;
  880. }
  881. return aResult;
  882. }
  883. nsresult
  884. TextEditRules::WillRedo(Selection* aSelection,
  885. bool* aCancel,
  886. bool* aHandled)
  887. {
  888. if (!aSelection || !aCancel || !aHandled) {
  889. return NS_ERROR_NULL_POINTER;
  890. }
  891. CANCEL_OPERATION_IF_READONLY_OR_DISABLED
  892. // initialize out param
  893. *aCancel = false;
  894. *aHandled = false;
  895. return NS_OK;
  896. }
  897. nsresult
  898. TextEditRules::DidRedo(Selection* aSelection,
  899. nsresult aResult)
  900. {
  901. if (!aSelection) {
  902. return NS_ERROR_NULL_POINTER;
  903. }
  904. if (NS_FAILED(aResult)) {
  905. return aResult; // if aResult is an error, we return it.
  906. }
  907. NS_ENSURE_STATE(mTextEditor);
  908. nsCOMPtr<nsIDOMElement> theRoot = do_QueryInterface(mTextEditor->GetRoot());
  909. NS_ENSURE_TRUE(theRoot, NS_ERROR_FAILURE);
  910. nsCOMPtr<nsIDOMHTMLCollection> nodeList;
  911. nsresult rv = theRoot->GetElementsByTagName(NS_LITERAL_STRING("br"),
  912. getter_AddRefs(nodeList));
  913. NS_ENSURE_SUCCESS(rv, rv);
  914. if (nodeList) {
  915. uint32_t len;
  916. nodeList->GetLength(&len);
  917. if (len != 1) {
  918. // only in the case of one br could there be the bogus node
  919. mBogusNode = nullptr;
  920. return NS_OK;
  921. }
  922. nsCOMPtr<nsIDOMNode> node;
  923. nodeList->Item(0, getter_AddRefs(node));
  924. nsCOMPtr<nsIContent> content = do_QueryInterface(node);
  925. MOZ_ASSERT(content);
  926. if (mTextEditor->IsMozEditorBogusNode(content)) {
  927. mBogusNode = node;
  928. } else {
  929. mBogusNode = nullptr;
  930. }
  931. }
  932. return NS_OK;
  933. }
  934. nsresult
  935. TextEditRules::WillOutputText(Selection* aSelection,
  936. const nsAString* aOutputFormat,
  937. nsAString* aOutString,
  938. bool* aCancel,
  939. bool* aHandled)
  940. {
  941. // null selection ok
  942. if (!aOutString || !aOutputFormat || !aCancel || !aHandled) {
  943. return NS_ERROR_NULL_POINTER;
  944. }
  945. // initialize out param
  946. *aCancel = false;
  947. *aHandled = false;
  948. nsAutoString outputFormat(*aOutputFormat);
  949. ToLowerCase(outputFormat);
  950. if (outputFormat.EqualsLiteral("text/plain")) {
  951. // Only use these rules for plain text output.
  952. if (IsPasswordEditor()) {
  953. *aOutString = mPasswordText;
  954. *aHandled = true;
  955. } else if (mBogusNode) {
  956. // This means there's no content, so output null string.
  957. aOutString->Truncate();
  958. *aHandled = true;
  959. }
  960. }
  961. return NS_OK;
  962. }
  963. nsresult
  964. TextEditRules::DidOutputText(Selection* aSelection,
  965. nsresult aResult)
  966. {
  967. return NS_OK;
  968. }
  969. nsresult
  970. TextEditRules::RemoveRedundantTrailingBR()
  971. {
  972. // If the bogus node exists, we have no work to do
  973. if (mBogusNode) {
  974. return NS_OK;
  975. }
  976. // Likewise, nothing to be done if we could never have inserted a trailing br
  977. if (IsSingleLineEditor()) {
  978. return NS_OK;
  979. }
  980. NS_ENSURE_STATE(mTextEditor);
  981. RefPtr<dom::Element> body = mTextEditor->GetRoot();
  982. if (!body) {
  983. return NS_ERROR_NULL_POINTER;
  984. }
  985. uint32_t childCount = body->GetChildCount();
  986. if (childCount > 1) {
  987. // The trailing br is redundant if it is the only remaining child node
  988. return NS_OK;
  989. }
  990. RefPtr<nsIContent> child = body->GetFirstChild();
  991. if (!child || !child->IsElement()) {
  992. return NS_OK;
  993. }
  994. dom::Element* elem = child->AsElement();
  995. if (!TextEditUtils::IsMozBR(elem)) {
  996. return NS_OK;
  997. }
  998. // Rather than deleting this node from the DOM tree we should instead
  999. // morph this br into the bogus node
  1000. elem->UnsetAttr(kNameSpaceID_None, nsGkAtoms::type, true);
  1001. // set mBogusNode to be this <br>
  1002. mBogusNode = do_QueryInterface(elem);
  1003. // give it the bogus node attribute
  1004. elem->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
  1005. kMOZEditorBogusNodeValue, false);
  1006. return NS_OK;
  1007. }
  1008. nsresult
  1009. TextEditRules::CreateTrailingBRIfNeeded()
  1010. {
  1011. // but only if we aren't a single line edit field
  1012. if (IsSingleLineEditor()) {
  1013. return NS_OK;
  1014. }
  1015. NS_ENSURE_STATE(mTextEditor);
  1016. dom::Element* body = mTextEditor->GetRoot();
  1017. NS_ENSURE_TRUE(body, NS_ERROR_NULL_POINTER);
  1018. nsIContent* lastChild = body->GetLastChild();
  1019. // assuming CreateBogusNodeIfNeeded() has been called first
  1020. NS_ENSURE_TRUE(lastChild, NS_ERROR_NULL_POINTER);
  1021. if (!lastChild->IsHTMLElement(nsGkAtoms::br)) {
  1022. AutoTransactionsConserveSelection dontSpazMySelection(mTextEditor);
  1023. nsCOMPtr<nsIDOMNode> domBody = do_QueryInterface(body);
  1024. return CreateMozBR(domBody, body->Length());
  1025. }
  1026. // Check to see if the trailing BR is a former bogus node - this will have
  1027. // stuck around if we previously morphed a trailing node into a bogus node.
  1028. if (!mTextEditor->IsMozEditorBogusNode(lastChild)) {
  1029. return NS_OK;
  1030. }
  1031. // Morph it back to a mozBR
  1032. lastChild->UnsetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom, false);
  1033. lastChild->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
  1034. NS_LITERAL_STRING("_moz"), true);
  1035. return NS_OK;
  1036. }
  1037. nsresult
  1038. TextEditRules::CreateBogusNodeIfNeeded(Selection* aSelection)
  1039. {
  1040. NS_ENSURE_TRUE(aSelection, NS_ERROR_NULL_POINTER);
  1041. NS_ENSURE_TRUE(mTextEditor, NS_ERROR_NULL_POINTER);
  1042. if (mBogusNode) {
  1043. // Let's not create more than one, ok?
  1044. return NS_OK;
  1045. }
  1046. // tell rules system to not do any post-processing
  1047. AutoRules beginRulesSniffing(mTextEditor, EditAction::ignore,
  1048. nsIEditor::eNone);
  1049. nsCOMPtr<dom::Element> body = mTextEditor->GetRoot();
  1050. if (!body) {
  1051. // We don't even have a body yet, don't insert any bogus nodes at
  1052. // this point.
  1053. return NS_OK;
  1054. }
  1055. // Now we've got the body element. Iterate over the body element's children,
  1056. // looking for editable content. If no editable content is found, insert the
  1057. // bogus node.
  1058. for (nsCOMPtr<nsIContent> bodyChild = body->GetFirstChild();
  1059. bodyChild;
  1060. bodyChild = bodyChild->GetNextSibling()) {
  1061. if (mTextEditor->IsMozEditorBogusNode(bodyChild) ||
  1062. !mTextEditor->IsEditable(body) || // XXX hoist out of the loop?
  1063. mTextEditor->IsEditable(bodyChild) ||
  1064. mTextEditor->IsBlockNode(bodyChild)) {
  1065. return NS_OK;
  1066. }
  1067. }
  1068. // Skip adding the bogus node if body is read-only.
  1069. if (!mTextEditor->IsModifiableNode(body)) {
  1070. return NS_OK;
  1071. }
  1072. // Create a br.
  1073. nsCOMPtr<Element> newContent = mTextEditor->CreateHTMLContent(nsGkAtoms::br);
  1074. NS_ENSURE_STATE(newContent);
  1075. // set mBogusNode to be the newly created <br>
  1076. mBogusNode = do_QueryInterface(newContent);
  1077. NS_ENSURE_TRUE(mBogusNode, NS_ERROR_NULL_POINTER);
  1078. // Give it a special attribute.
  1079. newContent->SetAttr(kNameSpaceID_None, kMOZEditorBogusNodeAttrAtom,
  1080. kMOZEditorBogusNodeValue, false);
  1081. // Put the node in the document.
  1082. nsCOMPtr<nsIDOMNode> bodyNode = do_QueryInterface(body);
  1083. nsresult rv = mTextEditor->InsertNode(mBogusNode, bodyNode, 0);
  1084. NS_ENSURE_SUCCESS(rv, rv);
  1085. // Set selection.
  1086. aSelection->CollapseNative(body, 0);
  1087. return NS_OK;
  1088. }
  1089. nsresult
  1090. TextEditRules::TruncateInsertionIfNeeded(Selection* aSelection,
  1091. const nsAString* aInString,
  1092. nsAString* aOutString,
  1093. int32_t aMaxLength,
  1094. bool* aTruncated)
  1095. {
  1096. if (!aSelection || !aInString || !aOutString) {
  1097. return NS_ERROR_NULL_POINTER;
  1098. }
  1099. if (!aOutString->Assign(*aInString, mozilla::fallible)) {
  1100. return NS_ERROR_OUT_OF_MEMORY;
  1101. }
  1102. if (aTruncated) {
  1103. *aTruncated = false;
  1104. }
  1105. NS_ENSURE_STATE(mTextEditor);
  1106. if (-1 != aMaxLength && IsPlaintextEditor() &&
  1107. !mTextEditor->IsIMEComposing()) {
  1108. // Get the current text length.
  1109. // Get the length of inString.
  1110. // Get the length of the selection.
  1111. // If selection is collapsed, it is length 0.
  1112. // Subtract the length of the selection from the len(doc)
  1113. // since we'll delete the selection on insert.
  1114. // This is resultingDocLength.
  1115. // Get old length of IME composing string
  1116. // which will be replaced by new one.
  1117. // If (resultingDocLength) is at or over max, cancel the insert
  1118. // If (resultingDocLength) + (length of input) > max,
  1119. // set aOutString to subset of inString so length = max
  1120. int32_t docLength;
  1121. nsresult rv = mTextEditor->GetTextLength(&docLength);
  1122. if (NS_FAILED(rv)) {
  1123. return rv;
  1124. }
  1125. int32_t start, end;
  1126. nsContentUtils::GetSelectionInTextControl(aSelection,
  1127. mTextEditor->GetRoot(),
  1128. start, end);
  1129. TextComposition* composition = mTextEditor->GetComposition();
  1130. int32_t oldCompStrLength = composition ? composition->String().Length() : 0;
  1131. const int32_t selectionLength = end - start;
  1132. const int32_t resultingDocLength = docLength - selectionLength - oldCompStrLength;
  1133. if (resultingDocLength >= aMaxLength) {
  1134. // This call is guaranteed to reduce the capacity of the string, so it
  1135. // cannot cause an OOM.
  1136. aOutString->Truncate();
  1137. if (aTruncated) {
  1138. *aTruncated = true;
  1139. }
  1140. } else {
  1141. int32_t oldLength = aOutString->Length();
  1142. if (oldLength + resultingDocLength > aMaxLength) {
  1143. int32_t newLength = aMaxLength - resultingDocLength;
  1144. MOZ_ASSERT(newLength > 0);
  1145. char16_t newLastChar = aOutString->CharAt(newLength - 1);
  1146. char16_t removingFirstChar = aOutString->CharAt(newLength);
  1147. // Don't separate the string between a surrogate pair.
  1148. if (NS_IS_HIGH_SURROGATE(newLastChar) &&
  1149. NS_IS_LOW_SURROGATE(removingFirstChar)) {
  1150. newLength--;
  1151. }
  1152. // XXX What should we do if we're removing IVS and its preceding
  1153. // character won't be removed?
  1154. // This call is guaranteed to reduce the capacity of the string, so it
  1155. // cannot cause an OOM.
  1156. aOutString->Truncate(newLength);
  1157. if (aTruncated) {
  1158. *aTruncated = true;
  1159. }
  1160. }
  1161. }
  1162. }
  1163. return NS_OK;
  1164. }
  1165. void
  1166. TextEditRules::ResetIMETextPWBuf()
  1167. {
  1168. mPasswordIMEText.Truncate();
  1169. }
  1170. void
  1171. TextEditRules::RemoveIMETextFromPWBuf(int32_t& aStart,
  1172. nsAString* aIMEString)
  1173. {
  1174. MOZ_ASSERT(aIMEString);
  1175. // initialize PasswordIME
  1176. if (mPasswordIMEText.IsEmpty()) {
  1177. mPasswordIMEIndex = aStart;
  1178. } else {
  1179. // manage the password buffer
  1180. mPasswordText.Cut(mPasswordIMEIndex, mPasswordIMEText.Length());
  1181. aStart = mPasswordIMEIndex;
  1182. }
  1183. mPasswordIMEText.Assign(*aIMEString);
  1184. }
  1185. NS_IMETHODIMP
  1186. TextEditRules::Notify(nsITimer* aTimer)
  1187. {
  1188. MOZ_ASSERT(mTimer);
  1189. // Check whether our text editor's password flag was changed before this
  1190. // "hide password character" timer actually fires.
  1191. nsresult rv = IsPasswordEditor() ? HideLastPWInput() : NS_OK;
  1192. ASSERT_PASSWORD_LENGTHS_EQUAL();
  1193. mLastLength = 0;
  1194. return rv;
  1195. }
  1196. nsresult
  1197. TextEditRules::HideLastPWInput()
  1198. {
  1199. if (!mLastLength) {
  1200. // Special case, we're trying to replace a range that no longer exists
  1201. return NS_OK;
  1202. }
  1203. nsAutoString hiddenText;
  1204. FillBufWithPWChars(&hiddenText, mLastLength);
  1205. NS_ENSURE_STATE(mTextEditor);
  1206. RefPtr<Selection> selection = mTextEditor->GetSelection();
  1207. NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
  1208. int32_t start, end;
  1209. nsContentUtils::GetSelectionInTextControl(selection, mTextEditor->GetRoot(),
  1210. start, end);
  1211. nsCOMPtr<nsINode> selNode = GetTextNode(selection);
  1212. NS_ENSURE_TRUE(selNode, NS_OK);
  1213. selNode->GetAsText()->ReplaceData(mLastStart, mLastLength, hiddenText);
  1214. selection->Collapse(selNode, start);
  1215. if (start != end) {
  1216. selection->Extend(selNode, end);
  1217. }
  1218. return NS_OK;
  1219. }
  1220. // static
  1221. void
  1222. TextEditRules::FillBufWithPWChars(nsAString* aOutString,
  1223. int32_t aLength)
  1224. {
  1225. MOZ_ASSERT(aOutString);
  1226. // change the output to the platform password character
  1227. char16_t passwordChar = LookAndFeel::GetPasswordCharacter();
  1228. aOutString->Truncate();
  1229. for (int32_t i = 0; i < aLength; i++) {
  1230. aOutString->Append(passwordChar);
  1231. }
  1232. }
  1233. /**
  1234. * CreateMozBR() puts a BR node with moz attribute at {inParent, inOffset}.
  1235. */
  1236. nsresult
  1237. TextEditRules::CreateMozBR(nsIDOMNode* inParent,
  1238. int32_t inOffset,
  1239. nsIDOMNode** outBRNode)
  1240. {
  1241. NS_ENSURE_TRUE(inParent, NS_ERROR_NULL_POINTER);
  1242. nsCOMPtr<nsIDOMNode> brNode;
  1243. NS_ENSURE_STATE(mTextEditor);
  1244. nsresult rv = mTextEditor->CreateBR(inParent, inOffset, address_of(brNode));
  1245. NS_ENSURE_SUCCESS(rv, rv);
  1246. // give it special moz attr
  1247. nsCOMPtr<Element> brElem = do_QueryInterface(brNode);
  1248. if (brElem) {
  1249. rv = mTextEditor->SetAttribute(brElem, nsGkAtoms::type,
  1250. NS_LITERAL_STRING("_moz"));
  1251. NS_ENSURE_SUCCESS(rv, rv);
  1252. }
  1253. if (outBRNode) {
  1254. brNode.forget(outBRNode);
  1255. }
  1256. return NS_OK;
  1257. }
  1258. NS_IMETHODIMP
  1259. TextEditRules::DocumentModified()
  1260. {
  1261. return NS_ERROR_NOT_IMPLEMENTED;
  1262. }
  1263. bool
  1264. TextEditRules::IsPasswordEditor() const
  1265. {
  1266. return mTextEditor ? mTextEditor->IsPasswordEditor() : false;
  1267. }
  1268. bool
  1269. TextEditRules::IsSingleLineEditor() const
  1270. {
  1271. return mTextEditor ? mTextEditor->IsSingleLineEditor() : false;
  1272. }
  1273. bool
  1274. TextEditRules::IsPlaintextEditor() const
  1275. {
  1276. return mTextEditor ? mTextEditor->IsPlaintextEditor() : false;
  1277. }
  1278. bool
  1279. TextEditRules::IsReadonly() const
  1280. {
  1281. return mTextEditor ? mTextEditor->IsReadonly() : false;
  1282. }
  1283. bool
  1284. TextEditRules::IsDisabled() const
  1285. {
  1286. return mTextEditor ? mTextEditor->IsDisabled() : false;
  1287. }
  1288. bool
  1289. TextEditRules::IsMailEditor() const
  1290. {
  1291. return mTextEditor ? mTextEditor->IsMailEditor() : false;
  1292. }
  1293. bool
  1294. TextEditRules::DontEchoPassword() const
  1295. {
  1296. return mTextEditor ? mTextEditor->DontEchoPassword() : false;
  1297. }
  1298. } // namespace mozilla