|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 // Use "dyld interposing" to hook methods imported from other libraries in the |
|
7 // plugin child process. The basic technique is described at |
|
8 // http://books.google.com/books?id=K8vUkpOXhN4C&pg=PA73&lpg=PA73&dq=__interpose&source=bl&ots=OJnnXZYpZC&sig=o7I3lXvoduUi13SrPfOON7o3do4&hl=en&ei=AoehS9brCYGQNrvsmeUM&sa=X&oi=book_result&ct=result&resnum=6&ved=0CBsQ6AEwBQ#v=onepage&q=__interpose&f=false. |
|
9 // The idea of doing it for the plugin child process comes from Chromium code, |
|
10 // particularly from plugin_carbon_interpose_mac.cc |
|
11 // (http://codesearch.google.com/codesearch/p?hl=en#OAMlx_jo-ck/src/chrome/browser/plugin_carbon_interpose_mac.cc&q=nscursor&exact_package=chromium&d=1&l=168) |
|
12 // and from PluginProcessHost::Init() in plugin_process_host.cc |
|
13 // (http://codesearch.google.com/codesearch/p?hl=en#OAMlx_jo-ck/src/content/browser/plugin_process_host.cc&q=nscursor&exact_package=chromium&d=1&l=222). |
|
14 |
|
15 // These hooks are needed to make certain OS calls work from the child process |
|
16 // (a background process) that would normally only work when called in the |
|
17 // parent process (the foreground process). They allow us to serialize |
|
18 // information from the child process to the parent process, so that the same |
|
19 // (or equivalent) calls can be made from the parent process. |
|
20 |
|
21 // This file lives in a seperate module (libplugin_child_interpose.dylib), |
|
22 // which will get loaded by the OS before any other modules when the plugin |
|
23 // child process is launched (from GeckoChildProcessHost:: |
|
24 // PerformAsyncLaunchInternal()). For this reason it shouldn't link in other |
|
25 // browser modules when loaded. Instead it should use dlsym() to load |
|
26 // pointers to the methods it wants to call in other modules. |
|
27 |
|
28 #if !defined(__LP64__) |
|
29 |
|
30 #include <dlfcn.h> |
|
31 #import <Carbon/Carbon.h> |
|
32 |
|
33 // The header file QuickdrawAPI.h is missing on OS X 10.7 and up (though the |
|
34 // QuickDraw APIs defined in it are still present) -- so we need to supply the |
|
35 // relevant parts of its contents here. It's likely that Apple will eventually |
|
36 // remove the APIs themselves (probably in OS X 10.8), so we need to make them |
|
37 // weak imports, and test for their presence before using them. |
|
38 #if !defined(__QUICKDRAWAPI__) |
|
39 |
|
40 struct Cursor; |
|
41 extern "C" void SetCursor(const Cursor * crsr) __attribute__((weak_import)); |
|
42 |
|
43 #endif /* __QUICKDRAWAPI__ */ |
|
44 |
|
45 BOOL (*OnSetThemeCursorPtr) (ThemeCursor) = NULL; |
|
46 BOOL (*OnSetCursorPtr) (const Cursor*) = NULL; |
|
47 BOOL (*OnHideCursorPtr) () = NULL; |
|
48 BOOL (*OnShowCursorPtr) () = NULL; |
|
49 |
|
50 static BOOL loadXULPtrs() |
|
51 { |
|
52 if (!OnSetThemeCursorPtr) { |
|
53 // mac_plugin_interposing_child_OnSetThemeCursor(ThemeCursor cursor) is in |
|
54 // PluginInterposeOSX.mm |
|
55 OnSetThemeCursorPtr = (BOOL(*)(ThemeCursor)) |
|
56 dlsym(RTLD_DEFAULT, "mac_plugin_interposing_child_OnSetThemeCursor"); |
|
57 } |
|
58 if (!OnSetCursorPtr) { |
|
59 // mac_plugin_interposing_child_OnSetCursor(const Cursor* cursor) is in |
|
60 // PluginInterposeOSX.mm |
|
61 OnSetCursorPtr = (BOOL(*)(const Cursor*)) |
|
62 dlsym(RTLD_DEFAULT, "mac_plugin_interposing_child_OnSetCursor"); |
|
63 } |
|
64 if (!OnHideCursorPtr) { |
|
65 // mac_plugin_interposing_child_OnHideCursor() is in PluginInterposeOSX.mm |
|
66 OnHideCursorPtr = (BOOL(*)()) |
|
67 dlsym(RTLD_DEFAULT, "mac_plugin_interposing_child_OnHideCursor"); |
|
68 } |
|
69 if (!OnShowCursorPtr) { |
|
70 // mac_plugin_interposing_child_OnShowCursor() is in PluginInterposeOSX.mm |
|
71 OnShowCursorPtr = (BOOL(*)()) |
|
72 dlsym(RTLD_DEFAULT, "mac_plugin_interposing_child_OnShowCursor"); |
|
73 } |
|
74 return (OnSetCursorPtr && OnSetThemeCursorPtr && OnHideCursorPtr && OnShowCursorPtr); |
|
75 } |
|
76 |
|
77 static OSStatus MacPluginChildSetThemeCursor(ThemeCursor cursor) |
|
78 { |
|
79 if (loadXULPtrs()) { |
|
80 OnSetThemeCursorPtr(cursor); |
|
81 } |
|
82 return ::SetThemeCursor(cursor); |
|
83 } |
|
84 |
|
85 static void MacPluginChildSetCursor(const Cursor* cursor) |
|
86 { |
|
87 if (::SetCursor) { |
|
88 if (loadXULPtrs()) { |
|
89 OnSetCursorPtr(cursor); |
|
90 } |
|
91 ::SetCursor(cursor); |
|
92 } |
|
93 } |
|
94 |
|
95 static CGError MacPluginChildCGDisplayHideCursor(CGDirectDisplayID display) |
|
96 { |
|
97 if (loadXULPtrs()) { |
|
98 OnHideCursorPtr(); |
|
99 } |
|
100 return ::CGDisplayHideCursor(display); |
|
101 } |
|
102 |
|
103 static CGError MacPluginChildCGDisplayShowCursor(CGDirectDisplayID display) |
|
104 { |
|
105 if (loadXULPtrs()) { |
|
106 OnShowCursorPtr(); |
|
107 } |
|
108 return ::CGDisplayShowCursor(display); |
|
109 } |
|
110 |
|
111 #pragma mark - |
|
112 |
|
113 struct interpose_substitution { |
|
114 const void* replacement; |
|
115 const void* original; |
|
116 }; |
|
117 |
|
118 #define INTERPOSE_FUNCTION(function) \ |
|
119 { reinterpret_cast<const void*>(MacPluginChild##function), \ |
|
120 reinterpret_cast<const void*>(function) } |
|
121 |
|
122 __attribute__((used)) static const interpose_substitution substitutions[] |
|
123 __attribute__((section("__DATA, __interpose"))) = { |
|
124 INTERPOSE_FUNCTION(SetThemeCursor), |
|
125 INTERPOSE_FUNCTION(CGDisplayHideCursor), |
|
126 INTERPOSE_FUNCTION(CGDisplayShowCursor), |
|
127 // SetCursor() and other QuickDraw APIs will probably be removed in OS X |
|
128 // 10.8. But this will make 'SetCursor' NULL, which will just stop the OS |
|
129 // from interposing it (tested using an INTERPOSE_FUNCTION_BROKEN macro |
|
130 // that just sets the second address of each tuple to NULL). |
|
131 INTERPOSE_FUNCTION(SetCursor), |
|
132 }; |
|
133 |
|
134 #endif // !__LP64__ |