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 8f2fb6fe271423f8541db1a786c9d6147b5ef5cf..2cae45fa7c9d596550ae22a5ca7672cd0751dc82 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 acfd52f0b948a653fc06f28c53fd2721640a8ad4..89cc896c737918d40e2c524a0aef99090328db86 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 cbc68b44481406c6418a57573ada603487310829..93bfb42fbc25bcf206ae6676a347e56419d15cb4 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 3531e973651566c10d5bb9e380b35db2ea2c724c..1160f42d6a77cb93c32d043b62b4fadb86be4833 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 42382cafec72ca9deccfe2ee111a94a894a1ce57..bfa791becb1508ee6d34d98edca09a5766273f25 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 823e21f7b5732fc501e08e085a4bfc0c1293a879..f0be982b596de0a66cf4183745968e57eccc78b9 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 f892e0bedc49ecdb70551fcadec08980cfaf9123..fd5a327706fa3c1a12fa941c7ea4ac17f838efd4 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 44e97ee64c6d69277c3feb7afb0ab9e4bc232aa8..ff179f8cd4fdcee435c843eeccd80d430e796384 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
@@ -1030,32 +1029,26 @@ 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 9e82700e0b86ba55e5f4b7edad14b6c5f04c465e..7aaa03ad4f54e7ce342bb6bc6f2d27d8f2ff0172 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 5979d8ae2a93854834341315ac04be681c6a5ffb..fe0aa699d7b74dc85b8235980e4f75e64e03584a 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 2ccb6533d9ecf0b330a4ff7616d074fd493f3ad0..14a143eb8a8363a5e7e11b116971cbab58aeeccd 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 748db9be35b35b7667ff1a8347db51785d86bcf5..14165899c7f12906827839f4a63d5cd775b5cdfb 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 49e67bc1fa7f45312551d40fcd21a4d2df054b5c..cfb197e31882c458cedcfe473020f651728a48e9 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 06e740654dcf2b0a92b354692dd528dbbfef8f1a..65510f264b5aa26e91468fbf1f4e3b62efed4fba 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 e9b573a311e51048c396ad249ad1d9a82737d0bd..6b08e109f54184a51c5ed89d251cb146a372a8d2 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 0e9b0eb79b78fc71d21c614c2ba6cca0044d1c39..d9ded76fafe95d1f98bb4d660290bd19b469df55 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 3aa5ca9d9778ae21bb00906cfc7f8be5c3fff77d..05bf80e616c7e41e5606566b67ae01ebd78433e5 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 113c118bc8754a4dc59c1c9cd144433c0adb94b5..9e8d64a97a4391edf8ca5543448eb95bbd461f93 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 3674176e047f8a4e740ba7c1d7c56dc777bc53fb..1d72520f702bdbcdb53c20a79d745dbab4bf8bd2 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 a7fc6c86e07e9663c2c3bf76985da44cb6f032ee..c91469ba0e4b0f93472365b58a3b4960afacbe27 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 82bdd77b2476c82cd69995aea690228843a0b296..7f70f1d5453b6b08b63b725577695402f7dbcfcd 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 dcccd4b8a1b1c7a38b65308a0c590773c8653537..55262369a1b39672e816b9179d59fcf3c028dadf 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 c014652f0071ceca7cafcbb31e6ab0861a0ce36c..ab7bca1e73ed3f0652d9bbabacd559f3e407ef24 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 e798073b2b5b3ba01f3ec9f8f196e699d9eb79b7..ff5615d72aea5d135cf27c3d4510c98903b50976 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 b83fc898c8f0c03db1c15b31f11a08d78fc3b962..533f415fc1f3c56daa89e7cfda9063ae127d80fb 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 47512c8cb2731ffc04b3d632c5b98ba05370b216..3552ab1f3bdee42e9cc8a0233f26a7af2aef0288 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 f77a3118c9692e386f0eb679165aa4b2ec1cb959..306a6997277e3881f8f54d58d8989710f2687208 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 c3fbf22789d8fb5038945f939b88b5f6c5b3b3f6..d5bac295cf543739313fad40a3095469410d5d46 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 bf8b3c4aca575713a186b6b091a8888f56b08893..7fa6bbe0998de7d4c0e32c42abd18506c447947d 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 46416bce413ae2557f9c04869068b02723abe58f..a0318f7d2c3c93c2467d1887d5799c2c67a8f8e0 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 1abc21d977beb1319a3451f5052c60dc86e5c4e0..f93df5b49c465a6c64bad36ab4d65530786fa753 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 7527db611315dd8e31716038815f7f777b4fc385..4cee1deab6973a03dd1e8df79272b2a5dc2a4bea 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);