WebCore:
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Sep 2007 23:03:57 +0000 (23:03 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 13 Sep 2007 23:03:57 +0000 (23:03 +0000)
        Reviewed by Oliver.

        - fix <rdar://problem/5470457> REGRESSION: Input method inline hole is mishandled in text
          <input> elements with maxlength limit

        * editing/Editor.h: Moved MarkedTextUnderline here and renamed it CompositionUnderline.
        Moved the rest of the marked text API here and used the term that will be more familiar
        to those on platforms other than Macintosh, "composition". This helps prevent confusion
        with the other kinds of mark -- the emacs "mark" and spelling/grammar marks. Also
        cleaned up the conditionals a bit for the Macintosh-specific parts of this header.

        * editing/Editor.cpp:
        (WebCore::Editor::Editor): Updated for name change.
        (WebCore::Editor::clear): Added. To be called by FrameLoader::clear().
        (WebCore::Editor::insertTextWithoutSendingTextEvent): Removed code to make inserted
        text replace the marked text range -- we now deal with this explicitly by not
        calling this function to replace marked text. Also removed unneeded code that was
        specific to the use of this to replace the marked text.
        (WebCore::Editor::selectComposition): Renamed from selectMarkedText. Updated since
        the composition range is not stored as a Range.
        (WebCore::Editor::confirmComposition): Added. To be called when changing a composition
        into actual text. Unlike the old code path, deletes the composition first, then inserts
        the text, triggering the normal insertion code path and events. This is helpful because
        it means the inserted text will be truncated by the <input> element, for example.
        (WebCore::Editor::confirmCompositionWithoutDisturbingSelection): Added.
        (WebCore::Editor::setComposition): Added. To be called when changing the composition.
        Takes parameters for the underlines and selection. Unlike the old code path, this passes
        a flag down that indicates the inserted text is part of a composition. This is helpful
        because we don't send the event that will cause the <input> element to do truncation.
        It's also a better API for future improvements to our input method handling.
        (WebCore::Editor::revealSelectionAfterEditingOperation): Updated for name change.
        (WebCore::Editor::setIgnoreCompositionSelectionChange): Ditto.
        (WebCore::Editor::compositionRange): Added. Needed now that the composition is not
        stored as a Range.
        (WebCore::Editor::getCompositionSelection): Added.

        * editing/TypingCommand.h:
        * editing/TypingCommand.cpp: (WebCore::TypingCommand::insertText):
        Added an insertedTextIsComposition parameter, and don't send the BeforeTextInsertedEvent
        if it's true.

        * loader/FrameLoader.cpp: (WebCore::FrameLoader::clear): Replaced the Macintosh-specific
        call to setMarkedTextRange with a call to the new Editor::clear().

        * page/Frame.h:
        * page/Frame.cpp:
        * page/FramePrivate.h:
        * page/mac/FrameMac.mm:
        Removed the marked text code. It was streamlined and moved to Editor, except for the
        Mac-specific code, which was moved into WebKit.

        * page/mac/WebCoreFrameBridge.h:
        * page/mac/WebCoreFrameBridge.mm: Removed some now-unneeded marked text code.
        (-[WebCoreFrameBridge markedTextNSRange]): Updated for name/API change.

        * rendering/InlineTextBox.h:
        * rendering/InlineTextBox.cpp:
        (WebCore::InlineTextBox::paint): Updated marked text code for name changes, and also
        streamlined the code a bit for the case where there is no composition.
        (WebCore::InlineTextBox::paintCompositionBackground): Name change.
        (WebCore::InlineTextBox::paintCompositionUnderline): Ditto.

        * rendering/RenderTextControl.h:
        * rendering/RenderTextControl.cpp:
        (WebCore::RenderTextControl::finishText): Added. Helper function shared by the
        (WebCore::RenderTextControl::text):
        (WebCore::getNextSoftBreak):
        (WebCore::RenderTextControl::textWithHardLineBreaks):

        * platform/CharacterNames.h: Added newlineCharacter.

        * dom/Range.h: Remove the now-unneeded version of toString that converts <br>
        elements into newlines.
        * dom/Range.cpp:
        (WebCore::Range::toString): Changed this to use a Vector<UChar> instead of
        a String so it will not have pathological reallocation performance, and removed
        the <br> feature.
        (WebCore::Range::pastEndNode): Made this return 0 when there is no start node.
        This bit of extra robustness guarantees you can't do a null dereference if the
        start node is 0 and the end node is not. Not sure this case really exists.

        * page/ContextMenuController.cpp: (ContextMenuController::contextMenuItemSelected):
        Removed a semi-bogus use of Range::toString(true). The right function to use here
        is plainText().

        * bridge/EditorClient.h: Removed obsolete markedTextAbandoned function.

        * WebCore.exp: Updated for above changes.

WebKit:

        Reviewed by Oliver.

        - fix <rdar://problem/5470457> REGRESSION: Input method inline hole is mishandled in text
          <input> elements with maxlength limit

        * WebView/WebHTMLView.mm:
        (-[WebHTMLView _selectionChanged]): Tweaked code a bit.
        (-[WebHTMLView markedRange]): Simplified logic, since markedTextNSRange works when there's
        no composition range.
        (-[WebHTMLView hasMarkedText]): Call directly to Editor instead of bridge.
        (-[WebHTMLView unmarkText]): Call new confirmComposition to make it clear that this is
        confirming text, not just unmarking it to discard it.
        (extractUnderlines): Added. Converts directly from an NSAttributedString to the
        CompositionUnderline vector that's used by WebCore.
        (-[WebHTMLView setMarkedText:selectedRange:]): Changed to use the new setComposition.
        (-[WebHTMLView insertText:]): Changed to use confirmComposition when appropriate, instead
        of relying on special behavior of Editor::insertText.
        (-[WebHTMLView _updateSelectionForInputManager]): Rewrote to use getCompositionSelection
        and confirmCompositionWithoutDisturbingSelection.

        * WebCoreSupport/WebEditorClient.h:
        * WebCoreSupport/WebEditorClient.mm:
        Removed obsolete markedTextAbandoned function.

win:

        Reviewed by Oliver.

        - fix <rdar://problem/5470457> REGRESSION: Input method inline hole is mishandled in text
          <input> elements with maxlength limit

        * WebView.cpp:
        (WebView::resetIME): Change to use confirmCompositionWithoutDisturbingSelection.
        (WebView::updateSelectionForIME): Update for name changes, and to use new functions
        in Editor.
        (WebView::onIMEStartComposition): Removed unneeded call to unmarkText.
        (compositionToUnderlines): Removed startOffset parameter, since setComposition now
        handles this.
        (WebView::onIMEComposition): Changed to use confirmComposition and setComposition.
        Logic gets a lot cleaner.
        (WebView::onIMEEndComposition): Removed unneeded calls to Editor.
        (WebView::onIMERequestCharPosition): Updated for name changes.

LayoutTests:

        Reviewed by Oliver.

        - updated test results changed by change in input manager logic

        * platform/mac/editing/input/firstrectforcharacterrange-styled-expected.txt:
        * platform/mac/editing/input/text-input-controller-expected.txt:
        * platform/mac/editing/input/wrapped-line-char-rect-expected.txt:
        Updated. Small changes in which delegate methods are called.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@25547 268f45cc-cd09-0410-ab3c-d52691b4dbfc

32 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac/editing/input/firstrectforcharacterrange-styled-expected.txt
LayoutTests/platform/mac/editing/input/text-input-controller-expected.txt
LayoutTests/platform/mac/editing/input/wrapped-line-char-rect-expected.txt
WebCore/ChangeLog
WebCore/WebCore.exp
WebCore/bridge/EditorClient.h
WebCore/dom/Range.cpp
WebCore/dom/Range.h
WebCore/editing/Editor.cpp
WebCore/editing/Editor.h
WebCore/editing/TypingCommand.cpp
WebCore/editing/TypingCommand.h
WebCore/loader/FrameLoader.cpp
WebCore/page/ContextMenuController.cpp
WebCore/page/Frame.cpp
WebCore/page/Frame.h
WebCore/page/FramePrivate.h
WebCore/page/mac/FrameMac.mm
WebCore/page/mac/WebCoreFrameBridge.h
WebCore/page/mac/WebCoreFrameBridge.mm
WebCore/platform/CharacterNames.h
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/InlineTextBox.h
WebCore/rendering/RenderTextControl.cpp
WebCore/rendering/RenderTextControl.h
WebKit/ChangeLog
WebKit/WebCoreSupport/WebEditorClient.h
WebKit/WebCoreSupport/WebEditorClient.mm
WebKit/WebView/WebHTMLView.mm
WebKit/win/ChangeLog
WebKit/win/WebView.cpp

index 8f2fb6f..2cae45f 100644 (file)
@@ -1,6 +1,17 @@
+2007-09-13  Darin Adler  <darin@apple.com>
+
+        Reviewed by Oliver.
+
+        - updated test results changed by change in input manager logic
+
+        * platform/mac/editing/input/firstrectforcharacterrange-styled-expected.txt:
+        * platform/mac/editing/input/text-input-controller-expected.txt:
+        * platform/mac/editing/input/wrapped-line-char-rect-expected.txt:
+        Updated. Small changes in which delegate methods are called.
+
 2007-09-13  Kevin McCullough  <kmccullough@apple.com>
 
-        Reviewed by Geof, Sam, Adam, Hyatt, Darin.
+        Reviewed by Geoff, Sam, Adam, Hyatt, Darin.
 
         - <rdar://problem/5480234> JS setTimeout function requires a second argument
         - Removed check for number of arguments in setTimeout to behave like other browsers.
index acfd52f..89cc896 100644 (file)
@@ -1,6 +1,7 @@
 EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of BODY > HTML > #document to 4 of BODY > HTML > #document
 EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 1 of #text > I > B > BODY > HTML > #document to 1 of #text > I > B > BODY > HTML > #document toDOMRange:range from 1 of #text > I > B > BODY > HTML > #document to 3 of #text > I > B > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
index cbc68b4..93bfb42 100644 (file)
@@ -14,11 +14,11 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldDeleteDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
@@ -27,5 +27,15 @@ EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotificatio
 EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
-EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldInsertText:Success replacingDOMRange:range from 0 of DIV > BODY > HTML > #document to 0 of DIV > BODY > HTML > #document givenAction:WebViewInsertActionTyped
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:(null) toDOMRange:range from 7 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
+EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 7 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document toDOMRange:range from 0 of #text > DIV > BODY > HTML > #document to 7 of #text > DIV > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 Success
index 3531e97..1160f42 100644 (file)
@@ -1,6 +1,7 @@
 EDITING DELEGATE: shouldBeginEditingInDOMRange:range from 0 of P > BODY > HTML > #document to 0 of P > BODY > HTML > #document
 EDITING DELEGATE: webViewDidBeginEditing:WebViewDidBeginEditingNotification
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
 EDITING DELEGATE: shouldChangeSelectedDOMRange:range from 0 of P > BODY > HTML > #document to 0 of P > BODY > HTML > #document toDOMRange:range from 0 of #text > P > BODY > HTML > #document to 20 of #text > P > BODY > HTML > #document affinity:NSSelectionAffinityDownstream stillSelecting:FALSE
 EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
 EDITING DELEGATE: webViewDidChange:WebViewDidChangeNotification
index 42382ca..bfa791b 100644 (file)
@@ -1,3 +1,94 @@
+2007-09-13  Darin Adler  <darin@apple.com>
+
+        Reviewed by Oliver.
+
+        - fix <rdar://problem/5470457> REGRESSION: Input method inline hole is mishandled in text
+          <input> elements with maxlength limit
+
+        * editing/Editor.h: Moved MarkedTextUnderline here and renamed it CompositionUnderline.
+        Moved the rest of the marked text API here and used the term that will be more familiar
+        to those on platforms other than Macintosh, "composition". This helps prevent confusion
+        with the other kinds of mark -- the emacs "mark" and spelling/grammar marks. Also
+        cleaned up the conditionals a bit for the Macintosh-specific parts of this header.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::Editor): Updated for name change.
+        (WebCore::Editor::clear): Added. To be called by FrameLoader::clear().
+        (WebCore::Editor::insertTextWithoutSendingTextEvent): Removed code to make inserted
+        text replace the marked text range -- we now deal with this explicitly by not
+        calling this function to replace marked text. Also removed unneeded code that was
+        specific to the use of this to replace the marked text.
+        (WebCore::Editor::selectComposition): Renamed from selectMarkedText. Updated since
+        the composition range is not stored as a Range.
+        (WebCore::Editor::confirmComposition): Added. To be called when changing a composition
+        into actual text. Unlike the old code path, deletes the composition first, then inserts
+        the text, triggering the normal insertion code path and events. This is helpful because
+        it means the inserted text will be truncated by the <input> element, for example.
+        (WebCore::Editor::confirmCompositionWithoutDisturbingSelection): Added.
+        (WebCore::Editor::setComposition): Added. To be called when changing the composition.
+        Takes parameters for the underlines and selection. Unlike the old code path, this passes
+        a flag down that indicates the inserted text is part of a composition. This is helpful
+        because we don't send the event that will cause the <input> element to do truncation.
+        It's also a better API for future improvements to our input method handling.
+        (WebCore::Editor::revealSelectionAfterEditingOperation): Updated for name change.
+        (WebCore::Editor::setIgnoreCompositionSelectionChange): Ditto.
+        (WebCore::Editor::compositionRange): Added. Needed now that the composition is not
+        stored as a Range.
+        (WebCore::Editor::getCompositionSelection): Added.
+
+        * editing/TypingCommand.h:
+        * editing/TypingCommand.cpp: (WebCore::TypingCommand::insertText):
+        Added an insertedTextIsComposition parameter, and don't send the BeforeTextInsertedEvent
+        if it's true.
+
+        * loader/FrameLoader.cpp: (WebCore::FrameLoader::clear): Replaced the Macintosh-specific
+        call to setMarkedTextRange with a call to the new Editor::clear().
+
+        * page/Frame.h:
+        * page/Frame.cpp:
+        * page/FramePrivate.h:
+        * page/mac/FrameMac.mm:
+        Removed the marked text code. It was streamlined and moved to Editor, except for the
+        Mac-specific code, which was moved into WebKit.
+
+        * page/mac/WebCoreFrameBridge.h:
+        * page/mac/WebCoreFrameBridge.mm: Removed some now-unneeded marked text code.
+        (-[WebCoreFrameBridge markedTextNSRange]): Updated for name/API change.
+
+        * rendering/InlineTextBox.h:
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::paint): Updated marked text code for name changes, and also
+        streamlined the code a bit for the case where there is no composition.
+        (WebCore::InlineTextBox::paintCompositionBackground): Name change.
+        (WebCore::InlineTextBox::paintCompositionUnderline): Ditto.
+
+        * rendering/RenderTextControl.h:
+        * rendering/RenderTextControl.cpp:
+        (WebCore::RenderTextControl::finishText): Added. Helper function shared by the
+        (WebCore::RenderTextControl::text):
+        (WebCore::getNextSoftBreak):
+        (WebCore::RenderTextControl::textWithHardLineBreaks):
+
+        * platform/CharacterNames.h: Added newlineCharacter.
+
+        * dom/Range.h: Remove the now-unneeded version of toString that converts <br>
+        elements into newlines.
+        * dom/Range.cpp:
+        (WebCore::Range::toString): Changed this to use a Vector<UChar> instead of
+        a String so it will not have pathological reallocation performance, and removed
+        the <br> feature.
+        (WebCore::Range::pastEndNode): Made this return 0 when there is no start node.
+        This bit of extra robustness guarantees you can't do a null dereference if the
+        start node is 0 and the end node is not. Not sure this case really exists.
+
+        * page/ContextMenuController.cpp: (ContextMenuController::contextMenuItemSelected):
+        Removed a semi-bogus use of Range::toString(true). The right function to use here
+        is plainText().
+
+        * bridge/EditorClient.h: Removed obsolete markedTextAbandoned function.
+
+        * WebCore.exp: Updated for above changes. 
+
 2007-09-13  Anders Carlsson  <andersca@apple.com>
 
         Reviewed by Adam and Geoff.
