1/*
2 * Copyright (C) 2010 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 "SuggestionsPopupMenuClient.h"
33
34#include "CSSStyleSelector.h"
35#include "CSSValueKeywords.h"
36#include "Chrome.h"
37#include "FrameView.h"
38#include "HTMLInputElement.h"
39#include "RenderTheme.h"
40#include "WebViewImpl.h"
41
42using namespace WebCore;
43
44namespace WebKit {
45
46SuggestionsPopupMenuClient::SuggestionsPopupMenuClient()
47    : m_textField(0)
48    , m_selectedIndex(0)
49{
50}
51
52SuggestionsPopupMenuClient::~SuggestionsPopupMenuClient()
53{
54}
55
56// FIXME: Implement this per-derived class?
57void SuggestionsPopupMenuClient::valueChanged(unsigned listIndex, bool fireEvents)
58{
59    m_textField->setValue(getSuggestion(listIndex));
60
61    WebViewImpl* webView = getWebView();
62    if (!webView)
63        return;
64
65    EditorClientImpl* editor =
66        static_cast<EditorClientImpl*>(webView->page()->editorClient());
67    ASSERT(editor);
68    editor->onAutofillSuggestionAccepted(
69        static_cast<HTMLInputElement*>(m_textField.get()));
70}
71
72String SuggestionsPopupMenuClient::itemText(unsigned listIndex) const
73{
74    return getSuggestion(listIndex);
75}
76
77PopupMenuStyle SuggestionsPopupMenuClient::itemStyle(unsigned listIndex) const
78{
79    return *m_style;
80}
81
82PopupMenuStyle SuggestionsPopupMenuClient::menuStyle() const
83{
84    return *m_style;
85}
86
87int SuggestionsPopupMenuClient::clientPaddingLeft() const
88{
89    // Bug http://crbug.com/7708 seems to indicate the style can be 0.
90    RenderStyle* style = textFieldStyle();
91    if (!style)
92       return 0;
93
94    return RenderTheme::defaultTheme()->popupInternalPaddingLeft(style);
95}
96
97int SuggestionsPopupMenuClient::clientPaddingRight() const
98{
99    // Bug http://crbug.com/7708 seems to indicate the style can be 0.
100    RenderStyle* style = textFieldStyle();
101    if (!style)
102        return 0;
103
104    return RenderTheme::defaultTheme()->popupInternalPaddingRight(style);
105}
106
107void SuggestionsPopupMenuClient::popupDidHide()
108{
109    WebViewImpl* webView = getWebView();
110    if (webView)
111        webView->suggestionsPopupDidHide();
112}
113
114void SuggestionsPopupMenuClient::setTextFromItem(unsigned listIndex)
115{
116    m_textField->setValue(getSuggestion(listIndex));
117}
118
119FontSelector* SuggestionsPopupMenuClient::fontSelector() const
120{
121    return m_textField->document()->styleSelector()->fontSelector();
122}
123
124HostWindow* SuggestionsPopupMenuClient::hostWindow() const
125{
126    return m_textField->document()->view()->hostWindow();
127}
128
129PassRefPtr<Scrollbar> SuggestionsPopupMenuClient::createScrollbar(
130    ScrollbarClient* client,
131    ScrollbarOrientation orientation,
132    ScrollbarControlSize size)
133{
134    return Scrollbar::createNativeScrollbar(client, orientation, size);
135}
136
137RenderStyle* SuggestionsPopupMenuClient::textFieldStyle() const
138{
139    RenderStyle* style = m_textField->computedStyle();
140    if (!style) {
141        // It seems we can only have a 0 style in a TextField if the
142        // node is detached, in which case we the popup shoud not be
143        // showing.  Please report this in http://crbug.com/7708 and
144        // include the page you were visiting.
145        ASSERT_NOT_REACHED();
146    }
147    return style;
148}
149
150void SuggestionsPopupMenuClient::initialize(HTMLInputElement* textField,
151                                            int defaultSuggestionIndex)
152{
153    m_textField = textField;
154    m_selectedIndex = defaultSuggestionIndex;
155
156    FontDescription fontDescription;
157    RenderTheme::defaultTheme()->systemFont(CSSValueWebkitControl,
158                                            fontDescription);
159
160    // Use a smaller font size to match IE/Firefox.
161    // FIXME: http://crbug.com/7376 use the system size instead of a
162    //        fixed font size value.
163    fontDescription.setComputedSize(12.0);
164    Font font(fontDescription, 0, 0);
165    font.update(textField->document()->styleSelector()->fontSelector());
166    // The direction of text in popup menu is set the same as the direction of
167    // the input element: textField.
168    m_style.set(new PopupMenuStyle(Color::black, Color::white, font, true,
169                                   Length(WebCore::Fixed),
170                                   textField->renderer()->style()->direction()));
171}
172
173WebViewImpl* SuggestionsPopupMenuClient::getWebView() const
174{
175    Frame* frame = m_textField->document()->frame();
176    if (!frame)
177        return 0;
178
179    Page* page = frame->page();
180    if (!page)
181        return 0;
182
183    return static_cast<ChromeClientImpl*>(page->chrome()->client())->webView();
184}
185
186} // namespace WebKit
187