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 6 #ifndef mozilla_TextEditRules_h 7 #define mozilla_TextEditRules_h 8 9 #include "mozilla/EditAction.h" 10 #include "mozilla/EditorDOMPoint.h" 11 #include "nsCOMPtr.h" 12 #include "nsCycleCollectionParticipant.h" 13 #include "nsIEditor.h" 14 #include "nsINamed.h" 15 #include "nsISupportsImpl.h" 16 #include "nsITimer.h" 17 #include "nsString.h" 18 #include "nscore.h" 19 20 class nsIDOMNode; 21 22 namespace mozilla { 23 24 class AutoLockRulesSniffing; 25 class HTMLEditRules; 26 class RulesInfo; 27 class TextEditor; 28 namespace dom { 29 class Selection; 30 } // namespace dom 31 32 /** 33 * Object that encapsulates HTML text-specific editing rules. 34 * 35 * To be a good citizen, edit rules must live by these restrictions: 36 * 1. All data manipulation is through the editor. 37 * Content nodes in the document tree must <B>not</B> be manipulated 38 * directly. Content nodes in document fragments that are not part of the 39 * document itself may be manipulated at will. Operations on document 40 * fragments must <B>not</B> go through the editor. 41 * 2. Selection must not be explicitly set by the rule method. 42 * Any manipulation of Selection must be done by the editor. 43 */ 44 class TextEditRules : public nsITimerCallback, public nsINamed { 45 public: 46 typedef dom::Element Element; 47 typedef dom::Selection Selection; 48 typedef dom::Text Text; 49 template <typename T> 50 using OwningNonNull = OwningNonNull<T>; 51 52 NS_DECL_NSITIMERCALLBACK 53 NS_DECL_NSINAMED 54 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 55 NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(TextEditRules, nsITimerCallback) 56 57 TextEditRules(); 58 59 HTMLEditRules* AsHTMLEditRules(); 60 const HTMLEditRules* AsHTMLEditRules() const; 61 62 virtual nsresult Init(TextEditor* aTextEditor); 63 virtual nsresult SetInitialValue(const nsAString& aValue); 64 virtual nsresult DetachEditor(); 65 virtual nsresult BeforeEdit(EditAction aAction, 66 nsIEditor::EDirection aDirection); 67 virtual nsresult AfterEdit(EditAction aAction, 68 nsIEditor::EDirection aDirection); 69 virtual nsresult WillDoAction(Selection* aSelection, RulesInfo* aInfo, 70 bool* aCancel, bool* aHandled); 71 virtual nsresult DidDoAction(Selection* aSelection, RulesInfo* aInfo, 72 nsresult aResult); 73 virtual bool DocumentIsEmpty(); 74 virtual nsresult DocumentModified(); 75 76 protected: 77 virtual ~TextEditRules(); 78 79 public: 80 void ResetIMETextPWBuf(); 81 82 /** 83 * Handles the newline characters either according to aNewLineHandling 84 * or to the default system prefs if aNewLineHandling is negative. 85 * 86 * @param aString the string to be modified in place. 87 * @param aNewLineHandling determine the desired type of newline handling: 88 * * negative values: 89 * handle newlines according to platform defaults. 90 * * nsIPlaintextEditor::eNewlinesReplaceWithSpaces: 91 * replace newlines with spaces. 92 * * nsIPlaintextEditor::eNewlinesStrip: 93 * remove newlines from the string. 94 * * nsIPlaintextEditor::eNewlinesReplaceWithCommas: 95 * replace newlines with commas. 96 * * nsIPlaintextEditor::eNewlinesStripSurroundingWhitespace: 97 * collapse newlines and surrounding whitespace characters and 98 * remove them from the string. 99 * * nsIPlaintextEditor::eNewlinesPasteIntact: 100 * only remove the leading and trailing newlines. 101 * * nsIPlaintextEditor::eNewlinesPasteToFirst or any other value: 102 * remove the first newline and all characters following it. 103 */ 104 static void HandleNewLines(nsString& aString, int32_t aNewLineHandling); 105 106 /** 107 * Prepare a string buffer for being displayed as the contents of a password 108 * field. This function uses the platform-specific character for representing 109 * characters entered into password fields. 110 * 111 * @param aOutString the output string. When this function returns, 112 * aOutString will contain aLength password characters. 113 * @param aLength the number of password characters that aOutString should 114 * contain. 115 */ 116 static void FillBufWithPWChars(nsAString* aOutString, int32_t aLength); 117 HasBogusNode()118 bool HasBogusNode() { return !!mBogusNode; } 119 120 protected: 121 void InitFields(); 122 123 // TextEditRules implementation methods 124 nsresult WillInsertText(EditAction aAction, Selection* aSelection, 125 bool* aCancel, bool* aHandled, 126 const nsAString* inString, nsAString* outString, 127 int32_t aMaxLength); 128 nsresult DidInsertText(Selection* aSelection, nsresult aResult); 129 130 nsresult WillInsertBreak(Selection* aSelection, bool* aCancel, bool* aHandled, 131 int32_t aMaxLength); 132 nsresult DidInsertBreak(Selection* aSelection, nsresult aResult); 133 134 nsresult WillSetText(Selection& aSelection, bool* aCancel, bool* aHandled, 135 const nsAString* inString, int32_t aMaxLength); 136 nsresult DidSetText(Selection& aSelection, nsresult aResult); 137 138 void WillInsert(Selection& aSelection, bool* aCancel); 139 nsresult DidInsert(Selection* aSelection, nsresult aResult); 140 141 nsresult WillDeleteSelection(Selection* aSelection, 142 nsIEditor::EDirection aCollapsedAction, 143 bool* aCancel, bool* aHandled); 144 nsresult DidDeleteSelection(Selection* aSelection, 145 nsIEditor::EDirection aCollapsedAction, 146 nsresult aResult); 147 148 nsresult WillSetTextProperty(Selection* aSelection, bool* aCancel, 149 bool* aHandled); 150 nsresult DidSetTextProperty(Selection* aSelection, nsresult aResult); 151 152 nsresult WillRemoveTextProperty(Selection* aSelection, bool* aCancel, 153 bool* aHandled); 154 nsresult DidRemoveTextProperty(Selection* aSelection, nsresult aResult); 155 156 nsresult WillUndo(Selection* aSelection, bool* aCancel, bool* aHandled); 157 nsresult DidUndo(Selection* aSelection, nsresult aResult); 158 159 nsresult WillRedo(Selection* aSelection, bool* aCancel, bool* aHandled); 160 nsresult DidRedo(Selection* aSelection, nsresult aResult); 161 162 /** 163 * Called prior to nsIEditor::OutputToString. 164 * @param aSelection 165 * @param aInFormat The format requested for the output, a MIME type. 166 * @param aOutText The string to use for output, if aCancel is set to true. 167 * @param aOutCancel If set to true, the caller should cancel the operation 168 * and use aOutText as the result. 169 */ 170 nsresult WillOutputText(Selection* aSelection, const nsAString* aInFormat, 171 nsAString* aOutText, uint32_t aFlags, 172 bool* aOutCancel, bool* aHandled); 173 174 nsresult DidOutputText(Selection* aSelection, nsresult aResult); 175 176 /** 177 * Check for and replace a redundant trailing break. 178 */ 179 nsresult RemoveRedundantTrailingBR(); 180 181 /** 182 * Creates a trailing break in the text doc if there is not one already. 183 */ 184 nsresult CreateTrailingBRIfNeeded(); 185 186 /** 187 * Creates a bogus text node if the document has no editable content. 188 */ 189 nsresult CreateBogusNodeIfNeeded(Selection* aSelection); 190 191 /** 192 * Returns a truncated insertion string if insertion would place us over 193 * aMaxLength 194 */ 195 nsresult TruncateInsertionIfNeeded(Selection* aSelection, 196 const nsAString* aInString, 197 nsAString* aOutString, int32_t aMaxLength, 198 bool* aTruncated); 199 200 /** 201 * Remove IME composition text from password buffer. 202 */ 203 void RemoveIMETextFromPWBuf(uint32_t& aStart, nsAString* aIMEString); 204 205 /** 206 * Create a normal <br> element and insert it to aPointToInsert. 207 * 208 * @param aPointToInsert The point where the new <br> element will be 209 * inserted. 210 * @return Returns created <br> element. 211 */ CreateBR(const EditorRawDOMPoint & aPointToInsert)212 already_AddRefed<Element> CreateBR(const EditorRawDOMPoint& aPointToInsert) { 213 return CreateBRInternal(aPointToInsert, false); 214 } 215 216 /** 217 * Create a moz-<br> element and insert it to aPointToInsert. 218 * 219 * @param aPointToInsert The point where the new moz-<br> element will be 220 * inserted. 221 * @return Returns created moz-<br> element. 222 */ CreateMozBR(const EditorRawDOMPoint & aPointToInsert)223 already_AddRefed<Element> CreateMozBR( 224 const EditorRawDOMPoint& aPointToInsert) { 225 return CreateBRInternal(aPointToInsert, true); 226 } 227 228 /** 229 * Create a normal <br> element or a moz-<br> element and insert it to 230 * aPointToInsert. 231 * 232 * @param aParentToInsert The point where the new <br> element will be 233 * inserted. 234 * @param aCreateMozBR true if the caller wants to create a moz-<br> 235 * element. Otherwise, false. 236 * @return Returns created <br> element. 237 */ 238 already_AddRefed<Element> CreateBRInternal( 239 const EditorRawDOMPoint& aPointToInsert, bool aCreateMozBR); 240 241 void UndefineCaretBidiLevel(Selection* aSelection); 242 243 nsresult CheckBidiLevelForDeletion(Selection* aSelection, nsINode* aSelNode, 244 int32_t aSelOffset, 245 nsIEditor::EDirection aAction, 246 bool* aCancel); 247 248 nsresult HideLastPWInput(); 249 250 nsresult CollapseSelectionToTrailingBRIfNeeded(Selection* aSelection); 251 252 bool IsPasswordEditor() const; 253 bool IsSingleLineEditor() const; 254 bool IsPlaintextEditor() const; 255 bool IsReadonly() const; 256 bool IsDisabled() const; 257 bool IsMailEditor() const; 258 bool DontEchoPassword() const; 259 260 private: 261 // Note that we do not refcount the editor. 262 TextEditor* mTextEditor; 263 264 protected: 265 // A buffer we use to store the real value of password editors. 266 nsString mPasswordText; 267 // A buffer we use to track the IME composition string. 268 nsString mPasswordIMEText; 269 uint32_t mPasswordIMEIndex; 270 // Magic node acts as placeholder in empty doc. 271 nsCOMPtr<nsIContent> mBogusNode; 272 // Cached selected node. 273 nsCOMPtr<nsINode> mCachedSelectionNode; 274 // Cached selected offset. 275 uint32_t mCachedSelectionOffset; 276 uint32_t mActionNesting; 277 bool mLockRulesSniffing; 278 bool mDidExplicitlySetInterline; 279 // In bidirectional text, delete characters not visually adjacent to the 280 // caret without moving the caret first. 281 bool mDeleteBidiImmediately; 282 bool mIsHTMLEditRules; 283 // The top level editor action. 284 EditAction mTheAction; 285 nsCOMPtr<nsITimer> mTimer; 286 uint32_t mLastStart; 287 uint32_t mLastLength; 288 289 // friends 290 friend class AutoLockRulesSniffing; 291 }; 292 293 /** 294 * An object to encapsulate any additional info needed to be passed 295 * to rules system by the editor. 296 * TODO: This class (almost struct, though) is ugly and its size isn't 297 * optimized. Should be refined later. 298 */ 299 class RulesInfo final { 300 public: RulesInfo(EditAction aAction)301 explicit RulesInfo(EditAction aAction) 302 : action(aAction), 303 inString(nullptr), 304 outString(nullptr), 305 outputFormat(nullptr), 306 maxLength(-1), 307 flags(0), 308 collapsedAction(nsIEditor::eNext), 309 stripWrappers(nsIEditor::eStrip), 310 bOrdered(false), 311 entireList(false), 312 bulletType(nullptr), 313 alignType(nullptr), 314 blockType(nullptr) {} 315 316 EditAction action; 317 318 // EditAction::insertText / EditAction::insertIMEText 319 const nsAString* inString; 320 nsAString* outString; 321 const nsAString* outputFormat; 322 int32_t maxLength; 323 324 // EditAction::outputText 325 uint32_t flags; 326 327 // EditAction::deleteSelection 328 nsIEditor::EDirection collapsedAction; 329 nsIEditor::EStripWrappers stripWrappers; 330 331 // EditAction::removeList 332 bool bOrdered; 333 334 // EditAction::makeList 335 bool entireList; 336 const nsAString* bulletType; 337 338 // EditAction::align 339 const nsAString* alignType; 340 341 // EditAction::makeBasicBlock 342 const nsAString* blockType; 343 }; 344 345 /** 346 * Stack based helper class for StartOperation()/EndOperation() sandwich. 347 * This class sets a bool letting us know to ignore any rules sniffing 348 * that tries to occur reentrantly. 349 */ 350 class MOZ_STACK_CLASS AutoLockRulesSniffing final { 351 public: AutoLockRulesSniffing(TextEditRules * aRules)352 explicit AutoLockRulesSniffing(TextEditRules* aRules) : mRules(aRules) { 353 if (mRules) { 354 mRules->mLockRulesSniffing = true; 355 } 356 } 357 ~AutoLockRulesSniffing()358 ~AutoLockRulesSniffing() { 359 if (mRules) { 360 mRules->mLockRulesSniffing = false; 361 } 362 } 363 364 protected: 365 TextEditRules* mRules; 366 }; 367 368 /** 369 * Stack based helper class for turning on/off the edit listener. 370 */ 371 class MOZ_STACK_CLASS AutoLockListener final { 372 public: AutoLockListener(bool * aEnabled)373 explicit AutoLockListener(bool* aEnabled) 374 : mEnabled(aEnabled), mOldState(false) { 375 if (mEnabled) { 376 mOldState = *mEnabled; 377 *mEnabled = false; 378 } 379 } 380 ~AutoLockListener()381 ~AutoLockListener() { 382 if (mEnabled) { 383 *mEnabled = mOldState; 384 } 385 } 386 387 protected: 388 bool* mEnabled; 389 bool mOldState; 390 }; 391 392 } // namespace mozilla 393 394 #endif // #ifndef mozilla_TextEditRules_h 395