1/*
2 * Copyright (C) 2010 Apple 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
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#import "config.h"
27#import "PluginProcess.h"
28
29#if ENABLE(PLUGIN_PROCESS)
30
31#import "NetscapePlugin.h"
32#import "PluginProcessShim.h"
33#import "PluginProcessProxyMessages.h"
34#import "PluginProcessCreationParameters.h"
35#import <WebCore/LocalizedStrings.h>
36#import <WebKitSystemInterface.h>
37#import <dlfcn.h>
38#import <wtf/HashSet.h>
39
40namespace WebKit {
41
42class FullscreenWindowTracker {
43    WTF_MAKE_NONCOPYABLE(FullscreenWindowTracker);
44
45public:
46    FullscreenWindowTracker() { }
47
48    template<typename T> void windowShown(T window);
49    template<typename T> void windowHidden(T window);
50
51private:
52    typedef HashSet<void*> WindowSet;
53    WindowSet m_windows;
54};
55
56static bool rectCoversAnyScreen(NSRect rect)
57{
58    for (NSScreen *screen in [NSScreen screens]) {
59        if (NSContainsRect(rect, [screen frame]))
60            return YES;
61    }
62    return NO;
63}
64
65#ifndef NP_NO_CARBON
66static bool windowCoversAnyScreen(WindowRef window)
67{
68    HIRect bounds;
69    HIWindowGetBounds(window, kWindowStructureRgn, kHICoordSpaceScreenPixel, &bounds);
70
71    // Convert to Cocoa-style screen coordinates that use a Y offset relative to the zeroth screen's origin.
72    bounds.origin.y = NSHeight([(NSScreen *)[[NSScreen screens] objectAtIndex:0] frame]) - CGRectGetMaxY(bounds);
73
74    return rectCoversAnyScreen(NSRectFromCGRect(bounds));
75}
76#endif
77
78static bool windowCoversAnyScreen(NSWindow* window)
79{
80    return rectCoversAnyScreen([window frame]);
81}
82
83template<typename T> void FullscreenWindowTracker::windowShown(T window)
84{
85    // If this window is already visible then there is nothing to do.
86    WindowSet::iterator it = m_windows.find(window);
87    if (it != m_windows.end())
88        return;
89
90    // If the window is not full-screen then we're not interested in it.
91    if (!windowCoversAnyScreen(window))
92        return;
93
94    bool windowSetWasEmpty = m_windows.isEmpty();
95
96    m_windows.add(window);
97
98    // If this is the first full screen window to be shown, notify the UI process.
99    if (windowSetWasEmpty)
100        PluginProcess::shared().setFullscreenWindowIsShowing(true);
101}
102
103template<typename T> void FullscreenWindowTracker::windowHidden(T window)
104{
105    // If this is not a window that we're tracking then there is nothing to do.
106    WindowSet::iterator it = m_windows.find(window);
107    if (it == m_windows.end())
108        return;
109
110    m_windows.remove(it);
111
112    // If this was the last full screen window that was visible, notify the UI process.
113    if (m_windows.isEmpty())
114        PluginProcess::shared().setFullscreenWindowIsShowing(false);
115}
116
117static FullscreenWindowTracker& fullscreenWindowTracker()
118{
119    DEFINE_STATIC_LOCAL(FullscreenWindowTracker, fullscreenWindowTracker, ());
120    return fullscreenWindowTracker;
121}
122
123static bool isUserbreakSet = false;
124
125static void initShouldCallRealDebugger()
126{
127    char* var = getenv("USERBREAK");
128
129    if (var)
130        isUserbreakSet = atoi(var);
131}
132
133static bool shouldCallRealDebugger()
134{
135    static pthread_once_t shouldCallRealDebuggerOnce = PTHREAD_ONCE_INIT;
136    pthread_once(&shouldCallRealDebuggerOnce, initShouldCallRealDebugger);
137
138    return isUserbreakSet;
139}
140
141static bool isWindowActive(WindowRef windowRef, bool& result)
142{
143#ifndef NP_NO_CARBON
144    if (NetscapePlugin* plugin = NetscapePlugin::netscapePluginFromWindow(windowRef)) {
145        result = plugin->isWindowActive();
146        return true;
147    }
148#endif
149    return false;
150}
151
152static UInt32 getCurrentEventButtonState()
153{
154#ifndef NP_NO_CARBON
155    return NetscapePlugin::buttonState();
156#else
157    ASSERT_NOT_REACHED();
158    return 0;
159#endif
160}
161
162static void cocoaWindowShown(NSWindow *window)
163{
164    fullscreenWindowTracker().windowShown(window);
165}
166
167static void cocoaWindowHidden(NSWindow *window)
168{
169    fullscreenWindowTracker().windowHidden(window);
170}
171
172static void carbonWindowShown(WindowRef window)
173{
174#ifndef NP_NO_CARBON
175    fullscreenWindowTracker().windowShown(window);
176#endif
177}
178
179static void carbonWindowHidden(WindowRef window)
180{
181#ifndef NP_NO_CARBON
182    fullscreenWindowTracker().windowHidden(window);
183#endif
184}
185
186static void setModal(bool modalWindowIsShowing)
187{
188    PluginProcess::shared().setModalWindowIsShowing(modalWindowIsShowing);
189}
190
191void PluginProcess::initializeShim()
192{
193    const PluginProcessShimCallbacks callbacks = {
194        shouldCallRealDebugger,
195        isWindowActive,
196        getCurrentEventButtonState,
197        cocoaWindowShown,
198        cocoaWindowHidden,
199        carbonWindowShown,
200        carbonWindowHidden,
201        setModal,
202    };
203
204    PluginProcessShimInitializeFunc initFunc = reinterpret_cast<PluginProcessShimInitializeFunc>(dlsym(RTLD_DEFAULT, "WebKitPluginProcessShimInitialize"));
205    initFunc(callbacks);
206}
207
208void PluginProcess::setModalWindowIsShowing(bool modalWindowIsShowing)
209{
210    m_connection->send(Messages::PluginProcessProxy::SetModalWindowIsShowing(modalWindowIsShowing), 0);
211}
212
213void PluginProcess::setFullscreenWindowIsShowing(bool fullscreenWindowIsShowing)
214{
215    m_connection->send(Messages::PluginProcessProxy::SetFullscreenWindowIsShowing(fullscreenWindowIsShowing), 0);
216}
217
218void PluginProcess::platformInitialize(const PluginProcessCreationParameters& parameters)
219{
220    m_compositingRenderServerPort = parameters.acceleratedCompositingPort.port();
221
222    NSString *applicationName = [NSString stringWithFormat:WEB_UI_STRING("%@ (%@ Internet plug-in)",
223                                                                     "visible name of the plug-in host process. The first argument is the plug-in name "
224                                                                     "and the second argument is the application name."),
225                                 [[(NSString *)parameters.pluginPath lastPathComponent] stringByDeletingPathExtension],
226                                 (NSString *)parameters.parentProcessName];
227
228    WKSetVisibleApplicationName((CFStringRef)applicationName);
229}
230
231} // namespace WebKit
232
233#endif // ENABLE(PLUGIN_PROCESS)
234