OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008 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 853 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
864 startRoot->dispatchEvent(Event::create(eventNames().webkitEditableConten
tChangedEvent, false, false), ec); | 864 startRoot->dispatchEvent(Event::create(eventNames().webkitEditableConten
tChangedEvent, false, false), ec); |
865 if (endRoot && endRoot != startRoot) | 865 if (endRoot && endRoot != startRoot) |
866 endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentC
hangedEvent, false, false), ec); | 866 endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentC
hangedEvent, false, false), ec); |
867 } | 867 } |
868 | 868 |
869 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd) | 869 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd) |
870 { | 870 { |
871 dispatchEditableContentChangedEvents(*cmd); | 871 dispatchEditableContentChangedEvents(*cmd); |
872 | 872 |
873 VisibleSelection newSelection(cmd->endingSelection()); | 873 VisibleSelection newSelection(cmd->endingSelection()); |
874 // If there is no selection change, don't bother sending shouldChangeSelecti
on, but still call setSelection, | |
875 // because there is work that it must do in this situation. | |
876 // The old selection can be invalid here and calling shouldChangeSelection c
an produce some strange calls. | |
877 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ra
nges for selections that are no longer valid | |
878 // Don't clear the typing style with this selection change. We do those thi
ngs elsewhere if necessary. | 874 // Don't clear the typing style with this selection change. We do those thi
ngs elsewhere if necessary. |
879 if (newSelection == m_frame->selection()->selection() || m_frame->shouldChan
geSelection(newSelection)) | 875 changeSelectionAfterCommand(newSelection, false, false, cmd.get()); |
880 m_frame->selection()->setSelection(newSelection, false, false); | |
881 | 876 |
882 if (!cmd->preservesTypingStyle()) | 877 if (!cmd->preservesTypingStyle()) |
883 m_frame->setTypingStyle(0); | 878 m_frame->setTypingStyle(0); |
884 | 879 |
885 // Command will be equal to last edit command only in the case of typing | 880 // Command will be equal to last edit command only in the case of typing |
886 if (m_lastEditCommand.get() == cmd) | 881 if (m_lastEditCommand.get() == cmd) |
887 ASSERT(cmd->isTypingCommand()); | 882 ASSERT(cmd->isTypingCommand()); |
888 else { | 883 else { |
889 // Only register a new undo command if the command passed in is | 884 // Only register a new undo command if the command passed in is |
890 // different from the last command | 885 // different from the last command |
891 m_lastEditCommand = cmd; | 886 m_lastEditCommand = cmd; |
892 if (client()) | 887 if (client()) |
893 client()->registerCommandForUndo(m_lastEditCommand); | 888 client()->registerCommandForUndo(m_lastEditCommand); |
894 } | 889 } |
895 respondToChangedContents(newSelection); | 890 respondToChangedContents(newSelection); |
896 } | 891 } |
897 | 892 |
898 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd) | 893 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd) |
899 { | 894 { |
900 dispatchEditableContentChangedEvents(*cmd); | 895 dispatchEditableContentChangedEvents(*cmd); |
901 | 896 |
902 VisibleSelection newSelection(cmd->startingSelection()); | 897 VisibleSelection newSelection(cmd->startingSelection()); |
903 // If there is no selection change, don't bother sending shouldChangeSelecti
on, but still call setSelection, | 898 changeSelectionAfterCommand(newSelection, true, true, cmd.get()); |
904 // because there is work that it must do in this situation. | |
905 // The old selection can be invalid here and calling shouldChangeSelection c
an produce some strange calls. | |
906 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ra
nges for selections that are no longer valid | |
907 if (newSelection == m_frame->selection()->selection() || m_frame->shouldChan
geSelection(newSelection)) | |
908 m_frame->selection()->setSelection(newSelection, true); | |
909 | 899 |
910 m_lastEditCommand = 0; | 900 m_lastEditCommand = 0; |
911 if (client()) | 901 if (client()) |
912 client()->registerCommandForRedo(cmd); | 902 client()->registerCommandForRedo(cmd); |
913 respondToChangedContents(newSelection); | 903 respondToChangedContents(newSelection); |
914 } | 904 } |
915 | 905 |
916 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd) | 906 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd) |
917 { | 907 { |
918 dispatchEditableContentChangedEvents(*cmd); | 908 dispatchEditableContentChangedEvents(*cmd); |
919 | 909 |
920 VisibleSelection newSelection(cmd->endingSelection()); | 910 VisibleSelection newSelection(cmd->endingSelection()); |
921 // If there is no selection change, don't bother sending shouldChangeSelecti
on, but still call setSelection, | 911 changeSelectionAfterCommand(newSelection, true, true, cmd.get()); |
922 // because there is work that it must do in this situation. | |
923 // The old selection can be invalid here and calling shouldChangeSelection c
an produce some strange calls. | |
924 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ra
nges for selections that are no longer valid | |
925 if (newSelection == m_frame->selection()->selection() || m_frame->shouldChan
geSelection(newSelection)) | |
926 m_frame->selection()->setSelection(newSelection, true); | |
927 | 912 |
928 m_lastEditCommand = 0; | 913 m_lastEditCommand = 0; |
929 if (client()) | 914 if (client()) |
930 client()->registerCommandForUndo(cmd); | 915 client()->registerCommandForUndo(cmd); |
931 respondToChangedContents(newSelection); | 916 respondToChangedContents(newSelection); |
932 } | 917 } |
933 | 918 |
934 Editor::Editor(Frame* frame) | 919 Editor::Editor(Frame* frame) |
935 : m_frame(frame) | 920 : m_frame(frame) |
936 , m_deleteButtonController(new DeleteButtonController(frame)) | 921 , m_deleteButtonController(new DeleteButtonController(frame)) |
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1544 // These results were all between the start of the paragraph and the sta
rt of the search range; look | 1529 // These results were all between the start of the paragraph and the sta
rt of the search range; look |
1545 // beyond this phrase. | 1530 // beyond this phrase. |
1546 startOffset = badGrammarPhraseLocation + badGrammarPhraseLength; | 1531 startOffset = badGrammarPhraseLocation + badGrammarPhraseLength; |
1547 } | 1532 } |
1548 | 1533 |
1549 return firstBadGrammarPhrase; | 1534 return firstBadGrammarPhrase; |
1550 } | 1535 } |
1551 | 1536 |
1552 #endif /* not BUILDING_ON_TIGER */ | 1537 #endif /* not BUILDING_ON_TIGER */ |
1553 | 1538 |
| 1539 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 1540 |
| 1541 static String findFirstMisspellingOrBadGrammarInRange(EditorClient* client, Rang
e* searchRange, bool checkGrammar, bool& outIsSpelling, int& outFirstFoundOffset
, GrammarDetail& outGrammarDetail) |
| 1542 { |
| 1543 ASSERT_ARG(client, client); |
| 1544 ASSERT_ARG(searchRange, searchRange); |
| 1545 |
| 1546 String firstFoundItem; |
| 1547 String misspelledWord; |
| 1548 String badGrammarPhrase; |
| 1549 ExceptionCode ec = 0; |
| 1550 |
| 1551 // Initialize out parameters; these will be updated if we find something to
return. |
| 1552 outIsSpelling = true; |
| 1553 outFirstFoundOffset = 0; |
| 1554 outGrammarDetail.location = -1; |
| 1555 outGrammarDetail.length = 0; |
| 1556 outGrammarDetail.guesses.clear(); |
| 1557 outGrammarDetail.userDescription = ""; |
| 1558 |
| 1559 // Expand the search range to encompass entire paragraphs, since text checki
ng needs that much context. |
| 1560 // Determine the character offset from the start of the paragraph to the sta
rt of the original search range, |
| 1561 // since we will want to ignore results in this area. |
| 1562 RefPtr<Range> paragraphRange = searchRange->cloneRange(ec); |
| 1563 setStart(paragraphRange.get(), startOfParagraph(searchRange->startPosition()
)); |
| 1564 int totalRangeLength = TextIterator::rangeLength(paragraphRange.get()); |
| 1565 setEnd(paragraphRange.get(), endOfParagraph(searchRange->startPosition())); |
| 1566 |
| 1567 RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContainer(e
c)->document(), paragraphRange->startPosition(), searchRange->startPosition()); |
| 1568 int searchRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get()); |
| 1569 int totalLengthProcessed = 0; |
| 1570 |
| 1571 bool firstIteration = true; |
| 1572 bool lastIteration = false; |
| 1573 while (totalLengthProcessed < totalRangeLength) { |
| 1574 // Iterate through the search range by paragraphs, checking each one for
spelling and grammar. |
| 1575 int currentLength = TextIterator::rangeLength(paragraphRange.get()); |
| 1576 int currentStartOffset = firstIteration ? searchRangeStartOffset : 0; |
| 1577 int currentEndOffset = currentLength; |
| 1578 if (inSameParagraph(paragraphRange->startPosition(), searchRange->endPos
ition())) { |
| 1579 // Determine the character offset from the end of the original searc
h range to the end of the paragraph, |
| 1580 // since we will want to ignore results in this area. |
| 1581 RefPtr<Range> endOffsetAsRange = Range::create(paragraphRange->start
Container(ec)->document(), paragraphRange->startPosition(), searchRange->endPosi
tion()); |
| 1582 currentEndOffset = TextIterator::rangeLength(endOffsetAsRange.get())
; |
| 1583 lastIteration = true; |
| 1584 } |
| 1585 if (currentStartOffset < currentEndOffset) { |
| 1586 String paragraphString = plainText(paragraphRange.get()); |
| 1587 if (paragraphString.length() > 0) { |
| 1588 bool foundGrammar = false; |
| 1589 int spellingLocation = 0; |
| 1590 int grammarPhraseLocation = 0; |
| 1591 int grammarDetailLocation = 0; |
| 1592 unsigned grammarDetailIndex = 0; |
| 1593 |
| 1594 Vector<TextCheckingResult> results; |
| 1595 client->checkSpellingAndGrammarOfParagraph(paragraphString.chara
cters(), paragraphString.length(), checkGrammar, results); |
| 1596 |
| 1597 for (unsigned i = 0; i < results.size(); i++) { |
| 1598 const TextCheckingResult* result = &results[i]; |
| 1599 if (result->resultType == 1 && result->location >= currentSt
artOffset && result->location + result->length <= currentEndOffset) { |
| 1600 ASSERT(result->length > 0 && result->location >= 0); |
| 1601 spellingLocation = result->location; |
| 1602 misspelledWord = paragraphString.substring(result->locat
ion, result->length); |
| 1603 ASSERT(misspelledWord.length() != 0); |
| 1604 break; |
| 1605 } else if (checkGrammar && result->resultType == 2 && result
->location < currentEndOffset && result->location + result->length > currentStar
tOffset) { |
| 1606 ASSERT(result->length > 0 && result->location >= 0); |
| 1607 // We can't stop after the first grammar result, since t
here might still be a spelling result after |
| 1608 // it begins but before the first detail in it, but we c
an stop if we find a second grammar result. |
| 1609 if (foundGrammar) break; |
| 1610 for (unsigned j = 0; j < result->details.size(); j++) { |
| 1611 const GrammarDetail* detail = &result->details[j]; |
| 1612 ASSERT(detail->length > 0 && detail->location >= 0); |
| 1613 if (result->location + detail->location >= currentSt
artOffset && result->location + detail->location + detail->length <= currentEndO
ffset && (!foundGrammar || result->location + detail->location < grammarDetailLo
cation)) { |
| 1614 grammarDetailIndex = j; |
| 1615 grammarDetailLocation = result->location + detai
l->location; |
| 1616 foundGrammar = true; |
| 1617 } |
| 1618 } |
| 1619 if (foundGrammar) { |
| 1620 grammarPhraseLocation = result->location; |
| 1621 outGrammarDetail = result->details[grammarDetailInde
x]; |
| 1622 badGrammarPhrase = paragraphString.substring(result-
>location, result->length); |
| 1623 ASSERT(badGrammarPhrase.length() != 0); |
| 1624 } |
| 1625 } |
| 1626 } |
| 1627 |
| 1628 if (!misspelledWord.isEmpty() && (!checkGrammar || badGrammarPhr
ase.isEmpty() || spellingLocation <= grammarDetailLocation)) { |
| 1629 int spellingOffset = spellingLocation - currentStartOffset; |
| 1630 if (!firstIteration) { |
| 1631 RefPtr<Range> paragraphOffsetAsRange = Range::create(par
agraphRange->startContainer(ec)->document(), searchRange->startPosition(), parag
raphRange->startPosition()); |
| 1632 spellingOffset += TextIterator::rangeLength(paragraphOff
setAsRange.get()); |
| 1633 } |
| 1634 outIsSpelling = true; |
| 1635 outFirstFoundOffset = spellingOffset; |
| 1636 firstFoundItem = misspelledWord; |
| 1637 break; |
| 1638 } else if (checkGrammar && !badGrammarPhrase.isEmpty()) { |
| 1639 int grammarPhraseOffset = grammarPhraseLocation - currentSta
rtOffset; |
| 1640 if (!firstIteration) { |
| 1641 RefPtr<Range> paragraphOffsetAsRange = Range::create(par
agraphRange->startContainer(ec)->document(), searchRange->startPosition(), parag
raphRange->startPosition()); |
| 1642 grammarPhraseOffset += TextIterator::rangeLength(paragra
phOffsetAsRange.get()); |
| 1643 } |
| 1644 outIsSpelling = false; |
| 1645 outFirstFoundOffset = grammarPhraseOffset; |
| 1646 firstFoundItem = badGrammarPhrase; |
| 1647 break; |
| 1648 } |
| 1649 } |
| 1650 } |
| 1651 if (lastIteration || totalLengthProcessed + currentLength >= totalRangeL
ength) |
| 1652 break; |
| 1653 setStart(paragraphRange.get(), startOfNextParagraph(paragraphRange->endP
osition())); |
| 1654 setEnd(paragraphRange.get(), endOfParagraph(paragraphRange->startPositio
n())); |
| 1655 firstIteration = false; |
| 1656 totalLengthProcessed += currentLength; |
| 1657 } |
| 1658 return firstFoundItem; |
| 1659 } |
| 1660 |
| 1661 #endif |
| 1662 |
1554 void Editor::advanceToNextMisspelling(bool startBeforeSelection) | 1663 void Editor::advanceToNextMisspelling(bool startBeforeSelection) |
1555 { | 1664 { |
1556 ExceptionCode ec = 0; | 1665 ExceptionCode ec = 0; |
1557 | 1666 |
1558 // The basic approach is to search in two phases - from the selection end to
the end of the doc, and | 1667 // The basic approach is to search in two phases - from the selection end to
the end of the doc, and |
1559 // then we wrap and search from the doc start to (approximately) where we st
arted. | 1668 // then we wrap and search from the doc start to (approximately) where we st
arted. |
1560 | 1669 |
1561 // Start at the end of the selection, search to edge of document. Starting
at the selection end makes | 1670 // Start at the end of the selection, search to edge of document. Starting
at the selection end makes |
1562 // repeated "check spelling" commands work. | 1671 // repeated "check spelling" commands work. |
1563 VisibleSelection selection(frame()->selection()->selection()); | 1672 VisibleSelection selection(frame()->selection()->selection()); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1611 if (!client()) | 1720 if (!client()) |
1612 return; | 1721 return; |
1613 | 1722 |
1614 // We go to the end of our first range instead of the start of it, just to b
e sure | 1723 // We go to the end of our first range instead of the start of it, just to b
e sure |
1615 // we don't get foiled by any word boundary problems at the start. It means
we might | 1724 // we don't get foiled by any word boundary problems at the start. It means
we might |
1616 // do a tiny bit more searching. | 1725 // do a tiny bit more searching. |
1617 Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec); | 1726 Node *searchEndNodeAfterWrap = spellingSearchRange->endContainer(ec); |
1618 int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec); | 1727 int searchEndOffsetAfterWrap = spellingSearchRange->endOffset(ec); |
1619 | 1728 |
1620 int misspellingOffset; | 1729 int misspellingOffset; |
| 1730 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 1731 RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec); |
| 1732 String misspelledWord; |
| 1733 String badGrammarPhrase; |
| 1734 int grammarPhraseOffset = 0; |
| 1735 bool isSpelling = true; |
| 1736 int foundOffset = 0; |
| 1737 GrammarDetail grammarDetail; |
| 1738 String foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellin
gSearchRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammar
Detail); |
| 1739 if (isSpelling) { |
| 1740 misspelledWord = foundItem; |
| 1741 misspellingOffset = foundOffset; |
| 1742 } else { |
| 1743 badGrammarPhrase = foundItem; |
| 1744 grammarPhraseOffset = foundOffset; |
| 1745 } |
| 1746 #else |
1621 String misspelledWord = findFirstMisspellingInRange(client(), spellingSearch
Range.get(), misspellingOffset, false); | 1747 String misspelledWord = findFirstMisspellingInRange(client(), spellingSearch
Range.get(), misspellingOffset, false); |
1622 | 1748 |
1623 String badGrammarPhrase; | 1749 String badGrammarPhrase; |
1624 | 1750 |
1625 #ifndef BUILDING_ON_TIGER | 1751 #ifndef BUILDING_ON_TIGER |
1626 int grammarPhraseOffset = 0; | 1752 int grammarPhraseOffset = 0; |
1627 GrammarDetail grammarDetail; | 1753 GrammarDetail grammarDetail; |
1628 | 1754 |
1629 // Search for bad grammar that occurs prior to the next misspelled word (if
any) | 1755 // Search for bad grammar that occurs prior to the next misspelled word (if
any) |
1630 RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec); | 1756 RefPtr<Range> grammarSearchRange = spellingSearchRange->cloneRange(ec); |
1631 if (!misspelledWord.isEmpty()) { | 1757 if (!misspelledWord.isEmpty()) { |
1632 // Stop looking at start of next misspelled word | 1758 // Stop looking at start of next misspelled word |
1633 CharacterIterator chars(grammarSearchRange.get()); | 1759 CharacterIterator chars(grammarSearchRange.get()); |
1634 chars.advance(misspellingOffset); | 1760 chars.advance(misspellingOffset); |
1635 grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.rang
e()->startOffset(ec), ec); | 1761 grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.rang
e()->startOffset(ec), ec); |
1636 } | 1762 } |
1637 | 1763 |
1638 if (isGrammarCheckingEnabled()) | 1764 if (isGrammarCheckingEnabled()) |
1639 badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRan
ge.get(), grammarDetail, grammarPhraseOffset, false); | 1765 badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearchRan
ge.get(), grammarDetail, grammarPhraseOffset, false); |
1640 #endif | 1766 #endif |
| 1767 #endif |
1641 | 1768 |
1642 // If we found neither bad grammar nor a misspelled word, wrap and try again
(but don't bother if we started at the beginning of the | 1769 // If we found neither bad grammar nor a misspelled word, wrap and try again
(but don't bother if we started at the beginning of the |
1643 // block rather than at a selection). | 1770 // block rather than at a selection). |
1644 if (startedWithSelection && !misspelledWord && !badGrammarPhrase) { | 1771 if (startedWithSelection && !misspelledWord && !badGrammarPhrase) { |
1645 spellingSearchRange->setStart(topNode, 0, ec); | 1772 spellingSearchRange->setStart(topNode, 0, ec); |
1646 // going until the end of the very first chunk we tested is far enough | 1773 // going until the end of the very first chunk we tested is far enough |
1647 spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfter
Wrap, ec); | 1774 spellingSearchRange->setEnd(searchEndNodeAfterWrap, searchEndOffsetAfter
Wrap, ec); |
1648 | 1775 |
| 1776 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 1777 grammarSearchRange = spellingSearchRange->cloneRange(ec); |
| 1778 foundItem = findFirstMisspellingOrBadGrammarInRange(client(), spellingSe
archRange.get(), isGrammarCheckingEnabled(), isSpelling, foundOffset, grammarDet
ail); |
| 1779 if (isSpelling) { |
| 1780 misspelledWord = foundItem; |
| 1781 misspellingOffset = foundOffset; |
| 1782 } else { |
| 1783 badGrammarPhrase = foundItem; |
| 1784 grammarPhraseOffset = foundOffset; |
| 1785 } |
| 1786 #else |
1649 misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRan
ge.get(), misspellingOffset, false); | 1787 misspelledWord = findFirstMisspellingInRange(client(), spellingSearchRan
ge.get(), misspellingOffset, false); |
1650 | 1788 |
1651 #ifndef BUILDING_ON_TIGER | 1789 #ifndef BUILDING_ON_TIGER |
1652 grammarSearchRange = spellingSearchRange->cloneRange(ec); | 1790 grammarSearchRange = spellingSearchRange->cloneRange(ec); |
1653 if (!misspelledWord.isEmpty()) { | 1791 if (!misspelledWord.isEmpty()) { |
1654 // Stop looking at start of next misspelled word | 1792 // Stop looking at start of next misspelled word |
1655 CharacterIterator chars(grammarSearchRange.get()); | 1793 CharacterIterator chars(grammarSearchRange.get()); |
1656 chars.advance(misspellingOffset); | 1794 chars.advance(misspellingOffset); |
1657 grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.
range()->startOffset(ec), ec); | 1795 grammarSearchRange->setEnd(chars.range()->startContainer(ec), chars.
range()->startOffset(ec), ec); |
1658 } | 1796 } |
1659 if (isGrammarCheckingEnabled()) | 1797 if (isGrammarCheckingEnabled()) |
1660 badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearc
hRange.get(), grammarDetail, grammarPhraseOffset, false); | 1798 badGrammarPhrase = findFirstBadGrammarInRange(client(), grammarSearc
hRange.get(), grammarDetail, grammarPhraseOffset, false); |
1661 #endif | 1799 #endif |
| 1800 #endif |
1662 } | 1801 } |
1663 | 1802 |
1664 if (!badGrammarPhrase.isEmpty()) { | 1803 if (!badGrammarPhrase.isEmpty()) { |
1665 #ifdef BUILDING_ON_TIGER | 1804 #ifdef BUILDING_ON_TIGER |
1666 ASSERT_NOT_REACHED(); | 1805 ASSERT_NOT_REACHED(); |
1667 #else | 1806 #else |
1668 // We found bad grammar. Since we only searched for bad grammar up to th
e first misspelled word, the bad grammar | 1807 // We found bad grammar. Since we only searched for bad grammar up to th
e first misspelled word, the bad grammar |
1669 // takes precedence and we ignore any potential misspelled word. Select
the grammar detail, update the spelling | 1808 // takes precedence and we ignore any potential misspelled word. Select
the grammar detail, update the spelling |
1670 // panel, and store a marker so we draw the green squiggle later. | 1809 // panel, and store a marker so we draw the green squiggle later. |
1671 | 1810 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1793 { | 1932 { |
1794 String selectedString = frame()->selectedText(); | 1933 String selectedString = frame()->selectedText(); |
1795 ASSERT(selectedString.length() != 0); | 1934 ASSERT(selectedString.length() != 0); |
1796 | 1935 |
1797 Vector<String> guesses; | 1936 Vector<String> guesses; |
1798 if (client()) | 1937 if (client()) |
1799 client()->getGuessesForWord(selectedString, guesses); | 1938 client()->getGuessesForWord(selectedString, guesses); |
1800 return guesses; | 1939 return guesses; |
1801 } | 1940 } |
1802 | 1941 |
| 1942 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 1943 |
| 1944 static Vector<String> guessesForMisspelledOrUngrammaticalRange(EditorClient* cli
ent, Range *range, bool checkGrammar, bool& misspelled, bool& ungrammatical) |
| 1945 { |
| 1946 Vector<String> guesses; |
| 1947 ExceptionCode ec; |
| 1948 misspelled = false; |
| 1949 ungrammatical = false; |
| 1950 |
| 1951 if (!client || !range || range->collapsed(ec)) |
| 1952 return guesses; |
| 1953 |
| 1954 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. |
| 1955 int rangeStartOffset; |
| 1956 String paragraphString; |
| 1957 RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(range, rangeSta
rtOffset, paragraphString); |
| 1958 int rangeLength = TextIterator::rangeLength(range); |
| 1959 if (rangeLength == 0 || paragraphString.length() == 0) |
| 1960 return guesses; |
| 1961 |
| 1962 Vector<TextCheckingResult> results; |
| 1963 client->checkSpellingAndGrammarOfParagraph(paragraphString.characters(), par
agraphString.length(), checkGrammar, results); |
| 1964 |
| 1965 for (unsigned i = 0; i < results.size(); i++) { |
| 1966 const TextCheckingResult* result = &results[i]; |
| 1967 if (result->resultType == 1 && result->location == rangeStartOffset && r
esult->length == rangeLength) { |
| 1968 String misspelledWord = paragraphString.substring(rangeStartOffset,
rangeLength); |
| 1969 ASSERT(misspelledWord.length() != 0); |
| 1970 client->getGuessesForWord(misspelledWord, guesses); |
| 1971 client->updateSpellingUIWithMisspelledWord(misspelledWord); |
| 1972 misspelled = true; |
| 1973 return guesses; |
| 1974 } |
| 1975 } |
| 1976 |
| 1977 if (!checkGrammar) |
| 1978 return guesses; |
| 1979 |
| 1980 for (unsigned i = 0; i < results.size(); i++) { |
| 1981 const TextCheckingResult* result = &results[i]; |
| 1982 if (result->resultType == 2 && result->location <= rangeStartOffset && r
esult->location + result->length >= rangeStartOffset + rangeLength) { |
| 1983 for (unsigned j = 0; j < result->details.size(); j++) { |
| 1984 const GrammarDetail* detail = &result->details[j]; |
| 1985 ASSERT(detail->length > 0 && detail->location >= 0); |
| 1986 if (result->location + detail->location == rangeStartOffset && d
etail->length == rangeLength) { |
| 1987 String badGrammarPhrase = paragraphString.substring(result->
location, result->length); |
| 1988 ASSERT(badGrammarPhrase.length() != 0); |
| 1989 for (unsigned k = 0; k < detail->guesses.size(); k++) |
| 1990 guesses.append(detail->guesses[k]); |
| 1991 client->updateSpellingUIWithGrammarString(badGrammarPhrase,
*detail); |
| 1992 ungrammatical = true; |
| 1993 return guesses; |
| 1994 } |
| 1995 } |
| 1996 } |
| 1997 } |
| 1998 return guesses; |
| 1999 } |
| 2000 |
| 2001 #endif |
| 2002 |
| 2003 Vector<String> Editor::guessesForMisspelledOrUngrammaticalSelection(bool& misspe
lled, bool& ungrammatical) |
| 2004 { |
| 2005 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 2006 return guessesForMisspelledOrUngrammaticalRange(client(), frame()->selection
()->toNormalizedRange().get(), isGrammarCheckingEnabled(), misspelled, ungrammat
ical); |
| 2007 #else |
| 2008 misspelled = isSelectionMisspelled(); |
| 2009 if (misspelled) { |
| 2010 ungrammatical = false; |
| 2011 return guessesForMisspelledSelection(); |
| 2012 } |
| 2013 if (isGrammarCheckingEnabled() && isSelectionUngrammatical()) { |
| 2014 ungrammatical = true; |
| 2015 return guessesForUngrammaticalSelection(); |
| 2016 } |
| 2017 ungrammatical = false; |
| 2018 return Vector<String>(); |
| 2019 #endif |
| 2020 } |
| 2021 |
1803 void Editor::showSpellingGuessPanel() | 2022 void Editor::showSpellingGuessPanel() |
1804 { | 2023 { |
1805 if (!client()) { | 2024 if (!client()) { |
1806 LOG_ERROR("No NSSpellChecker"); | 2025 LOG_ERROR("No NSSpellChecker"); |
1807 return; | 2026 return; |
1808 } | 2027 } |
1809 | 2028 |
1810 #ifndef BUILDING_ON_TIGER | 2029 #ifndef BUILDING_ON_TIGER |
1811 // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave
Tiger behavior alone | 2030 // Post-Tiger, this menu item is a show/hide toggle, to match AppKit. Leave
Tiger behavior alone |
1812 // to match rest of OS X. | 2031 // to match rest of OS X. |
(...skipping 12 matching lines...) Expand all Loading... |
1825 if (!client()) | 2044 if (!client()) |
1826 return false; | 2045 return false; |
1827 return client()->spellingUIIsShowing(); | 2046 return client()->spellingUIIsShowing(); |
1828 } | 2047 } |
1829 | 2048 |
1830 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p) | 2049 void Editor::markMisspellingsAfterTypingToPosition(const VisiblePosition &p) |
1831 { | 2050 { |
1832 if (!isContinuousSpellCheckingEnabled()) | 2051 if (!isContinuousSpellCheckingEnabled()) |
1833 return; | 2052 return; |
1834 | 2053 |
| 2054 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 2055 VisibleSelection adjacentWords = VisibleSelection(startOfWord(p, LeftWordIfO
nBoundary), endOfWord(p, RightWordIfOnBoundary)); |
| 2056 if (isGrammarCheckingEnabled()) { |
| 2057 VisibleSelection selectedSentence = VisibleSelection(startOfSentence(p),
endOfSentence(p)); |
| 2058 markMisspellingsAndBadGrammar(adjacentWords, true, selectedSentence); |
| 2059 } else { |
| 2060 markMisspellingsAndBadGrammar(adjacentWords, false, adjacentWords); |
| 2061 } |
| 2062 #else |
1835 // Check spelling of one word | 2063 // Check spelling of one word |
1836 markMisspellings(VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endO
fWord(p, RightWordIfOnBoundary))); | 2064 markMisspellings(VisibleSelection(startOfWord(p, LeftWordIfOnBoundary), endO
fWord(p, RightWordIfOnBoundary))); |
1837 | 2065 |
1838 if (!isGrammarCheckingEnabled()) | 2066 if (!isGrammarCheckingEnabled()) |
1839 return; | 2067 return; |
1840 | 2068 |
1841 // Check grammar of entire sentence | 2069 // Check grammar of entire sentence |
1842 markBadGrammar(VisibleSelection(startOfSentence(p), endOfSentence(p))); | 2070 markBadGrammar(VisibleSelection(startOfSentence(p), endOfSentence(p))); |
| 2071 #endif |
1843 } | 2072 } |
1844 | 2073 |
1845 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange) | 2074 static void markAllMisspellingsInRange(EditorClient* client, Range* searchRange) |
1846 { | 2075 { |
1847 // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the retu
rn value and the "out parameter"; | 2076 // Use the "markAll" feature of findFirstMisspellingInRange. Ignore the retu
rn value and the "out parameter"; |
1848 // all we need to do is mark every instance. | 2077 // all we need to do is mark every instance. |
1849 int ignoredOffset; | 2078 int ignoredOffset; |
1850 findFirstMisspellingInRange(client, searchRange, ignoredOffset, true); | 2079 findFirstMisspellingInRange(client, searchRange, ignoredOffset, true); |
1851 } | 2080 } |
1852 | 2081 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1903 | 2132 |
1904 void Editor::markBadGrammar(const VisibleSelection& selection) | 2133 void Editor::markBadGrammar(const VisibleSelection& selection) |
1905 { | 2134 { |
1906 #ifndef BUILDING_ON_TIGER | 2135 #ifndef BUILDING_ON_TIGER |
1907 markMisspellingsOrBadGrammar(this, selection, false); | 2136 markMisspellingsOrBadGrammar(this, selection, false); |
1908 #else | 2137 #else |
1909 UNUSED_PARAM(selection); | 2138 UNUSED_PARAM(selection); |
1910 #endif | 2139 #endif |
1911 } | 2140 } |
1912 | 2141 |
| 2142 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 2143 |
| 2144 static void markAllMisspellingsAndBadGrammarInRanges(EditorClient* client, Range
*spellingRange, bool markGrammar, Range *grammarRange) |
| 2145 { |
| 2146 // This function is called with selections already expanded to word boundari
es. |
| 2147 ExceptionCode ec; |
| 2148 if (!client || !spellingRange || (markGrammar && !grammarRange)) |
| 2149 return; |
| 2150 |
| 2151 // If we're not in an editable node, bail. |
| 2152 Node* editableNode = spellingRange->startContainer(); |
| 2153 if (!editableNode || !editableNode->isContentEditable()) |
| 2154 return; |
| 2155 |
| 2156 // Expand the range to encompass entire paragraphs, since text checking need
s that much context. |
| 2157 int spellingRangeStartOffset; |
| 2158 int spellingRangeEndOffset; |
| 2159 int grammarRangeStartOffset; |
| 2160 int grammarRangeEndOffset; |
| 2161 String paragraphString; |
| 2162 |
| 2163 if (markGrammar) { |
| 2164 // The spelling range should be contained in the paragraph-aligned exten
sion of the grammar range. |
| 2165 RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(grammarRang
e, grammarRangeStartOffset, paragraphString); |
| 2166 RefPtr<Range> offsetAsRange = Range::create(paragraphRange->startContain
er(ec)->document(), paragraphRange->startPosition(), spellingRange->startPositio
n()); |
| 2167 spellingRangeStartOffset = TextIterator::rangeLength(offsetAsRange.get()
); |
| 2168 grammarRangeEndOffset = grammarRangeStartOffset + TextIterator::rangeLen
gth(grammarRange); |
| 2169 } else { |
| 2170 RefPtr<Range> paragraphRange = paragraphAlignedRangeForRange(spellingRan
ge, spellingRangeStartOffset, paragraphString); |
| 2171 } |
| 2172 spellingRangeEndOffset = spellingRangeStartOffset + TextIterator::rangeLengt
h(spellingRange); |
| 2173 if (paragraphString.length() == 0 || (spellingRangeStartOffset >= spellingRa
ngeEndOffset && (!markGrammar || grammarRangeStartOffset >= grammarRangeEndOffse
t))) |
| 2174 return; |
| 2175 |
| 2176 Vector<TextCheckingResult> results; |
| 2177 client->checkSpellingAndGrammarOfParagraph(paragraphString.characters(), par
agraphString.length(), markGrammar, results); |
| 2178 |
| 2179 for (unsigned i = 0; i < results.size(); i++) { |
| 2180 const TextCheckingResult* result = &results[i]; |
| 2181 if (result->resultType == 1 && result->location >= spellingRangeStartOff
set && result->location + result->length <= spellingRangeEndOffset) { |
| 2182 ASSERT(result->length > 0 && result->location >= 0); |
| 2183 RefPtr<Range> misspellingRange = TextIterator::subrange(spellingRang
e, result->location - spellingRangeStartOffset, result->length); |
| 2184 misspellingRange->startContainer(ec)->document()->addMarker(misspell
ingRange.get(), DocumentMarker::Spelling); |
| 2185 } else if (markGrammar && result->resultType == 2 && result->location <
grammarRangeEndOffset && result->location + result->length > grammarRangeStartOf
fset) { |
| 2186 ASSERT(result->length > 0 && result->location >= 0); |
| 2187 for (unsigned j = 0; j < result->details.size(); j++) { |
| 2188 const GrammarDetail* detail = &result->details[j]; |
| 2189 ASSERT(detail->length > 0 && detail->location >= 0); |
| 2190 if (result->location + detail->location >= grammarRangeStartOffs
et && result->location + detail->location + detail->length <= grammarRangeEndOff
set) { |
| 2191 RefPtr<Range> badGrammarRange = TextIterator::subrange(gramm
arRange, result->location + detail->location - grammarRangeStartOffset, detail->
length); |
| 2192 grammarRange->startContainer(ec)->document()->addMarker(badG
rammarRange.get(), DocumentMarker::Grammar, detail->userDescription); |
| 2193 } |
| 2194 } |
| 2195 } |
| 2196 } |
| 2197 } |
| 2198 |
| 2199 #endif |
| 2200 |
| 2201 void Editor::markMisspellingsAndBadGrammar(const VisibleSelection& spellingSelec
tion, bool markGrammar, const VisibleSelection& grammarSelection) |
| 2202 { |
| 2203 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD
) |
| 2204 if (!isContinuousSpellCheckingEnabled()) |
| 2205 return; |
| 2206 markAllMisspellingsAndBadGrammarInRanges(client(), spellingSelection.toNorma
lizedRange().get(), markGrammar && isGrammarCheckingEnabled(), grammarSelection.
toNormalizedRange().get()); |
| 2207 #else |
| 2208 markMisspellings(spellingSelection); |
| 2209 if (markGrammar) |
| 2210 markBadGrammar(grammarSelection); |
| 2211 #endif |
| 2212 } |
| 2213 |
1913 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint) | 2214 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint) |
1914 { | 2215 { |
1915 Document* document = m_frame->documentAtPoint(windowPoint); | 2216 Document* document = m_frame->documentAtPoint(windowPoint); |
1916 if (!document) | 2217 if (!document) |
1917 return 0; | 2218 return 0; |
1918 | 2219 |
1919 Frame* frame = document->frame(); | 2220 Frame* frame = document->frame(); |
1920 ASSERT(frame); | 2221 ASSERT(frame); |
1921 FrameView* frameView = frame->view(); | 2222 FrameView* frameView = frame->view(); |
1922 if (!frameView) | 2223 if (!frameView) |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2182 | 2483 |
2183 if (!wrapFlag) | 2484 if (!wrapFlag) |
2184 return Range::create(m_frame->document()); | 2485 return Range::create(m_frame->document()); |
2185 | 2486 |
2186 if (forward) | 2487 if (forward) |
2187 return firstVisibleRange(target, caseFlag); | 2488 return firstVisibleRange(target, caseFlag); |
2188 | 2489 |
2189 return lastVisibleRange(target, caseFlag); | 2490 return lastVisibleRange(target, caseFlag); |
2190 } | 2491 } |
2191 | 2492 |
| 2493 void Editor::changeSelectionAfterCommand(const VisibleSelection& newSelection, b
ool closeTyping, bool clearTypingStyle, EditCommand* cmd) |
| 2494 { |
| 2495 // If there is no selection change, don't bother sending shouldChangeSelecti
on, but still call setSelection, |
| 2496 // because there is work that it must do in this situation. |
| 2497 // The old selection can be invalid here and calling shouldChangeSelection c
an produce some strange calls. |
| 2498 // See <rdar://problem/5729315> Some shouldChangeSelectedDOMRange contain Ra
nges for selections that are no longer valid |
| 2499 bool selectionDidNotChangeDOMPosition = newSelection == m_frame->selection()
->selection(); |
| 2500 if (selectionDidNotChangeDOMPosition || m_frame->shouldChangeSelection(newSe
lection)) |
| 2501 m_frame->selection()->setSelection(newSelection, closeTyping, clearTypin
gStyle); |
| 2502 |
| 2503 // Some kinds of deletes and line break insertions change the selection's po
sition within the document without |
| 2504 // changing its position within the DOM. For example when you press return
in the following (the caret is marked by ^): |
| 2505 // <div contentEditable="true"><div>^Hello</div></div> |
| 2506 // WebCore inserts <div><br></div> *before* the current block, which correct
ly moves the paragraph down but which doesn't |
| 2507 // change the caret's DOM position (["hello", 0]). In these situations the
above SelectionController::setSelection call |
| 2508 // does not call EditorClient::respondToChangedSelection(), which, on the Ma
c, sends selection change notifications and |
| 2509 // starts a new kill ring sequence, but we want to do these things (matches
AppKit). |
| 2510 if (selectionDidNotChangeDOMPosition && cmd->isTypingCommand()) |
| 2511 client()->respondToChangedSelection(); |
| 2512 } |
| 2513 |
2192 } // namespace WebCore | 2514 } // namespace WebCore |
2193 | |
2194 | |
2195 | |
2196 | |
OLD | NEW |