+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.
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
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
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
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
+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.
__ZN7WebCore16NavigationActionC1ERKNS_4KURLENS_13FrameLoadTypeEb
__ZN7WebCore16NavigationActionC1ERKNS_4KURLENS_14NavigationTypeE
__ZN7WebCore16NavigationActionC1Ev
+__ZN7WebCore16colorFromNSColorEP7NSColor
__ZN7WebCore18PlatformMouseEventC1EP7NSEvent
__ZN7WebCore19InspectorController16setWindowVisibleEb
__ZN7WebCore19InspectorController7inspectEPNS_4NodeE
__ZN7WebCore5Frame20setSelectionFromNoneEv
__ZN7WebCore5Frame20windowScriptNPObjectEv
__ZN7WebCore5Frame21setProhibitsScrollingEb
-__ZN7WebCore5Frame23selectRangeInMarkedTextEjj
__ZN7WebCore5Frame26dashboardRegionsDictionaryEv
__ZN7WebCore5Frame29cleanupScriptObjectsForPluginEPv
__ZN7WebCore5Frame4initEv
__ZN7WebCore5equalEPKNS_10StringImplES2_
__ZN7WebCore6Editor10applyStyleEPNS_19CSSStyleDeclarationENS_10EditActionE
__ZN7WebCore6Editor10insertTextERKNS_6StringEPNS_5EventE
-__ZN7WebCore6Editor10unmarkTextEv
__ZN7WebCore6Editor11canDHTMLCutEv
__ZN7WebCore6Editor11deleteRangeEPNS_5RangeEbbbNS_18EditorDeleteActionENS_15TextGranularityE
__ZN7WebCore6Editor11execCommandERKNS_12AtomicStringEPNS_5EventE
__ZN7WebCore6Editor13performDeleteEv
__ZN7WebCore6Editor13rangeForPointERKNS_8IntPointE
__ZN7WebCore6Editor13tryDHTMLPasteEv
+__ZN7WebCore6Editor14setCompositionERKNS_6StringERKN3WTF6VectorINS_20CompositionUnderlineELm0EEEjj
__ZN7WebCore6Editor16pasteAsPlainTextEv
-__ZN7WebCore6Editor16selectMarkedTextEv
-__ZN7WebCore6Editor17discardMarkedTextEv
__ZN7WebCore6Editor17insertOrderedListEv
-__ZN7WebCore6Editor17replaceMarkedTextERKNS_6StringE
+__ZN7WebCore6Editor18confirmCompositionERKNS_6StringE
+__ZN7WebCore6Editor18confirmCompositionEv
__ZN7WebCore6Editor19deleteWithDirectionENS_19SelectionController10EDirectionENS_15TextGranularityEbb
__ZN7WebCore6Editor19insertUnorderedListEv
__ZN7WebCore6Editor21applyStyleToSelectionEPNS_19CSSStyleDeclarationENS_10EditActionE
__ZN7WebCore6Editor32guessesForUngrammaticalSelectionEv
__ZN7WebCore6Editor33increaseSelectionListLevelOrderedEv
__ZN7WebCore6Editor33insertTextWithoutSendingTextEventERKNS_6StringEbPNS_5EventE
-__ZN7WebCore6Editor34setIgnoreMarkedTextSelectionChangeEb
__ZN7WebCore6Editor35increaseSelectionListLevelUnorderedEv
+__ZN7WebCore6Editor35setIgnoreCompositionSelectionChangeEb
__ZN7WebCore6Editor3cutEv
+__ZN7WebCore6Editor44confirmCompositionWithoutDisturbingSelectionEv
__ZN7WebCore6Editor4copyEv
__ZN7WebCore6Editor5pasteEv
__ZN7WebCore6Editor6indentEv
__ZNK7WebCore6Editor13canEditRichlyEv
__ZNK7WebCore6Editor17shouldDeleteRangeEPNS_5RangeE
__ZNK7WebCore6Editor22selectionStartHasStyleEPNS_19CSSStyleDeclarationE
+__ZNK7WebCore6Editor23getCompositionSelectionERjS1_
__ZNK7WebCore6Editor6canCutEv
__ZNK7WebCore6Editor7canCopyEv
__ZNK7WebCore6Editor7canEditEv
virtual void textDidChangeInTextArea(Element*) = 0;
#if PLATFORM(MAC)
- virtual void markedTextAbandoned(Frame*) = 0;
-
// FIXME: This should become SelectionController::toWebArchive()
virtual NSData* dataForArchivedSelection(Frame*) = 0;
/**
- * 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
namespace WebCore {
+using namespace std;
using namespace HTMLNames;
#ifndef NDEBUG
}
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
Node *Range::pastEndNode() const
{
- if (!m_endContainer)
+ if (!m_startContainer || !m_endContainer)
return 0;
if (m_endContainer->offsetInCharacters())
return m_endContainer->traverseNextSibling();
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;
#include "ReplaceSelectionCommand.h"
#include "SelectionController.h"
#include "Sound.h"
+#include "Text.h"
#include "TextIterator.h"
#include "TypingCommand.h"
#include "htmlediting.h"
namespace WebCore {
class FontData;
+
+using namespace std;
using namespace EventNames;
using namespace HTMLNames;
Editor::Editor(Frame* frame)
: m_frame(frame)
, m_deleteButtonController(new DeleteButtonController(frame))
- , m_ignoreMarkedTextSelectionChange(false)
+ , m_ignoreCompositionSelectionChange(false)
{
}
{
}
+void Editor::clear()
+{
+ m_compositionNode = 0;
+ m_customCompositionUnderlines.clear();
+}
+
bool Editor::execCommand(const AtomicString& command, Event* triggeringEvent)
{
if (!m_frame->document())
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();
}
}
- setIgnoreMarkedTextSelectionChange(false);
-
- // Inserting unmarks any marked text.
- unmarkText();
-
return true;
}
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()
markMisspellingsOrBadGrammar(this, selection, false);
#endif
}
-
-
+
PassRefPtr<Range> Editor::rangeForPoint(const IntPoint& windowPoint)
{
Document* document = m_frame->documentAtPoint(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
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*);
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();
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
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);
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);
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*);
// 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;
#include "ResourceRequest.h"
#include "SelectionController.h"
#include "Settings.h"
+#include "TextIterator.h"
#include "markup.h"
namespace WebCore {
selectedRange = document->createRange();
selectedRange->selectNode(document->documentElement(), ec);
}
- m_client->speak(selectedRange->toString(true, ec));
+ m_client->speak(plainText(selectedRange.get()));
break;
}
case ContextMenuItemTagStopSpeaking:
return plainText(selectionController()->toRange().get());
}
-Range* Frame::markedTextRange() const
-{
- return d->m_markedTextRange.get();
-}
-
-
IntRect Frame::firstRectForRange(Range* range) const
{
int extraWidthToEndOfLine = 0;
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;
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())
, m_loader(new FrameLoader(thisFrame, frameLoaderClient))
, m_userStyleSheetLoader(0)
, m_paintRestriction(PaintRestrictionNone)
- , m_markedTextUsesUnderlines(false)
, m_highlightTextMatches(false)
, m_windowHasFocus(false)
, m_inViewSourceMode(false)
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
void applyEditingStyleToElement(Element*) const;
void removeEditingStyleFromElement(Element*) const;
- Range* markedTextRange() const;
IntRect firstRectForRange(Range*) const;
#if PLATFORM(MAC)
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);
NSDictionary* fontAttributesForSelectionStart() const;
NSWritingDirection baseWritingDirectionForSelectionStart() const;
- void setMarkedTextRange(Range* , NSArray* attributes, NSArray* ranges);
-
#endif
};
RefPtr<Node> m_elementToDraw;
PaintRestriction m_paintRestriction;
- bool m_markedTextUsesUnderlines;
- Vector<MarkedTextUnderline> m_markedTextUnderlines;
bool m_highlightTextMatches;
bool m_windowHasFocus;
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;
}
}
-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();
- (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;
#import "SmartReplace.h"
#import "SubresourceLoader.h"
#import "SystemTime.h"
+#import "Text.h"
#import "TextEncoding.h"
#import "TextIterator.h"
#import "TextResourceDecoder.h"
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
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;
#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>
// 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);
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.
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);
}
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();
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;
+ }
}
}
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);
}
-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;
class String;
class StringImpl;
-class MarkedTextUnderline;
class HitTestResult;
class Position;
+struct CompositionUnderline;
+
class InlineTextBox : public InlineRunBox {
public:
InlineTextBox(RenderObject* obj)
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
/**
- * 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
#include "config.h"
#include "RenderTextControl.h"
+#include "CharacterNames.h"
#include "Document.h"
#include "Editor.h"
#include "EditorClient.h"
#include "SearchPopupMenu.h"
#include "SelectionController.h"
#include "Settings.h"
+#include "Text.h"
#include "TextIterator.h"
#include "TextStyle.h"
#include "htmlediting.h"
}
}
+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()
const AtomicString& autosaveName() const;
void startSearchEventTimer();
void searchEventTimerFired(Timer<RenderTextControl>*);
+ String finishText(Vector<UChar>&) const;
RefPtr<HTMLTextFieldInnerElement> m_innerBlock;
RefPtr<HTMLTextFieldInnerTextElement> m_innerText;
+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.
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*);
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)
#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>
{
[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
}
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];
- (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;
}
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;
}
- (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;
}
}
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;
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
{
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;
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
// 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;
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)
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];
}
}
+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.
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);
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);
}
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);
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);
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);
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;
}
{
if (m_inIMEComposition)
m_inIMEComposition--;
- Frame* targetFrame = m_page->focusController()->focusedOrMainFrame();
- if (!targetFrame)
- return true;
- targetFrame->editor()->unmarkText();
return true;
}
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);