index 823e21f..f0be982 100644 (file)
@@ -310,6 +310,7 @@ __ZN7WebCore16MIMETypeRegistry32isSupportedImageResourceMIMETypeERKNS_6StringE
 __ZN7WebCore16NavigationActionC1ERKNS_4KURLENS_13FrameLoadTypeEb
 __ZN7WebCore16NavigationActionC1ERKNS_4KURLENS_14NavigationTypeE
 __ZN7WebCore16NavigationActionC1Ev
+__ZN7WebCore16colorFromNSColorEP7NSColor
 __ZN7WebCore18PlatformMouseEventC1EP7NSEvent
 __ZN7WebCore19InspectorController16setWindowVisibleEb
 __ZN7WebCore19InspectorController7inspectEPNS_4NodeE
@@ -373,7 +374,6 @@ __ZN7WebCore5Frame18windowScriptObjectEv
 __ZN7WebCore5Frame20setSelectionFromNoneEv
 __ZN7WebCore5Frame20windowScriptNPObjectEv
 __ZN7WebCore5Frame21setProhibitsScrollingEb
-__ZN7WebCore5Frame23selectRangeInMarkedTextEjj
 __ZN7WebCore5Frame26dashboardRegionsDictionaryEv
 __ZN7WebCore5Frame29cleanupScriptObjectsForPluginEPv
 __ZN7WebCore5Frame4initEv
@@ -389,7 +389,6 @@ __ZN7WebCore5equalEPKNS_10StringImplEPKc
 __ZN7WebCore5equalEPKNS_10StringImplES2_
 __ZN7WebCore6Editor10applyStyleEPNS_19CSSStyleDeclarationENS_10EditActionE
 __ZN7WebCore6Editor10insertTextERKNS_6StringEPNS_5EventE
-__ZN7WebCore6Editor10unmarkTextEv
 __ZN7WebCore6Editor11canDHTMLCutEv
 __ZN7WebCore6Editor11deleteRangeEPNS_5RangeEbbbNS_18EditorDeleteActionENS_15TextGranularityE
 __ZN7WebCore6Editor11execCommandERKNS_12AtomicStringEPNS_5EventE
@@ -400,11 +399,11 @@ __ZN7WebCore6Editor13canDHTMLPasteEv
 __ZN7WebCore6Editor13performDeleteEv
 __ZN7WebCore6Editor13rangeForPointERKNS_8IntPointE
 __ZN7WebCore6Editor13tryDHTMLPasteEv
+__ZN7WebCore6Editor14setCompositionERKNS_6StringERKN3WTF6VectorINS_20CompositionUnderlineELm0EEEjj
 __ZN7WebCore6Editor16pasteAsPlainTextEv
-__ZN7WebCore6Editor16selectMarkedTextEv
-__ZN7WebCore6Editor17discardMarkedTextEv
 __ZN7WebCore6Editor17insertOrderedListEv
-__ZN7WebCore6Editor17replaceMarkedTextERKNS_6StringE
+__ZN7WebCore6Editor18confirmCompositionERKNS_6StringE
+__ZN7WebCore6Editor18confirmCompositionEv
 __ZN7WebCore6Editor19deleteWithDirectionENS_19SelectionController10EDirectionENS_15TextGranularityEbb
 __ZN7WebCore6Editor19insertUnorderedListEv
 __ZN7WebCore6Editor21applyStyleToSelectionEPNS_19CSSStyleDeclarationENS_10EditActionE
@@ -420,9 +419,10 @@ __ZN7WebCore6Editor30deleteSelectionWithSmartDeleteEb
 __ZN7WebCore6Editor32guessesForUngrammaticalSelectionEv
 __ZN7WebCore6Editor33increaseSelectionListLevelOrderedEv
 __ZN7WebCore6Editor33insertTextWithoutSendingTextEventERKNS_6StringEbPNS_5EventE
-__ZN7WebCore6Editor34setIgnoreMarkedTextSelectionChangeEb
 __ZN7WebCore6Editor35increaseSelectionListLevelUnorderedEv
+__ZN7WebCore6Editor35setIgnoreCompositionSelectionChangeEb
 __ZN7WebCore6Editor3cutEv
+__ZN7WebCore6Editor44confirmCompositionWithoutDisturbingSelectionEv
 __ZN7WebCore6Editor4copyEv
 __ZN7WebCore6Editor5pasteEv
 __ZN7WebCore6Editor6indentEv
@@ -648,6 +648,7 @@ __ZNK7WebCore5Range9startNodeEv
 __ZNK7WebCore6Editor13canEditRichlyEv
 __ZNK7WebCore6Editor17shouldDeleteRangeEPNS_5RangeE
 __ZNK7WebCore6Editor22selectionStartHasStyleEPNS_19CSSStyleDeclarationE
+__ZNK7WebCore6Editor23getCompositionSelectionERjS1_
 __ZNK7WebCore6Editor6canCutEv
 __ZNK7WebCore6Editor7canCopyEv
 __ZNK7WebCore6Editor7canEditEv
index f892e0b..fd5a327 100644 (file)
@@ -119,8 +119,6 @@ public:
     virtual void textDidChangeInTextArea(Element*) = 0;
 
 #if PLATFORM(MAC)
-    virtual void markedTextAbandoned(Frame*) = 0;
-
     // FIXME: This should become SelectionController::toWebArchive()
     virtual NSData* dataForArchivedSelection(Frame*) = 0; 
 
