1/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "core/html/ime/InputMethodContext.h"
33
34#include "core/dom/Document.h"
35#include "core/dom/Text.h"
36#include "core/editing/InputMethodController.h"
37#include "core/events/Event.h"
38#include "core/frame/LocalFrame.h"
39
40namespace blink {
41
42PassOwnPtrWillBeRawPtr<InputMethodContext> InputMethodContext::create(HTMLElement* element)
43{
44    return adoptPtrWillBeNoop(new InputMethodContext(element));
45}
46
47InputMethodContext::InputMethodContext(HTMLElement* element)
48    : m_element(element)
49{
50}
51
52InputMethodContext::~InputMethodContext()
53{
54}
55
56String InputMethodContext::locale() const
57{
58    // FIXME: Implement this.
59    return emptyString();
60}
61
62HTMLElement* InputMethodContext::target() const
63{
64    return m_element;
65}
66
67unsigned InputMethodContext::compositionStartOffset()
68{
69    if (hasFocus())
70        return inputMethodController().compositionStart();
71    return 0;
72}
73
74unsigned InputMethodContext::compositionEndOffset()
75{
76    if (hasFocus())
77        return inputMethodController().compositionEnd();
78    return 0;
79}
80
81void InputMethodContext::confirmComposition()
82{
83    if (hasFocus())
84        inputMethodController().confirmCompositionAndResetState();
85}
86
87bool InputMethodContext::hasFocus() const
88{
89    LocalFrame* frame = m_element->document().frame();
90    if (!frame)
91        return false;
92
93    const Element* element = frame->document()->focusedElement();
94    return element && element->isHTMLElement() && m_element == toHTMLElement(element);
95}
96
97String InputMethodContext::compositionText() const
98{
99    if (!hasFocus())
100        return emptyString();
101
102    Text* text = inputMethodController().compositionNode();
103    return text ? text->wholeText() : emptyString();
104}
105
106CompositionUnderline InputMethodContext::selectedSegment() const
107{
108    CompositionUnderline underline;
109    if (!hasFocus())
110        return underline;
111
112    const InputMethodController& controller = inputMethodController();
113    if (!controller.hasComposition())
114        return underline;
115
116    Vector<CompositionUnderline> underlines = controller.customCompositionUnderlines();
117    for (size_t i = 0; i < underlines.size(); ++i) {
118        if (underlines[i].thick)
119            return underlines[i];
120    }
121
122    // When no underline information is available while composition exists,
123    // build a CompositionUnderline whose element is the whole composition.
124    underline.endOffset = controller.compositionEnd() - controller.compositionStart();
125    return underline;
126
127}
128
129int InputMethodContext::selectionStart() const
130{
131    return selectedSegment().startOffset;
132}
133
134int InputMethodContext::selectionEnd() const
135{
136    return selectedSegment().endOffset;
137}
138
139const Vector<unsigned>& InputMethodContext::segments()
140{
141    m_segments.clear();
142    if (!hasFocus())
143        return m_segments;
144    const InputMethodController& controller = inputMethodController();
145    if (!controller.hasComposition())
146        return m_segments;
147
148    Vector<CompositionUnderline> underlines = controller.customCompositionUnderlines();
149    if (!underlines.size()) {
150        m_segments.append(0);
151    } else {
152        for (size_t i = 0; i < underlines.size(); ++i)
153            m_segments.append(underlines[i].startOffset);
154    }
155
156    return m_segments;
157}
158
159InputMethodController& InputMethodContext::inputMethodController() const
160{
161    return m_element->document().frame()->inputMethodController();
162}
163
164const AtomicString& InputMethodContext::interfaceName() const
165{
166    return EventTargetNames::InputMethodContext;
167}
168
169ExecutionContext* InputMethodContext::executionContext() const
170{
171    return &m_element->document();
172}
173
174void InputMethodContext::dispatchCandidateWindowShowEvent()
175{
176    dispatchEvent(Event::create(EventTypeNames::candidatewindowshow));
177}
178
179void InputMethodContext::dispatchCandidateWindowUpdateEvent()
180{
181    dispatchEvent(Event::create(EventTypeNames::candidatewindowupdate));
182}
183
184void InputMethodContext::dispatchCandidateWindowHideEvent()
185{
186    dispatchEvent(Event::create(EventTypeNames::candidatewindowhide));
187}
188
189void InputMethodContext::trace(Visitor* visitor)
190{
191    visitor->trace(m_element);
192    EventTargetWithInlineData::trace(visitor);
193}
194
195} // namespace blink
196