1/*
2 * Copyright (C) 2009 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 "WebPopupMenuImpl.h"
33
34#include "Cursor.h"
35#include "FramelessScrollView.h"
36#include "FrameView.h"
37#include "IntRect.h"
38#include "painting/GraphicsContextBuilder.h"
39#include "PlatformKeyboardEvent.h"
40#include "PlatformMouseEvent.h"
41#include "PlatformWheelEvent.h"
42#include "SkiaUtils.h"
43
44#include "WebInputEvent.h"
45#include "WebInputEventConversion.h"
46#include "WebRect.h"
47#include "WebWidgetClient.h"
48
49#include <skia/ext/platform_canvas.h>
50
51using namespace WebCore;
52
53namespace WebKit {
54
55// WebPopupMenu ---------------------------------------------------------------
56
57WebPopupMenu* WebPopupMenu::create(WebWidgetClient* client)
58{
59    // Pass the WebPopupMenuImpl's self-reference to the caller.
60    return adoptRef(new WebPopupMenuImpl(client)).leakRef();
61}
62
63// WebWidget ------------------------------------------------------------------
64
65WebPopupMenuImpl::WebPopupMenuImpl(WebWidgetClient* client)
66    : m_client(client)
67    , m_widget(0)
68{
69    // set to impossible point so we always get the first mouse pos
70    m_lastMousePosition = WebPoint(-1, -1);
71}
72
73WebPopupMenuImpl::~WebPopupMenuImpl()
74{
75    if (m_widget)
76        m_widget->setClient(0);
77}
78
79void WebPopupMenuImpl::Init(FramelessScrollView* widget, const WebRect& bounds)
80{
81    m_widget = widget;
82    m_widget->setClient(this);
83
84    if (m_client) {
85        m_client->setWindowRect(bounds);
86        m_client->show(WebNavigationPolicy());  // Policy is ignored
87    }
88}
89
90void WebPopupMenuImpl::MouseMove(const WebMouseEvent& event)
91{
92    // don't send mouse move messages if the mouse hasn't moved.
93    if (event.x != m_lastMousePosition.x || event.y != m_lastMousePosition.y) {
94        m_lastMousePosition = WebPoint(event.x, event.y);
95        m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event));
96    }
97}
98
99void WebPopupMenuImpl::MouseLeave(const WebMouseEvent& event)
100{
101    m_widget->handleMouseMoveEvent(PlatformMouseEventBuilder(m_widget, event));
102}
103
104void WebPopupMenuImpl::MouseDown(const WebMouseEvent& event)
105{
106    m_widget->handleMouseDownEvent(PlatformMouseEventBuilder(m_widget, event));
107}
108
109void WebPopupMenuImpl::MouseUp(const WebMouseEvent& event)
110{
111    mouseCaptureLost();
112    m_widget->handleMouseReleaseEvent(PlatformMouseEventBuilder(m_widget, event));
113}
114
115void WebPopupMenuImpl::MouseWheel(const WebMouseWheelEvent& event)
116{
117    m_widget->handleWheelEvent(PlatformWheelEventBuilder(m_widget, event));
118}
119
120bool WebPopupMenuImpl::KeyEvent(const WebKeyboardEvent& event)
121{
122    return m_widget->handleKeyEvent(PlatformKeyboardEventBuilder(event));
123}
124
125// WebWidget -------------------------------------------------------------------
126
127void WebPopupMenuImpl::close()
128{
129    if (m_widget)
130        m_widget->hide();
131
132    m_client = 0;
133
134    deref();  // Balances ref() from WebWidget::Create
135}
136
137void WebPopupMenuImpl::resize(const WebSize& newSize)
138{
139    if (m_size == newSize)
140        return;
141    m_size = newSize;
142
143    if (m_widget) {
144        IntRect newGeometry(0, 0, m_size.width, m_size.height);
145        m_widget->setFrameRect(newGeometry);
146    }
147
148    if (m_client) {
149        WebRect damagedRect(0, 0, m_size.width, m_size.height);
150        m_client->didInvalidateRect(damagedRect);
151    }
152}
153
154void WebPopupMenuImpl::animate()
155{
156}
157
158void WebPopupMenuImpl::layout()
159{
160}
161
162void WebPopupMenuImpl::paint(WebCanvas* canvas, const WebRect& rect)
163{
164    if (!m_widget)
165        return;
166
167    if (!rect.isEmpty())
168        m_widget->paint(&GraphicsContextBuilder(canvas).context(), rect);
169}
170
171void WebPopupMenuImpl::themeChanged()
172{
173    notImplemented();
174}
175
176void WebPopupMenuImpl::composite(bool finish)
177{
178    notImplemented();
179}
180
181bool WebPopupMenuImpl::handleInputEvent(const WebInputEvent& inputEvent)
182{
183    if (!m_widget)
184        return false;
185
186    // TODO (jcampan): WebKit seems to always return false on mouse events
187    // methods. For now we'll assume it has processed them (as we are only
188    // interested in whether keyboard events are processed).
189    switch (inputEvent.type) {
190    case WebInputEvent::MouseMove:
191        MouseMove(*static_cast<const WebMouseEvent*>(&inputEvent));
192        return true;
193
194    case WebInputEvent::MouseLeave:
195        MouseLeave(*static_cast<const WebMouseEvent*>(&inputEvent));
196        return true;
197
198    case WebInputEvent::MouseWheel:
199        MouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
200        return true;
201
202    case WebInputEvent::MouseDown:
203        MouseDown(*static_cast<const WebMouseEvent*>(&inputEvent));
204        return true;
205
206    case WebInputEvent::MouseUp:
207        MouseUp(*static_cast<const WebMouseEvent*>(&inputEvent));
208        return true;
209
210    // In Windows, RawKeyDown only has information about the physical key, but
211    // for "selection", we need the information about the character the key
212    // translated into. For English, the physical key value and the character
213    // value are the same, hence, "selection" works for English. But for other
214    // languages, such as Hebrew, the character value is different from the
215    // physical key value. Thus, without accepting Char event type which
216    // contains the key's character value, the "selection" won't work for
217    // non-English languages, such as Hebrew.
218    case WebInputEvent::RawKeyDown:
219    case WebInputEvent::KeyDown:
220    case WebInputEvent::KeyUp:
221    case WebInputEvent::Char:
222        return KeyEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
223
224    default:
225        break;
226    }
227    return false;
228}
229
230void WebPopupMenuImpl::mouseCaptureLost()
231{
232}
233
234void WebPopupMenuImpl::setFocus(bool enable)
235{
236}
237
238bool WebPopupMenuImpl::setComposition(
239    const WebString& text, const WebVector<WebCompositionUnderline>& underlines,
240    int selectionStart, int selectionEnd)
241{
242    return false;
243}
244
245bool WebPopupMenuImpl::confirmComposition()
246{
247    return false;
248}
249
250bool WebPopupMenuImpl::confirmComposition(const WebString& text)
251{
252    return false;
253}
254
255WebTextInputType WebPopupMenuImpl::textInputType()
256{
257    return WebTextInputTypeNone;
258}
259
260WebRect WebPopupMenuImpl::caretOrSelectionBounds()
261{
262    return WebRect();
263}
264
265void WebPopupMenuImpl::setTextDirection(WebTextDirection direction)
266{
267}
268
269
270//-----------------------------------------------------------------------------
271// WebCore::HostWindow
272
273void WebPopupMenuImpl::invalidateContents(const IntRect&, bool)
274{
275    notImplemented();
276}
277
278void WebPopupMenuImpl::invalidateWindow(const IntRect&, bool)
279{
280    notImplemented();
281}
282
283void WebPopupMenuImpl::invalidateContentsAndWindow(const IntRect& paintRect, bool /*immediate*/)
284{
285    if (paintRect.isEmpty())
286        return;
287    if (m_client)
288        m_client->didInvalidateRect(paintRect);
289}
290
291void WebPopupMenuImpl::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
292{
293    invalidateContentsAndWindow(updateRect, immediate);
294}
295
296void WebPopupMenuImpl::scheduleAnimation()
297{
298}
299
300void WebPopupMenuImpl::scroll(const IntSize& scrollDelta,
301                              const IntRect& scrollRect,
302                              const IntRect& clipRect)
303{
304    if (m_client) {
305        int dx = scrollDelta.width();
306        int dy = scrollDelta.height();
307        m_client->didScrollRect(dx, dy, clipRect);
308    }
309}
310
311IntPoint WebPopupMenuImpl::screenToWindow(const IntPoint& point) const
312{
313    notImplemented();
314    return IntPoint();
315}
316
317IntRect WebPopupMenuImpl::windowToScreen(const IntRect& rect) const
318{
319    notImplemented();
320    return IntRect();
321}
322
323void WebPopupMenuImpl::scrollRectIntoView(const IntRect&, const ScrollView*) const
324{
325    // Nothing to be done here since we do not have the concept of a container
326    // that implements its own scrolling.
327}
328
329void WebPopupMenuImpl::scrollbarsModeDidChange() const
330{
331    // Nothing to be done since we have no concept of different scrollbar modes.
332}
333
334void WebPopupMenuImpl::setCursor(const WebCore::Cursor&)
335{
336}
337
338//-----------------------------------------------------------------------------
339// WebCore::FramelessScrollViewClient
340
341void WebPopupMenuImpl::popupClosed(FramelessScrollView* widget)
342{
343    ASSERT(widget == m_widget);
344    if (m_widget) {
345        m_widget->setClient(0);
346        m_widget = 0;
347    }
348    m_client->closeWidgetSoon();
349}
350
351} // namespace WebKit
352