index 44e97ee..ff179f8 100644 (file)
@@ -1,11 +1,9 @@
 /**
- * This file is part of the DOM implementation for KDE.
- *
  * (C) 1999 Lars Knoll (knoll@kde.org)
  * (C) 2000 Gunnstein Lye (gunnstein@netcom.no)
  * (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -41,6 +39,7 @@
 
 namespace WebCore {
 
+using namespace std;
 using namespace HTMLNames;
 
 #ifndef NDEBUG
@@ -1031,31 +1030,25 @@ void Range::insertNode(PassRefPtr<Node> newNode, ExceptionCode& ec)
 
 String Range::toString(ExceptionCode& ec) const
 {
-    return toString(false, ec);
-}
-
-String Range::toString(bool convertBRsToNewlines, ExceptionCode& ec) const
-{
     if (m_detached) {
         ec = INVALID_STATE_ERR;
         return String();
     }
 
-    String text = "";
-    Node *pastEnd = pastEndNode();
-    for (Node *n = startNode(); n != pastEnd; n = n->traverseNextNode()) {
+    Vector<UChar> result;
+
+    Node* pastEnd = pastEndNode();
+    for (Node* n = startNode(); n != pastEnd; n = n->traverseNextNode()) {
         if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE) {
-            String str = static_cast<Text *>(n)->data().copy();
-            if (n == m_endContainer)
-                str.truncate(m_endOffset);
-            if (n == m_startContainer)
-                str.remove(0, m_startOffset);
-            text += str;
+            String data = static_cast<CharacterData*>(n)->data();
+            unsigned length = data.length();
+            unsigned start = (n == m_startContainer) ? min(m_startOffset, length) : 0;
+            unsigned end = (n == m_endContainer) ? min(max(start, m_endOffset), length) : length;
+            result.append(data.characters() + start, end - start);
         }
-        if (n->hasTagName(brTag) && convertBRsToNewlines)
-            text += "\n";
     }
-    return text;
+
+    return String::adopt(result);
 }
 
 String Range::toHTML() const
@@ -1530,7 +1523,7 @@ Position Range::editingStartPosition() const
 
 Node *Range::pastEndNode() const
 {
-    if (!m_endContainer)
+    if (!m_startContainer || !m_endContainer)
         return 0;
     if (m_endContainer->offsetInCharacters())
         return m_endContainer->traverseNextSibling();
index 9e82700..7aaa03a 100644 (file)
@@ -79,7 +79,6 @@ public:
     PassRefPtr<DocumentFragment> cloneContents(ExceptionCode&);
     void insertNode(PassRefPtr<Node>, ExceptionCode&);
     String toString(ExceptionCode&) const;
-    String toString(bool convertBRsToNewlines, ExceptionCode&) const;
 
     String toHTML() const;
     String text() const;
index 5979d8a..fe0aa69 100644 (file)
@@ -64,6 +64,7 @@
 #include "ReplaceSelectionCommand.h"
 #include "SelectionController.h"
 #include "Sound.h"
+#include "Text.h"
 #include "TextIterator.h"
 #include "TypingCommand.h"
 #include "htmlediting.h"
@@ -73,6 +74,8 @@
 namespace WebCore {
 
 class FontData;
+
+using namespace std;
 using namespace EventNames;
 using namespace HTMLNames;
 
@@ -1354,7 +1357,7 @@ static CommandMap* createCommandMap()
 Editor::Editor(Frame* frame)
     : m_frame(frame)
     , m_deleteButtonController(new DeleteButtonController(frame))
-    , m_ignoreMarkedTextSelectionChange(false)
+    , m_ignoreCompositionSelectionChange(false)
 { 
 }
 
@@ -1362,6 +1365,12 @@ Editor::~Editor()
 {
 }
 
+void Editor::clear()
+{
+    m_compositionNode = 0;
+    m_customCompositionUnderlines.clear();
+}
+
 bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
 {
     if (!m_frame->document())
@@ -1395,28 +1404,18 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
     if (text.isEmpty())
         return false;
 
-    RefPtr<Range> range = m_frame->markedTextRange();
-    if (!range) {
-        Selection selection = selectionForEvent(m_frame, triggeringEvent);
-        if (!selection.isContentEditable())
-            return false;
-        range = selection.toRange();
-    }
+    Selection selection = selectionForEvent(m_frame, triggeringEvent);
+    if (!selection.isContentEditable())
+        return false;
+    RefPtr<Range> range = selection.toRange();
 
-    if (!shouldInsertText(text, range.get(), EditorInsertActionTyped)) {
-        discardMarkedText();
+    if (!shouldInsertText(text, range.get(), EditorInsertActionTyped))
         return true;
-    }
-
-    setIgnoreMarkedTextSelectionChange(true);
-
-    // If we had marked text, replace that instead of the selection/caret.
-    selectMarkedText();
 
     // Get the selection to use for the event that triggered this insertText.
     // If the event handler changed the selection, we may want to use a different selection
     // that is contained in the event target.
-    Selection selection = selectionForEvent(m_frame, triggeringEvent);
+    selection = selectionForEvent(m_frame, triggeringEvent);
     if (selection.isContentEditable()) {
         if (Node* selectionStart = selection.start().node()) {
             RefPtr<Document> document = selectionStart->document();
@@ -1431,11 +1430,6 @@ bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectIn
         }
     }
 
-    setIgnoreMarkedTextSelectionChange(false);
-
-    // Inserting unmarks any marked text.
-    unmarkText();
-
     return true;
 }
 
@@ -1664,54 +1658,103 @@ void Editor::setBaseWritingDirection(String direction)
     applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection);
 }
 
-void Editor::selectMarkedText()
+void Editor::selectComposition()
 {
-    Range* range = m_frame->markedTextRange();
+    RefPtr<Range> range = compositionRange();
     if (!range)
         return;
     ExceptionCode ec = 0;
-    m_frame->selectionController()->setSelectedRange(m_frame->markedTextRange(), DOWNSTREAM, false, ec);
+    m_frame->selectionController()->setSelectedRange(range.get(), DOWNSTREAM, false, ec);
 }
 
-void Editor::discardMarkedText()
+void Editor::confirmComposition()
 {
-    if (!m_frame->markedTextRange())
+    if (!m_compositionNode)
         return;
+    confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), false);
+}
 
-    setIgnoreMarkedTextSelectionChange(true);
-
-    selectMarkedText();
-    unmarkText();
-#if PLATFORM(MAC)
-    if (EditorClient* c = client())
-        c->markedTextAbandoned(m_frame);
-#endif
-    deleteSelectionWithSmartDelete(false);
+void Editor::confirmCompositionWithoutDisturbingSelection()
+{
+    if (!m_compositionNode)
+        return;
+    confirmComposition(m_compositionNode->data().substring(m_compositionStart, m_compositionEnd - m_compositionStart), true);
+}
 
-    setIgnoreMarkedTextSelectionChange(false);
+void Editor::confirmComposition(const String& text)
+{
+    confirmComposition(text, false);
 }
 
-void Editor::unmarkText()
+void Editor::confirmComposition(const String& text, bool preserveSelection)
 {
-    Vector<MarkedTextUnderline> underlines;
-    m_frame->setMarkedTextRange(0, underlines);
+    setIgnoreCompositionSelectionChange(true);
+
+    Selection oldSelection = m_frame->selectionController()->selection();
+
+    selectComposition();
+
+    if (m_frame->selectionController()->isNone()) {
+        setIgnoreCompositionSelectionChange(false);
+        return;
+    }
+
+    deleteSelectionWithSmartDelete(false);
+
+    m_compositionNode = 0;
+    m_customCompositionUnderlines.clear();
+
+    insertText(text, 0);
+
+    if (preserveSelection)
+        m_frame->selectionController()->setSelection(oldSelection, false, false);
+
+    setIgnoreCompositionSelectionChange(false);
 }
 
-void Editor::replaceMarkedText(const String& text)
+void Editor::setComposition(const String& text, const Vector<CompositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd)
 {
-    if (m_frame->selectionController()->isNone())
+    setIgnoreCompositionSelectionChange(true);
+
+    selectComposition();
+
+    if (m_frame->selectionController()->isNone()) {
+        setIgnoreCompositionSelectionChange(false);
         return;
-    
-    int exception = 0;
-    
-    Range *markedTextRange = m_frame->markedTextRange();
-    if (markedTextRange && !markedTextRange->collapsed(exception))
-        TypingCommand::deleteKeyPressed(m_frame->document(), false);
-    
-    if (!text.isEmpty())
-        TypingCommand::insertText(m_frame->document(), text, true);
-    
-    revealSelectionAfterEditingOperation();
+    }
+
+    deleteSelectionWithSmartDelete(false);
+
+    if (!text.isEmpty()) {
+        TypingCommand::insertText(m_frame->document(), text, true, true);
+
+        Node* baseNode = m_frame->selectionController()->baseNode();
+        unsigned baseOffset = m_frame->selectionController()->base().offset();
+        Node* extentNode = m_frame->selectionController()->extentNode();
+        unsigned extentOffset = m_frame->selectionController()->extent().offset();
+
+        if (baseNode && baseNode == extentNode && baseNode->isTextNode() && baseOffset + text.length() == extentOffset) {
+            m_compositionNode = static_cast<Text*>(baseNode);
+            m_compositionStart = baseOffset;
+            m_compositionEnd = extentOffset;
+            m_customCompositionUnderlines = underlines;
+            size_t numUnderlines = m_customCompositionUnderlines.size();
+            for (size_t i = 0; i < numUnderlines; ++i) {
+                m_customCompositionUnderlines[i].startOffset += baseOffset;
+                m_customCompositionUnderlines[i].endOffset += baseOffset;
+            }
+            if (baseNode->renderer())
+                baseNode->renderer()->repaint();
+
+            unsigned start = min(baseOffset + selectionStart, extentOffset);
+            unsigned end = min(max(start, baseOffset + selectionEnd), extentOffset);
+            RefPtr<Range> selectedRange = new Range(baseNode->document(), baseNode, start, baseNode, end);                
+            ExceptionCode ec = 0;
+            m_frame->selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false, ec);
+        }
+    }
+
+    setIgnoreCompositionSelectionChange(false);
 }
 
 void Editor::ignoreSpelling()
@@ -2269,8 +2312,7 @@ void Editor::markBadGrammar(const Selection& selection)
     markMisspellingsOrBadGrammar(this, selection, false);
 #endif
 }
-    
-    
+
 PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
 {
     Document* document = m_frame->documentAtPoint(windowPoint);
@@ -2289,20 +2331,53 @@ PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
 
 void Editor::revealSelectionAfterEditingOperation()
 {
-    if (m_ignoreMarkedTextSelectionChange)
+    if (m_ignoreCompositionSelectionChange)
         return;
 
     m_frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded);
 }
 
-void Editor::setIgnoreMarkedTextSelectionChange(bool ignore)
+void Editor::setIgnoreCompositionSelectionChange(bool ignore)
 {
-    if (m_ignoreMarkedTextSelectionChange == ignore)
+    if (m_ignoreCompositionSelectionChange == ignore)
         return;
 
-    m_ignoreMarkedTextSelectionChange = ignore;
+    m_ignoreCompositionSelectionChange = ignore;
     if (!ignore)
         revealSelectionAfterEditingOperation();
 }
 
+PassRefPtr<Range> Editor::compositionRange() const
+{
+    if (!m_compositionNode)
+        return 0;
+    unsigned length = m_compositionNode->length();
+    unsigned start = min(m_compositionStart, length);
+    unsigned end = min(max(start, m_compositionEnd), length);
+    if (start >= end)
+        return 0;
+    return new Range(m_compositionNode->document(), m_compositionNode.get(), start, m_compositionNode.get(), end);
+}
+
+bool Editor::getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const
+{
+    if (!m_compositionNode)
+        return false;
+    Position start = m_frame->selectionController()->start();
+    if (start.node() != m_compositionNode)
+        return false;
+    Position end = m_frame->selectionController()->end();
+    if (end.node() != m_compositionNode)
+        return false;
+
+    if (static_cast<unsigned>(start.offset()) < m_compositionStart)
+        return false;
+    if (static_cast<unsigned>(end.offset()) > m_compositionEnd)
+        return false;
+
+    selectionStart = start.offset() - m_compositionStart;
+    selectionEnd = start.offset() - m_compositionEnd;
+    return true;
+}
+
 } // namespace WebCore
index 2ccb653..14a143e 100644 (file)
@@ -56,6 +56,17 @@ class Range;
 class SelectionController;
 class Selection;
 
+struct CompositionUnderline {
+    CompositionUnderline() 
+        : startOffset(0), endOffset(0), thick(false) { }
+    CompositionUnderline(unsigned s, unsigned e, const Color& c, bool t) 
+        : startOffset(s), endOffset(e), color(c), thick(t) { }
+    unsigned startOffset;
+    unsigned endOffset;
+    Color color;
+    bool thick;
+};
+
 class Editor {
 public:
     Editor(Frame*);
@@ -193,29 +204,45 @@ public:
 
     bool smartInsertDeleteEnabled();
     
-    void selectMarkedText();
-    void unmarkText();
-    void discardMarkedText();
-    void replaceMarkedText(const String&);
-
-    bool ignoreMarkedTextSelectionChange() const { return m_ignoreMarkedTextSelectionChange; }
-    void setIgnoreMarkedTextSelectionChange(bool ignore);
+    // international text input composition
+    bool hasComposition() const { return m_compositionNode; }
+    void setComposition(const String&, const Vector<CompositionUnderline>&, unsigned selectionStart, unsigned selectionEnd);
+    void confirmComposition();
+    void confirmComposition(const String&); // if no existing composition, replaces selection
+    void confirmCompositionWithoutDisturbingSelection();
+    PassRefPtr<Range> compositionRange() const;
+    bool getCompositionSelection(unsigned& selectionStart, unsigned& selectionEnd) const;
+
+    // getting international text input composition state (for use by InlineTextBox)
+    Text* compositionNode() const { return m_compositionNode.get(); }
+    unsigned compositionStart() const { return m_compositionStart; }
+    unsigned compositionEnd() const { return m_compositionEnd; }
+    bool compositionUsesCustomUnderlines() const { return !m_customCompositionUnderlines.isEmpty(); }
+    const Vector<CompositionUnderline>& customCompositionUnderlines() const { return m_customCompositionUnderlines; }
+
+    bool ignoreCompositionSelectionChange() const { return m_ignoreCompositionSelectionChange; }
+
+    void setStartNewKillRingSequence(bool);
 
 #if PLATFORM(MAC)
     NSString* userVisibleString(NSURL*);
-    void setStartNewKillRingSequence(bool flag) { m_startNewKillRingSequence = flag; }
-#else 
-    void setStartNewKillRingSequence(bool) { }
 #endif
 
     PassRefPtr<Range> rangeForPoint(const IntPoint& windowPoint);
 
+    void clear();
+
 private:
     Frame* m_frame;
     OwnPtr<DeleteButtonController> m_deleteButtonController;
     RefPtr<EditCommand> m_lastEditCommand;
     RefPtr<Node> m_removedAnchor;
-    bool m_ignoreMarkedTextSelectionChange;
+
+    RefPtr<Text> m_compositionNode;
+    unsigned m_compositionStart;
+    unsigned m_compositionEnd;
+    Vector<CompositionUnderline> m_customCompositionUnderlines;
+    bool m_ignoreCompositionSelectionChange;
 
     bool canDeleteRange(Range*) const;
     bool canSmartCopyOrDelete();
@@ -229,15 +256,31 @@ private:
     void writeSelectionToPasteboard(Pasteboard*);
     void revealSelectionAfterEditingOperation();
 
-#if PLATFORM(MAC)
+    void selectComposition();
+    void confirmComposition(const String&, bool preserveSelection);
+    void setIgnoreCompositionSelectionChange(bool ignore);
+
     void addToKillRing(Range*, bool prepend);
+
+#if PLATFORM(MAC)
     bool m_startNewKillRingSequence;
-#else
-    void addToKillRing(Range*, bool) { }
 #endif
-
 };
 
+#if PLATFORM(MAC)
+
+inline void Editor::setStartNewKillRingSequence(bool flag)
+{
+    m_startNewKillRingSequence = flag;
+}
+
+#else
+
+inline void Editor::setStartNewKillRingSequence(bool) { }
+inline void Editor::addToKillRing(Range*, bool) { }
+
+#endif
+
 } // namespace WebCore
 
 #endif // Editor_h
index 748db9b..1416589 100644 (file)
@@ -93,17 +93,17 @@ void TypingCommand::forwardDeleteKeyPressed(Document *document, bool smartDelete
     typingCommand->apply();
 }
 
-void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText)
+void TypingCommand::insertText(Document* document, const String& text, bool selectInsertedText, bool insertedTextIsComposition)
 {
     ASSERT(document);
     
     Frame* frame = document->frame();
     ASSERT(frame);
 
-    insertText(document, text, frame->selectionController()->selection(), selectInsertedText);
+    insertText(document, text, frame->selectionController()->selection(), selectInsertedText, insertedTextIsComposition);
 }
 
-void TypingCommand::insertText(Document* document, const String& text, const Selection& selectionForInsertion, bool selectInsertedText)
+void TypingCommand::insertText(Document* document, const String& text, const Selection& selectionForInsertion, bool selectInsertedText, bool insertedTextIsComposition)
 {
     ASSERT(document);
     
@@ -116,7 +116,7 @@ void TypingCommand::insertText(Document* document, const String& text, const Sel
     String newText = text;
     Node* startNode = selectionForInsertion.start().node();
     
-    if (startNode && startNode->rootEditableElement()) {        
+    if (startNode && startNode->rootEditableElement() && !insertedTextIsComposition) {        
         // Send BeforeTextInsertedEvent. The event handler will update text if necessary.
         ExceptionCode ec = 0;
         RefPtr<BeforeTextInsertedEvent> evt = new BeforeTextInsertedEvent(text);
index 49e67bc..cfb197e 100644 (file)
@@ -45,8 +45,8 @@ public:
 
     static void deleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity);
     static void forwardDeleteKeyPressed(Document*, bool smartDelete = false, TextGranularity = CharacterGranularity);
-    static void insertText(Document*, const String&, bool selectInsertedText = false);
-    static void insertText(Document*, const String&, const Selection&, bool selectInsertedText = false);
+    static void insertText(Document*, const String&, bool selectInsertedText = false, bool insertedTextIsComposition = false);
+    static void insertText(Document*, const String&, const Selection&, bool selectInsertedText = false, bool insertedTextIsComposition = false);
     static void insertLineBreak(Document*);
     static void insertParagraphSeparator(Document*);
     static void insertParagraphSeparatorInQuotedContent(Document*);
index 06e7406..65510f2 100644 (file)
@@ -773,9 +773,7 @@ void FrameLoader::clear(bool clearWindowProperties)
     // back causes a measurable performance regression which we will need to fix to restore the correct behavior
     // urlsBridgeKnowsAbout.clear();
 
-#if PLATFORM(MAC)
-    m_frame->setMarkedTextRange(0, nil, nil);
-#endif
+    m_frame->editor()->clear();
 
     if (!m_needsClear)
         return;
index e9b573a..6b08e10 100644 (file)
@@ -53,6 +53,7 @@
 #include "ResourceRequest.h"
 #include "SelectionController.h"
 #include "Settings.h"
+#include "TextIterator.h"
 #include "markup.h"
 
 namespace WebCore {
@@ -230,7 +231,7 @@ void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item)
                 selectedRange = document->createRange();
                 selectedRange->selectNode(document->documentElement(), ec);
             }
-            m_client->speak(selectedRange->toString(true, ec));
+            m_client->speak(plainText(selectedRange.get()));
             break;
         }
         case ContextMenuItemTagStopSpeaking:
index 0e9b0eb..d9ded76 100644 (file)
@@ -307,12 +307,6 @@ String Frame::selectedText() const
     return plainText(selectionController()->toRange().get());
 }
 
-Range* Frame::markedTextRange() const
-{
-    return d->m_markedTextRange.get();
-}
-
-
 IntRect Frame::firstRectForRange(Range* range) const
 {
     int extraWidthToEndOfLine = 0;
@@ -339,53 +333,6 @@ IntRect Frame::firstRectForRange(Range* range) const
                    startCaretRect.height());
 }
 
-void Frame::setMarkedTextRange(Range* range, Vector<MarkedTextUnderline>& markedRangeDecorations)
-{
-    int exception = 0;
-    
-    ASSERT(!range || range->startContainer(exception) == range->endContainer(exception));
-    ASSERT(!range || range->collapsed(exception) || range->startContainer(exception)->isTextNode());
-    
-    d->m_markedTextUnderlines.clear();
-    if (markedRangeDecorations.size()) {
-        d->m_markedTextUsesUnderlines = true;
-        d->m_markedTextUnderlines = markedRangeDecorations;
-    } else 
-        d->m_markedTextUsesUnderlines = false;
-    
-    if (d->m_markedTextRange.get() && document() && d->m_markedTextRange->startContainer(exception)->renderer())
-        d->m_markedTextRange->startContainer(exception)->renderer()->repaint();
-    
-    if (range && range->collapsed(exception))
-        d->m_markedTextRange = 0;
-    else
-        d->m_markedTextRange = range;
-    
-    if (d->m_markedTextRange.get() && document() && d->m_markedTextRange->startContainer(exception)->renderer())
-        d->m_markedTextRange->startContainer(exception)->renderer()->repaint();    
-}
-
-void Frame::selectRangeInMarkedText(unsigned selOffset, unsigned selLength)
-{
-    ExceptionCode ec = 0;
-    
-    RefPtr<Range> selectedRange = document()->createRange();
-    Range* markedTextRange = this->markedTextRange();
-    
-    ASSERT(markedTextRange->startContainer(ec) == markedTextRange->endContainer(ec));
-    ASSERT(!ec);
-    unsigned selectionStart = markedTextRange->startOffset(ec) + selOffset;
-    unsigned selectionEnd = selectionStart + selLength;
-    ASSERT(!ec);
-    
-    selectedRange->setStart(markedTextRange->startContainer(ec), selectionStart, ec);
-    ASSERT(!ec);
-    selectedRange->setEnd(markedTextRange->startContainer(ec), selectionEnd, ec);
-    ASSERT(!ec);
-    
-    selectionController()->setSelectedRange(selectedRange.get(), DOWNSTREAM, false, ec);
-}
-
 SelectionController* Frame::selectionController() const
 {
     return &d->m_selectionController;
@@ -1658,16 +1605,6 @@ UChar Frame::backslashAsCurrencySymbol() const
     return decoder->encoding().backslashAsCurrencySymbol();
 }
 
-bool Frame::markedTextUsesUnderlines() const
-{
-    return d->m_markedTextUsesUnderlines;
-}
-
-const Vector<MarkedTextUnderline>& Frame::markedTextUnderlines() const
-{
-    return d->m_markedTextUnderlines;
-}
-
 static bool isInShadowTree(Node* node)
 {
     for (Node* n = node; n; n = n->parentNode())
@@ -2015,7 +1952,6 @@ FramePrivate::FramePrivate(Page* page, Frame* parent, Frame* thisFrame, HTMLFram
     , m_loader(new FrameLoader(thisFrame, frameLoaderClient))
     , m_userStyleSheetLoader(0)
     , m_paintRestriction(PaintRestrictionNone)
-    , m_markedTextUsesUnderlines(false)
     , m_highlightTextMatches(false)
     , m_windowHasFocus(false)
     , m_inViewSourceMode(false)
index 3aa5ca9..05bf80e 100644 (file)
@@ -107,17 +107,6 @@ struct FrameLoadRequest;
 
 template <typename T> class Timer;
 
-struct MarkedTextUnderline {
-    MarkedTextUnderline() 
-        : startOffset(0), endOffset(0), thick(false) { }
-    MarkedTextUnderline(unsigned s, unsigned e, const Color& c, bool t) 
-        : startOffset(s), endOffset(e), color(c), thick(t) { }
-    unsigned startOffset;
-    unsigned endOffset;
-    Color color;
-    bool thick;
-};
-
 class Frame : public Shared<Frame> {
 public:
     static double currentPaintTimeStamp() { return s_currentPaintTimeStamp; } // returns 0 if not painting
@@ -280,7 +269,6 @@ public:
     void applyEditingStyleToElement(Element*) const;
     void removeEditingStyleFromElement(Element*) const;
 
-    Range* markedTextRange() const;
     IntRect firstRectForRange(Range*) const;
     
 #if PLATFORM(MAC)
@@ -292,11 +280,6 @@ public:
 
     RenderStyle* styleForSelectionStart(Node*& nodeToRemove) const;
 
-    const Vector<MarkedTextUnderline>& markedTextUnderlines() const;  
-    bool markedTextUsesUnderlines() const;
-    void setMarkedTextRange(Range* , Vector<MarkedTextUnderline>&);
-    void selectRangeInMarkedText(unsigned selOffset, unsigned selLength);
-  
     unsigned markAllMatchesForText(const String&, bool caseFlag, unsigned limit);
     bool markedTextMatchesAreHighlighted() const;
     void setMarkedTextMatchesAreHighlighted(bool flag);
@@ -390,8 +373,6 @@ public:
     NSDictionary* fontAttributesForSelectionStart() const;
     NSWritingDirection baseWritingDirectionForSelectionStart() const;
 
-    void setMarkedTextRange(Range* , NSArray* attributes, NSArray* ranges);
-
 #endif
 
 };
index 113c118..9e8d64a 100644 (file)
@@ -110,8 +110,6 @@ namespace WebCore {
         RefPtr<Node> m_elementToDraw;
         PaintRestriction m_paintRestriction;
         
-        bool m_markedTextUsesUnderlines;
-        Vector<MarkedTextUnderline> m_markedTextUnderlines;
         bool m_highlightTextMatches;
         bool m_windowHasFocus;
         
@@ -121,8 +119,6 @@ namespace WebCore {
 
         bool m_prohibitsScrolling;
 
-        RefPtr<Range> m_markedTextRange;
-
         // The root object used for objects bound outside the context of a plugin.
         RefPtr<KJS::Bindings::RootObject> m_bindingRootObject; 
         RootObjectMap m_rootObjects;
index 3674176..1d72520 100644 (file)
@@ -526,46 +526,6 @@ void Frame::setUseSecureKeyboardEntry(bool enable)
     }
 }
 
-static void convertAttributesToUnderlines(Vector<MarkedTextUnderline>& result, const Range* markedTextRange, NSArray* attributes, NSArray* ranges)
-{
-    int exception = 0;
-    int baseOffset = markedTextRange->startOffset(exception);
-
-    unsigned length = [attributes count];
-    ASSERT([ranges count] == length);
-
-    for (unsigned i = 0; i < length; i++) {
-        NSNumber* style = [[attributes objectAtIndex:i] objectForKey:NSUnderlineStyleAttributeName];
-        if (!style)
-            continue;
-        NSRange range = [[ranges objectAtIndex:i] rangeValue];
-        NSColor* color = [[attributes objectAtIndex:i] objectForKey:NSUnderlineColorAttributeName];
-        Color qColor = Color::black;
-        if (color)
-            qColor = colorFromNSColor([color colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
-
-        result.append(MarkedTextUnderline(range.location + baseOffset, 
-                                          range.location + baseOffset + range.length, 
-                                          qColor,
-                                          [style intValue] > 1));
-    }
-}
-
-void Frame::setMarkedTextRange(Range* range, NSArray* attributes, NSArray* ranges)
-{
-    int exception;
-    exception = 0;
-
-    ASSERT(!range || range->startContainer(exception) == range->endContainer(exception));
-    ASSERT(!range || range->collapsed(exception) || range->startContainer(exception)->isTextNode());
-
-    Vector<MarkedTextUnderline> decorations;
-    if (attributes)
-        convertAttributesToUnderlines(decorations, range, attributes, ranges);
-    
-    setMarkedTextRange(range, decorations);
-}
-
 NSMutableDictionary* Frame::dashboardRegionsDictionary()
 {
     Document* doc = document();
index a7fc6c8..c91469b 100644 (file)
@@ -168,10 +168,6 @@ enum WebScrollGranularity {
 - (void)setMarkDOMRange:(DOMRange *)range;
 - (DOMRange *)markDOMRange;
 
-// international text input "marked text"
-- (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges;
-- (DOMRange *)markedTextDOMRange;
-
 - (NSFont *)fontForSelection:(BOOL *)hasMultipleFonts;
 - (NSWritingDirection)baseWritingDirectionForSelectionStart;
 
index 82bdd77..7f70f1d 100644 (file)
@@ -76,6 +76,7 @@
 #import "SmartReplace.h"
 #import "SubresourceLoader.h"
 #import "SystemTime.h"
+#import "Text.h"
 #import "TextEncoding.h"
 #import "TextIterator.h"
 #import "TextResourceDecoder.h"
@@ -935,19 +936,9 @@ static HTMLFormElement *formElementFromDOMElement(DOMElement *element)
     return [DOMRange _wrapRange:m_frame->mark().toRange().get()];
 }
 
-- (void)setMarkedTextDOMRange:(DOMRange *)range customAttributes:(NSArray *)attributes ranges:(NSArray *)ranges
-{
-    m_frame->setMarkedTextRange([range _range], attributes, ranges);
-}
-
-- (DOMRange *)markedTextDOMRange
-{
-    return [DOMRange _wrapRange:m_frame->markedTextRange()];
-}
-
 - (NSRange)markedTextNSRange
 {
-    return [self convertToNSRange:m_frame->markedTextRange()];
+    return [self convertToNSRange:m_frame->editor()->compositionRange().get()];
 }
 
 // Given proposedRange, returns an extended range that includes adjacent whitespace that should
index dcccd4b..5526236 100644 (file)
@@ -41,6 +41,7 @@ namespace WebCore {
     const UChar ideographicSpace = 0x3000;
     const UChar leftToRightMark = 0x200E;
     const UChar leftToRightOverride = 0x202D;
+    const UChar newlineCharacter = 0x000A;
     const UChar noBreakSpace = 0x00A0;
     const UChar objectReplacementCharacter = 0xFFFC;
     const UChar popDirectionalFormatting = 0x202C;
index c014652..ab7bca1 100644 (file)
 #include "InlineTextBox.h"
 
 #include "Document.h"
+#include "Editor.h"
 #include "Frame.h"
 #include "GraphicsContext.h"
 #include "HitTestResult.h"
-#include "Range.h"
 #include "RenderArena.h"
 #include "RenderBlock.h"
+#include "Text.h"
 #include "TextStyle.h"
 #include "break_lines.h"
 #include <wtf/AlwaysInline.h>
@@ -251,11 +252,9 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
         // When only painting the selection, don't bother to paint if there is none.
         return;
 
-    // Determine whether or not we have marked text.
-    Range* markedTextRange = object()->document()->frame()->markedTextRange();
-    int exception = 0;
-    bool haveMarkedText = markedTextRange && markedTextRange->startContainer(exception) == object()->node();
-    bool markedTextUsesUnderlines = object()->document()->frame()->markedTextUsesUnderlines();
+    // Determine whether or not we have composition underlines to draw.
+    bool containsComposition = object()->document()->frame()->editor()->compositionNode() == object()->node();
+    bool useCustomUnderlines = containsComposition && object()->document()->frame()->editor()->compositionUsesCustomUnderlines();
 
     // Set our font.
     RenderStyle* styleToUse = object()->style(m_firstLine);
@@ -264,8 +263,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
     if (*font != paintInfo.context->font())
         paintInfo.context->setFont(*font);
 
-    // 1. Paint backgrounds behind text if needed.  Examples of such backgrounds include selection
-    // and marked text.
+    // 1. Paint backgrounds behind text if needed. Examples of such backgrounds include selection
+    // and composition underlines.
     if (paintInfo.phase != PaintPhaseSelection && !isPrinting) {
 #if PLATFORM(MAC)
         // Custom highlighters go behind everything else.
@@ -273,12 +272,14 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
             paintCustomHighlight(tx, ty, styleToUse->highlight());
 #endif
 
-        if (haveMarkedText  && !markedTextUsesUnderlines)
-            paintMarkedTextBackground(paintInfo.context, tx, ty, styleToUse, font, markedTextRange->startOffset(exception), markedTextRange->endOffset(exception));
+        if (containsComposition && !useCustomUnderlines)
+            paintCompositionBackground(paintInfo.context, tx, ty, styleToUse, font,
+                object()->document()->frame()->editor()->compositionStart(),
+                object()->document()->frame()->editor()->compositionEnd());
 
         paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, true);
 
-        if (haveSelection && !markedTextUsesUnderlines)
+        if (haveSelection && !useCustomUnderlines)
             paintSelection(paintInfo.context, tx, ty, styleToUse, font);
     }
 
@@ -286,13 +287,6 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
     if (m_len <= 0)
         return;
 
-    const Vector<MarkedTextUnderline>* underlines = 0;
-    size_t numUnderlines = 0;
-    if (haveMarkedText && markedTextUsesUnderlines) {
-        underlines = &object()->document()->frame()->markedTextUnderlines();
-        numUnderlines = underlines->size();
-    }
-
     Color textFillColor;
     Color textStrokeColor;
     float textStrokeWidth = styleToUse->textStrokeWidth();
@@ -432,24 +426,29 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
     if (paintInfo.phase != PaintPhaseSelection) {
         paintDocumentMarkers(paintInfo.context, tx, ty, styleToUse, font, false);
 
-        for (size_t index = 0; index < numUnderlines; ++index) {
-            const MarkedTextUnderline& underline = (*underlines)[index];
+        if (useCustomUnderlines) {
+            const Vector<CompositionUnderline>& underlines = object()->document()->frame()->editor()->customCompositionUnderlines();
+            size_t numUnderlines = underlines.size();
 
-            if (underline.endOffset <= start())
-                // underline is completely before this run.  This might be an underline that sits
-                // before the first run we draw, or underlines that were within runs we skipped 
-                // due to truncation.
-                continue;
-            
-            if (underline.startOffset <= end()) {
-                // underline intersects this run.  Paint it.
-                paintMarkedTextUnderline(paintInfo.context, tx, ty, underline);
-                if (underline.endOffset > end() + 1)
-                    // underline also runs into the next run. Bail now, no more marker advancement.
+            for (size_t index = 0; index < numUnderlines; ++index) {
+                const CompositionUnderline& underline = underlines[index];
+
+                if (underline.endOffset <= start())
+                    // underline is completely before this run.  This might be an underline that sits
+                    // before the first run we draw, or underlines that were within runs we skipped 
+                    // due to truncation.
+                    continue;
+                
+                if (underline.startOffset <= end()) {
+                    // underline intersects this run.  Paint it.
+                    paintCompositionUnderline(paintInfo.context, tx, ty, underline);
+                    if (underline.endOffset > end() + 1)
+                        // underline also runs into the next run. Bail now, no more marker advancement.
+                        break;
+                } else
+                    // underline is completely after this run, bail.  A later run will paint it.
                     break;
-            } else
-                // underline is completely after this run, bail.  A later run will paint it.
-                break;
+            }
         }
     }
 
@@ -507,7 +506,7 @@ void InlineTextBox::paintSelection(GraphicsContext* p, int tx, int ty, RenderSty
     p->restore();
 }
 
-void InlineTextBox::paintMarkedTextBackground(GraphicsContext* p, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos)
+void InlineTextBox::paintCompositionBackground(GraphicsContext* p, int tx, int ty, RenderStyle* style, const Font* f, int startPos, int endPos)
 {
     int offset = m_start;
     int sPos = max(startPos - offset, 0);
@@ -726,7 +725,7 @@ void InlineTextBox::paintDocumentMarkers(GraphicsContext* pt, int tx, int ty, Re
 }
 
 
-void InlineTextBox::paintMarkedTextUnderline(GraphicsContext* ctx, int tx, int ty, const MarkedTextUnderline& underline)
+void InlineTextBox::paintCompositionUnderline(GraphicsContext* ctx, int tx, int ty, const CompositionUnderline& underline)
 {
     tx += m_x;
     ty += m_y;
index e798073..ff5615d 100644 (file)
@@ -36,10 +36,11 @@ const unsigned short cFullTruncation = USHRT_MAX - 1;
 
 class String;
 class StringImpl;
-class MarkedTextUnderline;
 class HitTestResult;
 class Position;
 
+struct CompositionUnderline;
+
 class InlineTextBox : public InlineRunBox {
 public:
     InlineTextBox(RenderObject* obj)
@@ -94,11 +95,11 @@ public:
 
     void paintDecoration(GraphicsContext*, int tx, int ty, int decoration);
     void paintSelection(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*);
-    void paintMarkedTextBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos);
+    void paintCompositionBackground(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, int startPos, int endPos);
     void paintDocumentMarkers(GraphicsContext*, int tx, int ty, RenderStyle*, const Font*, bool background);
     void paintSpellingOrGrammarMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*, bool grammar);
     void paintTextMatchMarker(GraphicsContext*, int tx, int ty, DocumentMarker, RenderStyle*, const Font*);
-    void paintMarkedTextUnderline(GraphicsContext*, int tx, int ty, const MarkedTextUnderline&);
+    void paintCompositionUnderline(GraphicsContext*, int tx, int ty, const CompositionUnderline&);
 #if PLATFORM(MAC)
     void paintCustomHighlight(int tx, int ty, const AtomicString& type);
 #endif
index b83fc89..533f415 100644 (file)
@@ -1,5 +1,5 @@
 /**
- * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -21,6 +21,7 @@
 #include "config.h"
 #include "RenderTextControl.h"
 
+#include "CharacterNames.h"
 #include "Document.h"
 #include "Editor.h"
 #include "EditorClient.h"
@@ -40,6 +41,7 @@
 #include "SearchPopupMenu.h"
 #include "SelectionController.h"
 #include "Settings.h"
+#include "Text.h"
 #include "TextIterator.h"
 #include "TextStyle.h"
 #include "htmlediting.h"
@@ -546,52 +548,127 @@ void RenderTextControl::subtreeHasChanged()
     }
 }
 
+String RenderTextControl::finishText(Vector<UChar>& result) const
+{
+    UChar symbol = backslashAsCurrencySymbol();
+    if (symbol != '\\') {
+        size_t size = result.size();
+        for (size_t i = 0; i < size; ++i)
+            if (result[i] == '\\')
+                result[i] = symbol;
+    }
+
+    return String::adopt(result);
+}
+
 String RenderTextControl::text()
 {
-    if (m_innerText)
-        return m_innerText->textContent().replace('\\', backslashAsCurrencySymbol());
-    return String();
+    if (!m_innerText)
+        return "";
+    Frame* frame = document()->frame();
+    Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
+
+    Vector<UChar> result;
+
+    for (Node* n = m_innerText.get(); n; n = n->traverseNextNode(m_innerText.get())) {
+        if (n->isTextNode()) {
+            Text* text = static_cast<Text*>(n);
+            String data = text->data();
+            unsigned length = data.length();
+            if (text != compositionNode)
+                result.append(data.characters(), length);
+            else {
+                unsigned compositionStart = min(frame->editor()->compositionStart(), length);
+                unsigned compositionEnd = min(max(compositionStart, frame->editor()->compositionEnd()), length);
+                result.append(data.characters(), compositionStart);
+                result.append(data.characters() + compositionEnd, length - compositionEnd);
+            }
+        }
+    }
+
+    return finishText(result);
 }
 
-String RenderTextControl::textWithHardLineBreaks()
+static void getNextSoftBreak(RootInlineBox*& line, Node*& breakNode, unsigned& breakOffset)
 {
-    String s("");
+    RootInlineBox* next;
+    for (; line; line = next) {
+        next = line->nextRootBox();
+        if (next && !line->endsWithBreak()) {
+            ASSERT(line->lineBreakObj());
+            breakNode = line->lineBreakObj()->node();
+            breakOffset = line->lineBreakPos();
+            line = next;
+            return;
+        }
+    }
+    breakNode = 0;
+}
 
-    if (!m_innerText || !m_innerText->firstChild())
-        return s;
+String RenderTextControl::textWithHardLineBreaks()
+{
+    if (!m_innerText)
+        return "";
+    Node* firstChild = m_innerText->firstChild();
+    if (!firstChild)
+        return "";
 
     document()->updateLayout();
 
-    RenderObject* renderer = m_innerText->firstChild()->renderer();
+    RenderObject* renderer = firstChild->renderer();
     if (!renderer)
-        return s;
+        return "";
 
     InlineBox* box = renderer->inlineBox(0, DOWNSTREAM);
     if (!box)
-        return s;
+        return "";
 
-    ExceptionCode ec = 0;
-    RefPtr<Range> range = new Range(document());
-    range->selectNodeContents(m_innerText.get(), ec);
-    for (RootInlineBox* line = box->root(); line; line = line->nextRootBox()) {
-        // If we're at a soft wrap, then insert the hard line break here
-        if (!line->endsWithBreak() && line->nextRootBox()) {
-            // Update range so it ends before this wrap
-            ASSERT(line->lineBreakObj());
-            range->setEnd(line->lineBreakObj()->node(), line->lineBreakPos(), ec);
-
-            s.append(range->toString(true, ec));
-            s.append("\n");
-
-            // Update range so it starts after this wrap
-            range->setEnd(m_innerText.get(), maxDeepOffset(m_innerText.get()), ec);
-            range->setStart(line->lineBreakObj()->node(), line->lineBreakPos(), ec);
+    Frame* frame = document()->frame();
+    Text* compositionNode = frame ? frame->editor()->compositionNode() : 0;
+
+    Node* breakNode;
+    unsigned breakOffset;
+    RootInlineBox* line = box->root();
+    getNextSoftBreak(line, breakNode, breakOffset);
+
+    Vector<UChar> result;
+
+    for (Node* n = firstChild; n; n = n->traverseNextNode(m_innerText.get())) {
+        if (n->hasTagName(brTag))
+            result.append(&newlineCharacter, 1);
+        else if (n->isTextNode()) {
+            Text* text = static_cast<Text*>(n);
+            String data = text->data();
+            unsigned length = data.length();
+            unsigned compositionStart = (text == compositionNode)
+                ? min(frame->editor()->compositionStart(), length) : 0;
+            unsigned compositionEnd = (text == compositionNode)
+                ? min(max(compositionStart, frame->editor()->compositionEnd()), length) : 0;
+            unsigned position = 0;
+            while (breakNode == n && breakOffset < compositionStart) {
+                result.append(data.characters() + position, breakOffset - position);
+                position = breakOffset;
+                result.append(&newlineCharacter, 1);
+                getNextSoftBreak(line, breakNode, breakOffset);
+            }
+            result.append(data.characters() + position, compositionStart - position);
+            position = compositionEnd;
+            while (breakNode == n && breakOffset <= length) {
+                if (breakOffset > position) {
+                    result.append(data.characters() + position, breakOffset - position);
+                    position = breakOffset;
+                    result.append(&newlineCharacter, 1);
+                }
+                getNextSoftBreak(line, breakNode, breakOffset);
+            }
+            result.append(data.characters() + position, length - position);
         }
+        while (breakNode == n)
+            getNextSoftBreak(line, breakNode, breakOffset);
     }
-    s.append(range->toString(true, ec));
-    ASSERT(!ec);
 
-    return s.replace('\\', backslashAsCurrencySymbol());
+    return finishText(result);
 }
 
 void RenderTextControl::calcHeight()
index 47512c8..3552ab1 100644 (file)
@@ -133,6 +133,7 @@ private:
     const AtomicString& autosaveName() const;
     void startSearchEventTimer();
     void searchEventTimerFired(Timer<RenderTextControl>*);
+    String finishText(Vector<UChar>&) const;
 
     RefPtr<HTMLTextFieldInnerElement> m_innerBlock;
     RefPtr<HTMLTextFieldInnerTextElement> m_innerText;
index f77a311..306a699 100644 (file)
@@ -1,3 +1,29 @@
+2007-09-13  Darin Adler  <darin@apple.com>
+
+        Reviewed by Oliver.
+
+        - fix <rdar://problem/5470457> REGRESSION: Input method inline hole is mishandled in text
+          <input> elements with maxlength limit
+
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView _selectionChanged]): Tweaked code a bit.
+        (-[WebHTMLView markedRange]): Simplified logic, since markedTextNSRange works when there's
+        no composition range.
+        (-[WebHTMLView hasMarkedText]): Call directly to Editor instead of bridge.
+        (-[WebHTMLView unmarkText]): Call new confirmComposition to make it clear that this is
+        confirming text, not just unmarking it to discard it.
+        (extractUnderlines): Added. Converts directly from an NSAttributedString to the
+        CompositionUnderline vector that's used by WebCore.
+        (-[WebHTMLView setMarkedText:selectedRange:]): Changed to use the new setComposition.
+        (-[WebHTMLView insertText:]): Changed to use confirmComposition when appropriate, instead
+        of relying on special behavior of Editor::insertText.
+        (-[WebHTMLView _updateSelectionForInputManager]): Rewrote to use getCompositionSelection
+        and confirmCompositionWithoutDisturbingSelection.
+
+        * WebCoreSupport/WebEditorClient.h:
+        * WebCoreSupport/WebEditorClient.mm:
+        Removed obsolete markedTextAbandoned function.
 2007-09-12  David Kilzer  <ddkilzer@apple.com>
 
         Rubber-stamped by Darin and reviewed by Adam.
index c3fbf22..d5bac29 100644 (file)
@@ -90,8 +90,6 @@ public:
     virtual void handleKeypress(WebCore::KeyboardEvent*);
     virtual void handleInputMethodKeypress(WebCore::KeyboardEvent*);
 
-    virtual void markedTextAbandoned(WebCore::Frame*);
-
     virtual void textFieldDidBeginEditing(WebCore::Element*);
     virtual void textFieldDidEndEditing(WebCore::Element*);
     virtual void textDidChangeInTextField(WebCore::Element*);
index bf8b3c4..7fa6bbe 100644 (file)
@@ -446,12 +446,6 @@ void WebEditorClient::handleInputMethodKeypress(KeyboardEvent* event)
         event->setDefaultHandled();
 }
 
-void WebEditorClient::markedTextAbandoned(Frame* frame)
-{
-    WebHTMLView *webHTMLView = [[kit(frame) frameView] documentView];
-    [[NSInputManager currentInputManager] markedTextAbandoned:webHTMLView];
-}
-
 #define FormDelegateLog(ctrl)  LOG(FormDelegate, "control=%@", ctrl)
 
 void WebEditorClient::textFieldDidBeginEditing(Element* element)
index 46416bc..a0318f7 100644 (file)
@@ -75,6 +75,7 @@
 #import <dlfcn.h>
 #import <WebCore/CachedImage.h>
 #import <WebCore/CachedResourceClient.h>
+#import <WebCore/ColorMac.h>
 #import <WebCore/ContextMenu.h>
 #import <WebCore/ContextMenuController.h>
 #import <WebCore/Document.h>
 #import <WebCore/Range.h>
 #import <WebCore/SelectionController.h>
 #import <WebCore/SharedBuffer.h>
+#import <WebCore/Text.h>
 #import <WebCore/WebCoreObjCExtras.h>
 #import <WebCore/WebCoreTextRenderer.h>
 #import <WebKit/DOM.h>
@@ -4946,8 +4948,8 @@ static DOMRange *unionDOMRanges(DOMRange *a, DOMRange *b)
 {
     [self _updateSelectionForInputManager];
     [self _updateFontPanel];
-    if (core([self _frame]))
-        core([self _frame])->editor()->setStartNewKillRingSequence(true);
+    if (Frame* coreFrame = core([self _frame]))
+        coreFrame->editor()->setStartNewKillRingSequence(true);
 }
 
 - (void)_updateFontPanel
@@ -5353,7 +5355,7 @@ static BOOL isTextInput(Frame* coreFrame)
     }
     NSAttributedString *result = [self attributedSubstringFromRange:NSMakeRange(0, UINT_MAX)];
     
-    LOG(TextInput, "textStorage -> \"%s\"", result ? [[result string] UTF8String] : "");
+    LOG(TextInput, "textStorage -> \"%@\"", result ? [result string] : @"");
     
     // We have to return an empty string rather than null to prevent TSM from calling -string
     return result ? result : [[[NSAttributedString alloc] initWithString:@""] autorelease];
@@ -5423,12 +5425,7 @@ static BOOL isTextInput(Frame* coreFrame)
 
 - (NSRange)markedRange
 {
-    if (![self hasMarkedText]) {
-        LOG(TextInput, "markedRange -> (NSNotFound, 0)");
-        return NSMakeRange(NSNotFound, 0);
-    }
     NSRange result = [[self _bridge] markedTextNSRange];
-
     LOG(TextInput, "markedRange -> (%u, %u)", result.location, result.length);
     return result;
 }
@@ -5456,7 +5453,7 @@ static BOOL isTextInput(Frame* coreFrame)
         ASSERT([[result string] characterAtIndex:nsRange.length] == '\n' || [[result string] characterAtIndex:nsRange.length] == ' ');
         result = [result attributedSubstringFromRange:NSMakeRange(0, nsRange.length)];
     }
-    LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%s\"", nsRange.location, nsRange.length, [[result string] UTF8String]);
+    LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%@\"", nsRange.location, nsRange.length, [result string]);
     return result;
 }
 
@@ -5475,8 +5472,8 @@ static BOOL isTextInput(Frame* coreFrame)
 
 - (BOOL)hasMarkedText
 {
-    BOOL result = [[self _bridge] markedTextDOMRange] != nil;
-
+    Frame* coreFrame = core([self _frame]);
+    BOOL result = coreFrame && coreFrame->editor()->hasComposition();
     LOG(TextInput, "hasMarkedText -> %u", result);
     return result;
 }
@@ -5495,31 +5492,34 @@ static BOOL isTextInput(Frame* coreFrame)
     }
     
     if (Frame* coreFrame = core([self _frame]))
-        coreFrame->editor()->unmarkText();
+        coreFrame->editor()->confirmComposition();
 }
 
-- (void)_extractAttributes:(NSArray **)a ranges:(NSArray **)r fromAttributedString:(NSAttributedString *)string
+static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnderline>& result)
 {
     int length = [[string string] length];
+
     int i = 0;
-    NSMutableArray *attributes = [NSMutableArray array];
-    NSMutableArray *ranges = [NSMutableArray array];
     while (i < length) {
-        NSRange effectiveRange;
-        NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&effectiveRange inRange:NSMakeRange(i,length - i)];
-        [attributes addObject:attrs];
-        [ranges addObject:[NSValue valueWithRange:effectiveRange]];
-        i = effectiveRange.location + effectiveRange.length;
+        NSRange range;
+        NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&range inRange:NSMakeRange(i, length - i)];
+
+        if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
+            Color color = Color::black;
+            if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName])
+                color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
+            result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] > 1));
+        }
+
+        i = range.location + range.length;
     }
-    *a = attributes;
-    *r = ranges;
 }
 
 - (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange
 {
     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
 
-    LOG(TextInput, "setMarkedText:\"%s\" selectedRange:(%u, %u)", isAttributedString ? [[string string] UTF8String] : [string UTF8String], newSelRange.location, newSelRange.length);
+    LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelRange.location, newSelRange.length);
 
     // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
     WebHTMLViewInterpretKeyEventsParameters* parameters = _private->interpretKeyEventsParameters;
@@ -5534,42 +5534,26 @@ static BOOL isTextInput(Frame* coreFrame)
     if (!coreFrame)
         return;
 
-    WebFrameBridge *bridge = [self _bridge];
-
     if (![self _isEditable])
         return;
 
+    Vector<CompositionUnderline> underlines;
+    NSString *text = string;
+
     if (isAttributedString) {
         unsigned markedTextLength = [(NSString *)string length];
         NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, markedTextLength)];
-        LOG(TextInput, "    ReplacementRange: %s", [rangeString UTF8String]);
-        // The AppKit adds a 'secret' property to the string that contains the replacement
-        // range.  The replacement range is the range of the the text that should be replaced
-        // with the new string.
+        LOG(TextInput, "    ReplacementRange: %@", rangeString);
+        // The AppKit adds a 'secret' property to the string that contains the replacement range.
+        // The replacement range is the range of the the text that should be replaced with the new string.
         if (rangeString)
             [[self _bridge] selectNSRange:NSRangeFromString(rangeString)];
-    }
-
-    coreFrame->editor()->setIgnoreMarkedTextSelectionChange(true);
 
-    // if we had marked text already, we need to make sure to replace
-    // that, instead of the selection/caret
-    coreFrame->editor()->selectMarkedText();
-
-    NSString *text = string;
-    NSArray *attributes = nil;
-    NSArray *ranges = nil;
-    if (isAttributedString) {
         text = [string string];
-        [self _extractAttributes:&attributes ranges:&ranges fromAttributedString:string];
+        extractUnderlines(string, underlines);
     }
 
-    coreFrame->editor()->replaceMarkedText(text);
-    [bridge setMarkedTextDOMRange:[self _selectedRange] customAttributes:attributes ranges:ranges];
-    if ([self hasMarkedText])
-        coreFrame->selectRangeInMarkedText(newSelRange.location, newSelRange.length);
-
-    coreFrame->editor()->setIgnoreMarkedTextSelectionChange(false);
+    coreFrame->editor()->setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange));
 }
 
 - (void)doCommandBySelector:(SEL)selector
@@ -5631,7 +5615,7 @@ static BOOL isTextInput(Frame* coreFrame)
 {
     BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
 
-    LOG(TextInput, "insertText:\"%s\"", isAttributedString ? [[string string] UTF8String] : [string UTF8String]);
+    LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
 
     WebHTMLViewInterpretKeyEventsParameters* parameters = _private->interpretKeyEventsParameters;
     _private->interpretKeyEventsParameters = 0;
@@ -5639,8 +5623,9 @@ static BOOL isTextInput(Frame* coreFrame)
         parameters->consumedByIM = NO;
 
     // We don't support inserting an attributed string but input methods don't appear to require this.
+    Frame* coreFrame = core([self _frame]);
     NSString *text;
-    bool isFromInputMethod = [self hasMarkedText];
+    bool isFromInputMethod = coreFrame->editor()->hasComposition();
     if (isAttributedString) {
         text = [string string];
         // We deal with the NSTextInputReplacementRangeAttributeName attribute from NSAttributedString here
@@ -5648,7 +5633,7 @@ static BOOL isTextInput(Frame* coreFrame)
         // event in TSM.  This behaviour matches that of -[WebHTMLView setMarkedText:selectedRange:] when it receives an
         // NSAttributedString
         NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, [text length])];
-        LOG(TextInput, "    ReplacementRange: %s", [rangeString UTF8String]);
+        LOG(TextInput, "    ReplacementRange: %@", rangeString);
         if (rangeString) {
             [[self _bridge] selectNSRange:NSRangeFromString(rangeString)];
             isFromInputMethod = YES;
@@ -5674,10 +5659,16 @@ static BOOL isTextInput(Frame* coreFrame)
             return;
         }
         
-        Frame* coreFrame = core([self _frame]);
         String eventText = text;
         eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
-        eventHandled = coreFrame && coreFrame->editor()->insertText(eventText, event);
+        if (coreFrame) {
+            if (!coreFrame->editor()->hasComposition())
+                eventHandled = coreFrame->editor()->insertText(eventText, event);
+            else {
+                eventHandled = true;
+                coreFrame->editor()->confirmComposition(eventText);
+            }
+        }
     }
     
     if (!parameters)
@@ -5693,52 +5684,24 @@ static BOOL isTextInput(Frame* coreFrame)
     parameters->eventWasHandled = eventHandled;
 }
 
-- (BOOL)_selectionIsInsideMarkedText
-{
-    WebFrameBridge *bridge = [self _bridge];
-    DOMRange *selection = [self _selectedRange];
-    DOMRange *markedTextRange = [bridge markedTextDOMRange];
-
-    ASSERT([markedTextRange startContainer] == [markedTextRange endContainer]);
-
-    if ([selection startContainer] != [markedTextRange startContainer]) 
-        return NO;
-
-    if ([selection endContainer] != [markedTextRange startContainer])
-        return NO;
-
-    if ([selection startOffset] < [markedTextRange startOffset])
-        return NO;
-
-    if ([selection endOffset] > [markedTextRange endOffset])
-        return NO;
-
-    return YES;
-}
-
 - (void)_updateSelectionForInputManager
 {
-    if (![self hasMarkedText])
-        return;
-
     Frame* coreFrame = core([self _frame]);
     if (!coreFrame)
         return;
 
-    if (coreFrame->editor()->ignoreMarkedTextSelectionChange())
+    if (!coreFrame->editor()->hasComposition())
         return;
 
-    if ([self _selectionIsInsideMarkedText]) {
-        DOMRange *selection = [self _selectedRange];
-        DOMRange *markedTextDOMRange = [[self _bridge] markedTextDOMRange];
-
-        unsigned markedSelectionStart = [selection startOffset] - [markedTextDOMRange startOffset];
-        unsigned markedSelectionLength = [selection endOffset] - [selection startOffset];
-        NSRange newSelectionRange = NSMakeRange(markedSelectionStart, markedSelectionLength);
+    if (coreFrame->editor()->ignoreCompositionSelectionChange())
+        return;
 
-        [[NSInputManager currentInputManager] markedTextSelectionChanged:newSelectionRange client:self];
-    } else {
-        [self unmarkText];
+    unsigned start;
+    unsigned end;
+    if (coreFrame->editor()->getCompositionSelection(start, end))
+        [[NSInputManager currentInputManager] markedTextSelectionChanged:NSMakeRange(start, end - start) client:self];
+    else {
+        coreFrame->editor()->confirmCompositionWithoutDisturbingSelection();
         [[NSInputManager currentInputManager] markedTextAbandoned:self];
     }
 }
index 1abc21d..f93df5b 100644 (file)
@@ -1,3 +1,22 @@
+2007-09-13  Darin Adler  <darin@apple.com>
+
+        Reviewed by Oliver.
+
+        - fix <rdar://problem/5470457> REGRESSION: Input method inline hole is mishandled in text
+          <input> elements with maxlength limit
+
+        * WebView.cpp:
+        (WebView::resetIME): Change to use confirmCompositionWithoutDisturbingSelection.
+        (WebView::updateSelectionForIME): Update for name changes, and to use new functions
+        in Editor.
+        (WebView::onIMEStartComposition): Removed unneeded call to unmarkText.
+        (compositionToUnderlines): Removed startOffset parameter, since setComposition now
+        handles this.
+        (WebView::onIMEComposition): Changed to use confirmComposition and setComposition.
+        Logic gets a lot cleaner.
+        (WebView::onIMEEndComposition): Removed unneeded calls to Editor.
+        (WebView::onIMERequestCharPosition): Updated for name changes.
+
 2007-09-12  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Adam.
index 7527db6..4cee1de 100644 (file)
@@ -3789,43 +3789,10 @@ void WebView::prepareCandidateWindow(Frame* targetFrame, HIMC hInputContext)
     IMMDict::dict().setCandidateWindow(hInputContext, &form);
 }
 
-static bool markedTextContainsSelection(Range* markedTextRange, Range* selection)
-{
-    ExceptionCode ec = 0;
-
-    ASSERT(markedTextRange->startContainer(ec) == markedTextRange->endContainer(ec));
-
-    if (selection->startContainer(ec) != markedTextRange->startContainer(ec))
-        return false;
-
-    if (selection->endContainer(ec) != markedTextRange->endContainer(ec))
-        return false;
-
-    if (selection->startOffset(ec) < markedTextRange->startOffset(ec))
-        return false;
-
-    if (selection->endOffset(ec) > markedTextRange->endOffset(ec))
-        return false;
-
-    return true;
-}
-
-static void setSelectionToEndOfRange(Frame* targetFrame, Range* sourceRange)
-{
-    ExceptionCode ec = 0;
-    Node* caretContainer = sourceRange->endContainer(ec);
-    unsigned caretOffset = sourceRange->endOffset(ec);
-    RefPtr<Range> range = targetFrame->document()->createRange();
-    range->setStart(caretContainer, caretOffset, ec);
-    range->setEnd(caretContainer, caretOffset, ec);
-    targetFrame->editor()->unmarkText();
-    targetFrame->selectionController()->setSelectedRange(range.get(), WebCore::DOWNSTREAM, true, ec);
-}
-
 void WebView::resetIME(Frame* targetFrame)
 {
     if (targetFrame)
-        targetFrame->editor()->unmarkText();
+        targetFrame->editor()->confirmCompositionWithoutDisturbingSelection();
 
     if (HIMC hInputContext = getIMMContext()) {
         IMMDict::dict().notifyIME(hInputContext, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
@@ -3836,14 +3803,15 @@ void WebView::resetIME(Frame* targetFrame)
 void WebView::updateSelectionForIME()
 {
     Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
-    if (!targetFrame || !targetFrame->markedTextRange())
+    if (!targetFrame || !targetFrame->editor()->hasComposition())
         return;
     
-    if (targetFrame->editor()->ignoreMarkedTextSelectionChange())
+    if (targetFrame->editor()->ignoreCompositionSelectionChange())
         return;
 
-    RefPtr<Range> selectionRange = targetFrame->selectionController()->selection().toRange();
-    if (!selectionRange || !markedTextContainsSelection(targetFrame->markedTextRange(), selectionRange.get()))
+    unsigned start;
+    unsigned end;
+    if (!targetFrame->editor()->getCompositionSelection(start, end))
         resetIME(targetFrame);
 }
 
@@ -3864,9 +3832,6 @@ bool WebView::onIMEStartComposition()
     if (!targetFrame)
         return true;
 
-    //Tidy up in case the last IME composition was not correctly terminated
-    targetFrame->editor()->unmarkText();
-
     HIMC hInputContext = getIMMContext();
     prepareCandidateWindow(targetFrame, hInputContext);
     releaseIMMContext(hInputContext);
@@ -3886,17 +3851,18 @@ static bool getCompositionString(HIMC hInputContext, DWORD type, String& result)
     return true;
 }
 
-static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, 
-                                    unsigned startOffset, Vector<MarkedTextUnderline>& underlines)
+static void compositionToUnderlines(const Vector<DWORD>& clauses, const Vector<BYTE>& attributes, Vector<CompositionUnderline>& underlines)
 {
-    if (!clauses.size())
+    if (clauses.isEmpty()) {
+        underlines.clear();
         return;
+    }
   
     const size_t numBoundaries = clauses.size() - 1;
     underlines.resize(numBoundaries);
     for (unsigned i = 0; i < numBoundaries; i++) {
-        underlines[i].startOffset = startOffset + clauses[i];
-        underlines[i].endOffset = startOffset + clauses[i + 1];
+        underlines[i].startOffset = clauses[i];
+        underlines[i].endOffset = clauses[i + 1];
         BYTE attribute = attributes[clauses[i]];
         underlines[i].thick = attribute == ATTR_TARGET_CONVERTED || attribute == ATTR_TARGET_NOTCONVERTED;
         underlines[i].color = Color(0,0,0);
@@ -3914,42 +3880,18 @@ bool WebView::onIMEComposition(LPARAM lparam)
         return true;
 
     prepareCandidateWindow(targetFrame, hInputContext);
-    targetFrame->editor()->setIgnoreMarkedTextSelectionChange(true);
-
-    // if we had marked text already, we need to make sure to replace
-    // that, instead of the selection/caret
-    targetFrame->editor()->selectMarkedText();
 
     if (lparam & GCS_RESULTSTR || !lparam) {
         String compositionString;
         if (!getCompositionString(hInputContext, GCS_RESULTSTR, compositionString) && lparam)
-            goto cleanup;
+            return true;
         
-        targetFrame->editor()->replaceMarkedText(compositionString);
-        RefPtr<Range> sourceRange = targetFrame->selectionController()->selection().toRange();
-        setSelectionToEndOfRange(targetFrame, sourceRange.get());
-    } else if (lparam) {
+        targetFrame->editor()->confirmComposition(compositionString);
+    } else {
         String compositionString;
         if (!getCompositionString(hInputContext, GCS_COMPSTR, compositionString))
-            goto cleanup;
+            return true;
         
-        targetFrame->editor()->replaceMarkedText(compositionString);
-
-        ExceptionCode ec = 0;
-        RefPtr<Range> sourceRange = targetFrame->selectionController()->selection().toRange();
-        if (!sourceRange)
-            goto cleanup;
-
-        Node* startContainer = sourceRange->startContainer(ec);
-        const String& str = startContainer->textContent();
-        for (unsigned i = 0; i < str.length(); i++)
-            ASSERT(str[i]);
-
-        unsigned startOffset = sourceRange->startOffset(ec);
-        RefPtr<Range> range = targetFrame->document()->createRange();
-        range->setStart(startContainer, startOffset, ec);
-        range->setEnd(startContainer, startOffset + compositionString.length(), ec);
-
         // Composition string attributes
         int numAttributes = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPATTR, 0, 0);
         Vector<BYTE> attributes(numAttributes);
@@ -3959,14 +3901,15 @@ bool WebView::onIMEComposition(LPARAM lparam)
         int numClauses = IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, 0, 0);
         Vector<DWORD> clauses(numClauses / sizeof(DWORD));
         IMMDict::dict().getCompositionString(hInputContext, GCS_COMPCLAUSE, clauses.data(), numClauses);
-        Vector<MarkedTextUnderline> underlines;
-        compositionToUnderlines(clauses, attributes, startOffset, underlines);
-        targetFrame->setMarkedTextRange(range.get(), underlines);
-        if (targetFrame->markedTextRange())
-            targetFrame->selectRangeInMarkedText(LOWORD(IMMDict::dict().getCompositionString(hInputContext, GCS_CURSORPOS, 0, 0)), 0);
+
+        Vector<CompositionUnderline> underlines;
+        compositionToUnderlines(clauses, attributes, underlines);
+
+        int cursorPosition = LOWORD(IMMDict::dict().getCompositionString(hInputContext, GCS_CURSORPOS, 0, 0));
+
+        targetFrame->editor()->setComposition(compositionString, underlines, cursorPosition, 0);
     }
-cleanup:
-    targetFrame->editor()->setIgnoreMarkedTextSelectionChange(false);
+
     return true;
 }
 
@@ -3974,10 +3917,6 @@ bool WebView::onIMEEndComposition()
 {
     if (m_inIMEComposition) 
         m_inIMEComposition--;
-    Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
-    if (!targetFrame)
-        return true;
-    targetFrame->editor()->unmarkText();
     return true;
 }
 
@@ -3994,8 +3933,8 @@ bool WebView::onIMENotify(WPARAM, LPARAM, LRESULT*)
 bool WebView::onIMERequestCharPosition(Frame* targetFrame, IMECHARPOSITION* charPos, LRESULT* result)
 {
     IntRect caret;
-    ASSERT(charPos->dwCharPos == 0 || targetFrame->markedTextRange());
-    if (RefPtr<Range> range = targetFrame->markedTextRange() ? targetFrame->markedTextRange() : targetFrame->selectionController()->selection().toRange()) {
+    ASSERT(charPos->dwCharPos == 0 || targetFrame->editor()->hasComposition());
+    if (RefPtr<Range> range = targetFrame->editor()->hasComposition() ? targetFrame->editor()->compositionRange() : targetFrame->selectionController()->selection().toRange()) {
         ExceptionCode ec = 0;
         RefPtr<Range> tempRange = range->cloneRange(ec);
         tempRange->setStart(tempRange->startContainer(ec), tempRange->startOffset(ec) + charPos->dwCharPos, ec);