Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp

Issue 2291943002: Ensure clean layout for spellchecker (Closed)
Patch Set: Fix broken test Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | third_party/WebKit/Source/web/WebLocalFrameImpl.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 for (Node& node : NodeTraversal::startsAt(toLocalFrame(frame)->document( )->rootNode())) 164 for (Node& node : NodeTraversal::startsAt(toLocalFrame(frame)->document( )->rootNode()))
165 node.setAlreadySpellChecked(false); 165 node.setAlreadySpellChecked(false);
166 } 166 }
167 } 167 }
168 168
169 void SpellChecker::didBeginEditing(Element* element) 169 void SpellChecker::didBeginEditing(Element* element)
170 { 170 {
171 if (!isSpellCheckingEnabled()) 171 if (!isSpellCheckingEnabled())
172 return; 172 return;
173 173
174 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
175 // needs to be audited. See http://crbug.com/590369 for more details.
176 // In the long term we should use idle time spell checker to prevent
177 // synchronous layout caused by spell checking (see crbug.com/517298).
178 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
179
180 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle());
181
174 bool isTextField = false; 182 bool isTextField = false;
175 HTMLTextFormControlElement* enclosingHTMLTextFormControlElement = 0; 183 HTMLTextFormControlElement* enclosingHTMLTextFormControlElement = 0;
176 if (!isHTMLTextFormControlElement(*element)) 184 if (!isHTMLTextFormControlElement(*element))
177 enclosingHTMLTextFormControlElement = enclosingTextFormControl(Position: :firstPositionInNode(element)); 185 enclosingHTMLTextFormControlElement = enclosingTextFormControl(Position: :firstPositionInNode(element));
178 element = enclosingHTMLTextFormControlElement ? enclosingHTMLTextFormControl Element : element; 186 element = enclosingHTMLTextFormControlElement ? enclosingHTMLTextFormControl Element : element;
179 Element* parent = element; 187 Element* parent = element;
180 if (isHTMLTextFormControlElement(*element)) { 188 if (isHTMLTextFormControlElement(*element)) {
181 HTMLTextFormControlElement* textControl = toHTMLTextFormControlElement(e lement); 189 HTMLTextFormControlElement* textControl = toHTMLTextFormControlElement(e lement);
182 parent = textControl; 190 parent = textControl;
183 element = textControl->innerEditorElement(); 191 element = textControl->innerEditorElement();
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 spellCheckerClient().showSpellingUI(true); 316 spellCheckerClient().showSpellingUI(true);
309 } 317 }
310 318
311 void SpellChecker::clearMisspellingsAndBadGrammarForMovingParagraphs(const Visib leSelection& movingSelection) 319 void SpellChecker::clearMisspellingsAndBadGrammarForMovingParagraphs(const Visib leSelection& movingSelection)
312 { 320 {
313 removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers()); 321 removeMarkers(movingSelection, DocumentMarker::MisspellingMarkers());
314 } 322 }
315 323
316 void SpellChecker::markMisspellingsAndBadGrammarForMovingParagraphs(const Visibl eSelection& movingSelection) 324 void SpellChecker::markMisspellingsAndBadGrammarForMovingParagraphs(const Visibl eSelection& movingSelection)
317 { 325 {
326 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
327 // needs to be audited. See http://crbug.com/590369 for more details.
328 // In the long term we should use idle time spell checker to prevent
329 // synchronous layout caused by spell checking (see crbug.com/517298).
330 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
331
332 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle());
333
318 markMisspellingsAndBadGrammar(movingSelection); 334 markMisspellingsAndBadGrammar(movingSelection);
319 } 335 }
320 336
321 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& selecti on) 337 void SpellChecker::markMisspellingsAndBadGrammar(const VisibleSelection& selecti on)
322 { 338 {
323 if (!isSpellCheckingEnabled() || !isSpellCheckingEnabledFor(selection)) 339 if (!isSpellCheckingEnabled() || !isSpellCheckingEnabledFor(selection))
324 return; 340 return;
325 341
326 const EphemeralRange& range = selection.toNormalizedEphemeralRange(); 342 const EphemeralRange& range = selection.toNormalizedEphemeralRange();
327 if (range.isNull()) 343 if (range.isNull())
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 return; 496 return;
481 } 497 }
482 if (!request->isValid()) 498 if (!request->isValid())
483 return; 499 return;
484 if (request->rootEditableElement()->document() != frame().selection().docume nt()) { 500 if (request->rootEditableElement()->document() != frame().selection().docume nt()) {
485 // we ignore |request| made for another document. 501 // we ignore |request| made for another document.
486 // "editing/spelling/spellcheck-sequencenum.html" and others reach here. 502 // "editing/spelling/spellcheck-sequencenum.html" and others reach here.
487 return; 503 return;
488 } 504 }
489 505
506 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets needs to be audited.
507 // see http://crbug.com/590369 for more details.
508 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
509
490 TextCheckingParagraph paragraph(request->checkingRange(), request->checkingR ange()); 510 TextCheckingParagraph paragraph(request->checkingRange(), request->checkingR ange());
491 511
492 // Expand the range to encompass entire paragraphs, since text checking need s that much context. 512 // Expand the range to encompass entire paragraphs, since text checking need s that much context.
493 int selectionOffset = 0; 513 int selectionOffset = 0;
494 int ambiguousBoundaryOffset = -1; 514 int ambiguousBoundaryOffset = -1;
495 bool selectionChanged = false; 515 bool selectionChanged = false;
496 bool restoreSelectionAfterChange = false; 516 bool restoreSelectionAfterChange = false;
497 bool adjustSelectionForParagraphBoundaries = false; 517 bool adjustSelectionForParagraphBoundaries = false;
498 518
499 if (frame().selection().isCaret()) {
500 // Attempt to save the caret position so we can restore it later if need ed
501 Position caretPosition = frame().selection().end();
502 selectionOffset = paragraph.offsetTo(caretPosition);
503 restoreSelectionAfterChange = true;
504 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) > par agraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newlineCh aracter))
505 adjustSelectionForParagraphBoundaries = true;
506 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <= par agraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt(sele ctionOffset - 1)))
507 ambiguousBoundaryOffset = selectionOffset - 1;
508 }
509
510 // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets n eeds to be audited.
511 // see http://crbug.com/590369 for more details.
512 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
513
514 { 519 {
515 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle ()); 520 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle ());
516 521
522 if (frame().selection().isCaret()) {
523 // Attempt to save the caret position so we can restore it later if needed
524 Position caretPosition = frame().selection().end();
525 selectionOffset = paragraph.offsetTo(caretPosition);
526 restoreSelectionAfterChange = true;
527 if (selectionOffset > 0 && (static_cast<unsigned>(selectionOffset) > paragraph.text().length() || paragraph.textCharAt(selectionOffset - 1) == newli neCharacter))
528 adjustSelectionForParagraphBoundaries = true;
529 if (selectionOffset > 0 && static_cast<unsigned>(selectionOffset) <= paragraph.text().length() && isAmbiguousBoundaryCharacter(paragraph.textCharAt( selectionOffset - 1)))
530 ambiguousBoundaryOffset = selectionOffset - 1;
531 }
532
517 for (unsigned i = 0; i < results.size(); i++) { 533 for (unsigned i = 0; i < results.size(); i++) {
518 int spellingRangeEndOffset = paragraph.checkingEnd(); 534 int spellingRangeEndOffset = paragraph.checkingEnd();
519 const TextCheckingResult* result = &results[i]; 535 const TextCheckingResult* result = &results[i];
520 int resultLocation = result->location + paragraph.checkingStart(); 536 int resultLocation = result->location + paragraph.checkingStart();
521 int resultLength = result->length; 537 int resultLength = result->length;
522 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset; 538 bool resultEndsAtAmbiguousBoundary = ambiguousBoundaryOffset >= 0 && resultLocation + resultLength == ambiguousBoundaryOffset;
523 539
524 // Only mark misspelling if: 540 // Only mark misspelling if:
525 // 1. Current text checking isn't done for autocorrection. 541 // 1. Current text checking isn't done for autocorrection.
526 // 2. Result falls within spellingRange. 542 // 2. Result falls within spellingRange.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
682 } 698 }
683 699
684 static bool shouldCheckOldSelection(const VisibleSelection& oldSelection) 700 static bool shouldCheckOldSelection(const VisibleSelection& oldSelection)
685 { 701 {
686 if (!oldSelection.start().isConnected()) 702 if (!oldSelection.start().isConnected())
687 return false; 703 return false;
688 if (isSelectionInTextField(oldSelection)) 704 if (isSelectionInTextField(oldSelection))
689 return false; 705 return false;
690 if (isSelectionInTextArea(oldSelection)) 706 if (isSelectionInTextArea(oldSelection))
691 return true; 707 return true;
708
709 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
710 // needs to be audited. See http://crbug.com/590369 for more details.
711 // In the long term we should use idle time spell checker to prevent
712 // synchronous layout caused by spell checking (see crbug.com/517298).
692 oldSelection.start().document()->updateStyleAndLayoutIgnorePendingStylesheet s(); 713 oldSelection.start().document()->updateStyleAndLayoutIgnorePendingStylesheet s();
714
693 return oldSelection.isContentEditable(); 715 return oldSelection.isContentEditable();
694 } 716 }
695 717
696 void SpellChecker::respondToChangedSelection(const VisibleSelection& oldSelectio n, FrameSelection::SetSelectionOptions options) 718 void SpellChecker::respondToChangedSelection(const VisibleSelection& oldSelectio n, FrameSelection::SetSelectionOptions options)
697 { 719 {
698 TRACE_EVENT0("blink", "SpellChecker::respondToChangedSelection"); 720 TRACE_EVENT0("blink", "SpellChecker::respondToChangedSelection");
699 if (!isSpellCheckingEnabledFor(oldSelection)) 721 if (!isSpellCheckingEnabledFor(oldSelection))
700 return; 722 return;
701 723
702 // When spell checking is off, existing markers disappear after the selectio n changes. 724 // When spell checking is off, existing markers disappear after the selectio n changes.
703 if (!isSpellCheckingEnabled()) { 725 if (!isSpellCheckingEnabled()) {
704 frame().document()->markers().removeMarkers(DocumentMarker::Spelling); 726 frame().document()->markers().removeMarkers(DocumentMarker::Spelling);
705 frame().document()->markers().removeMarkers(DocumentMarker::Grammar); 727 frame().document()->markers().removeMarkers(DocumentMarker::Grammar);
706 return; 728 return;
707 } 729 }
708 730
709 if (!(options & FrameSelection::CloseTyping)) 731 if (!(options & FrameSelection::CloseTyping))
710 return; 732 return;
711 if (!shouldCheckOldSelection(oldSelection)) 733 if (!shouldCheckOldSelection(oldSelection))
712 return; 734 return;
713 735
736 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle());
737
714 VisibleSelection newAdjacentWords; 738 VisibleSelection newAdjacentWords;
715 const VisibleSelection newSelection = frame().selection().selection(); 739 const VisibleSelection newSelection = frame().selection().selection();
716 if (isSelectionInTextFormControl(newSelection)) { 740 if (isSelectionInTextFormControl(newSelection)) {
717 const Position newStart = newSelection.start(); 741 const Position newStart = newSelection.start();
718 newAdjacentWords.setWithoutValidation(HTMLTextFormControlElement::startO fWord(newStart), HTMLTextFormControlElement::endOfWord(newStart)); 742 newAdjacentWords.setWithoutValidation(HTMLTextFormControlElement::startO fWord(newStart), HTMLTextFormControlElement::endOfWord(newStart));
719 } else { 743 } else {
720 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets(); 744 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
721 const bool caretBrowsing = frame().settings() && frame().settings()->car etBrowsingEnabled(); 745 const bool caretBrowsing = frame().settings() && frame().settings()->car etBrowsingEnabled();
722 if (newSelection.isContentEditable() || caretBrowsing) { 746 if (newSelection.isContentEditable() || caretBrowsing) {
723 const VisiblePosition newStart(newSelection.visibleStart()); 747 const VisiblePosition newStart(newSelection.visibleStart());
(...skipping 26 matching lines...) Expand all
750 void SpellChecker::spellCheckAfterBlur() 774 void SpellChecker::spellCheckAfterBlur()
751 { 775 {
752 if (!frame().selection().selection().isContentEditable()) 776 if (!frame().selection().selection().isContentEditable())
753 return; 777 return;
754 778
755 if (isSelectionInTextField(frame().selection().selection())) { 779 if (isSelectionInTextField(frame().selection().selection())) {
756 // textFieldDidEndEditing() and textFieldDidBeginEditing() handle this. 780 // textFieldDidEndEditing() and textFieldDidBeginEditing() handle this.
757 return; 781 return;
758 } 782 }
759 783
784 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
785 // needs to be audited. See http://crbug.com/590369 for more details.
786 // In the long term we should use idle time spell checker to prevent
787 // synchronous layout caused by spell checking (see crbug.com/517298).
788 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
789
790 DocumentLifecycle::DisallowTransitionScope(frame().document()->lifecycle());
791
760 VisibleSelection empty; 792 VisibleSelection empty;
761 spellCheckOldSelection(frame().selection().selection(), empty); 793 spellCheckOldSelection(frame().selection().selection(), empty);
762 } 794 }
763 795
764 void SpellChecker::spellCheckOldSelection(const VisibleSelection& oldSelection, const VisibleSelection& newAdjacentWords) 796 void SpellChecker::spellCheckOldSelection(const VisibleSelection& oldSelection, const VisibleSelection& newAdjacentWords)
765 { 797 {
766 if (!isSpellCheckingEnabled()) 798 if (!isSpellCheckingEnabled())
767 return; 799 return;
768 800
769 TRACE_EVENT0("blink", "SpellChecker::spellCheckOldSelection"); 801 TRACE_EVENT0("blink", "SpellChecker::spellCheckOldSelection");
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
948 VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePo sition(paragraphEnd)); 980 VisiblePosition newParagraphStart = startOfNextParagraph(createVisiblePo sition(paragraphEnd));
949 paragraphStart = newParagraphStart.toParentAnchoredPosition(); 981 paragraphStart = newParagraphStart.toParentAnchoredPosition();
950 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n(); 982 paragraphEnd = endOfParagraph(newParagraphStart).toParentAnchoredPositio n();
951 firstIteration = false; 983 firstIteration = false;
952 totalLengthProcessed += currentLength; 984 totalLengthProcessed += currentLength;
953 } 985 }
954 return std::make_pair(firstFoundItem, firstFoundOffset); 986 return std::make_pair(firstFoundItem, firstFoundOffset);
955 } 987 }
956 988
957 } // namespace blink 989 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Source/web/WebLocalFrameImpl.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698