initial import
[vuplus_webkit] / Source / WebKit2 / UIProcess / mac / WebPageProxyMac.mm
1 /*
2  * Copyright (C) 2010, 2011 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 "WebPageProxy.h"
28
29 #import "AttributedString.h"
30 #import "DataReference.h"
31 #import "DictionaryPopupInfo.h"
32 #import "EditorState.h"
33 #import "NativeWebKeyboardEvent.h"
34 #import "PluginComplexTextInputState.h"
35 #import "PageClient.h"
36 #import "PageClientImpl.h"
37 #import "TextChecker.h"
38 #import "WebPageMessages.h"
39 #import "WebProcessProxy.h"
40 #import <wtf/text/StringConcatenate.h>
41
42 @interface NSApplication (Details)
43 - (void)speakString:(NSString *)string;
44 @end
45
46 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, process()->connection())
47
48 using namespace WebCore;
49
50 namespace WebKit {
51
52 #if defined(__ppc__) || defined(__ppc64__)
53 #define PROCESSOR "PPC"
54 #elif defined(__i386__) || defined(__x86_64__)
55 #define PROCESSOR "Intel"
56 #else
57 #error Unknown architecture
58 #endif
59
60 static inline int callGestalt(OSType selector)
61 {
62     SInt32 value = 0;
63     Gestalt(selector, &value);
64     return value;
65 }
66
67 // Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4.
68 static String macOSXVersionString()
69 {
70     // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want.
71     int major = callGestalt(gestaltSystemVersionMajor);
72     ASSERT(major);
73
74     int minor = callGestalt(gestaltSystemVersionMinor);
75     int bugFix = callGestalt(gestaltSystemVersionBugFix);
76     if (bugFix)
77         return String::format("%d_%d_%d", major, minor, bugFix);
78     if (minor)
79         return String::format("%d_%d", major, minor);
80     return String::format("%d", major);
81 }
82
83 static String userVisibleWebKitVersionString()
84 {
85     // If the version is 4 digits long or longer, then the first digit represents
86     // the version of the OS. Our user agent string should not include this first digit,
87     // so strip it off and report the rest as the version. <rdar://problem/4997547>
88     NSString *fullVersion = [[NSBundle bundleForClass:NSClassFromString(@"WKView")] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey];
89     NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
90     if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4)
91         return [fullVersion substringFromIndex:1];
92     if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4)
93         return [fullVersion substringFromIndex:1];
94     return fullVersion;
95 }
96
97 String WebPageProxy::standardUserAgent(const String& applicationNameForUserAgent)
98 {
99     DEFINE_STATIC_LOCAL(String, osVersion, (macOSXVersionString()));
100     DEFINE_STATIC_LOCAL(String, webKitVersion, (userVisibleWebKitVersionString()));
101
102     if (applicationNameForUserAgent.isEmpty())
103         return makeString("Mozilla/5.0 (Macintosh; " PROCESSOR " Mac OS X ", osVersion, ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko)");
104     return makeString("Mozilla/5.0 (Macintosh; " PROCESSOR " Mac OS X ", osVersion, ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko) ", applicationNameForUserAgent);
105 }
106
107 void WebPageProxy::getIsSpeaking(bool& isSpeaking)
108 {
109     isSpeaking = [NSApp isSpeaking];
110 }
111
112 void WebPageProxy::speak(const String& string)
113 {
114     [NSApp speakString:nsStringFromWebCoreString(string)];
115 }
116
117 void WebPageProxy::stopSpeaking()
118 {
119     [NSApp stopSpeaking:nil];
120 }
121
122 void WebPageProxy::searchWithSpotlight(const String& string)
123 {
124     [[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:nsStringFromWebCoreString(string)];
125 }
126
127 CGContextRef WebPageProxy::containingWindowGraphicsContext()
128 {
129     return m_pageClient->containingWindowGraphicsContext();
130 }
131
132 void WebPageProxy::updateWindowIsVisible(bool windowIsVisible)
133 {
134     if (!isValid())
135         return;
136     process()->send(Messages::WebPage::SetWindowIsVisible(windowIsVisible), m_pageID);
137 }
138
139 void WebPageProxy::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates, const IntPoint& accessibilityViewCoordinates)
140 {
141     if (!isValid())
142         return;
143
144     process()->send(Messages::WebPage::WindowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates, accessibilityViewCoordinates), m_pageID);
145 }
146
147 void WebPageProxy::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
148 {
149     if (!isValid()) {
150         // If this fails, we should call -discardMarkedText on input context to notify the input method.
151         // This will happen naturally later, as part of reloading the page.
152         return;
153     }
154
155     process()->sendSync(Messages::WebPage::SetComposition(text, underlines, selectionStart, selectionEnd, replacementRangeStart, replacementRangeEnd), Messages::WebPage::SetComposition::Reply(m_editorState), m_pageID);
156 }
157
158 void WebPageProxy::confirmComposition()
159 {
160     if (!isValid())
161         return;
162
163     process()->sendSync(Messages::WebPage::ConfirmComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID);
164 }
165
166 void WebPageProxy::cancelComposition()
167 {
168     if (!isValid())
169         return;
170
171     process()->sendSync(Messages::WebPage::CancelComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID);
172 }
173
174 bool WebPageProxy::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd)
175 {
176     if (!isValid())
177         return true;
178
179     bool handled = true;
180     process()->sendSync(Messages::WebPage::InsertText(text, replacementRangeStart, replacementRangeEnd), Messages::WebPage::InsertText::Reply(handled, m_editorState), m_pageID);
181     return handled;
182 }
183
184 void WebPageProxy::getMarkedRange(uint64_t& location, uint64_t& length)
185 {
186     location = NSNotFound;
187     length = 0;
188
189     if (!isValid())
190         return;
191
192     process()->sendSync(Messages::WebPage::GetMarkedRange(), Messages::WebPage::GetMarkedRange::Reply(location, length), m_pageID);
193 }
194
195 void WebPageProxy::getSelectedRange(uint64_t& location, uint64_t& length)
196 {
197     location = NSNotFound;
198     length = 0;
199
200     if (!isValid())
201         return;
202
203     process()->sendSync(Messages::WebPage::GetSelectedRange(), Messages::WebPage::GetSelectedRange::Reply(location, length), m_pageID);
204 }
205
206 void WebPageProxy::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result)
207 {
208     if (!isValid())
209         return;
210     process()->sendSync(Messages::WebPage::GetAttributedSubstringFromRange(location, length), Messages::WebPage::GetAttributedSubstringFromRange::Reply(result), m_pageID);
211 }
212
213 uint64_t WebPageProxy::characterIndexForPoint(const IntPoint point)
214 {
215     if (!isValid())
216         return 0;
217
218     uint64_t result = 0;
219     process()->sendSync(Messages::WebPage::CharacterIndexForPoint(point), Messages::WebPage::CharacterIndexForPoint::Reply(result), m_pageID);
220     return result;
221 }
222
223 IntRect WebPageProxy::firstRectForCharacterRange(uint64_t location, uint64_t length)
224 {
225     if (!isValid())
226         return IntRect();
227
228     IntRect resultRect;
229     process()->sendSync(Messages::WebPage::FirstRectForCharacterRange(location, length), Messages::WebPage::FirstRectForCharacterRange::Reply(resultRect), m_pageID);
230     return resultRect;
231 }
232
233 bool WebPageProxy::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands)
234 {
235     if (!isValid())
236         return false;
237
238     bool result = false;
239     process()->sendSync(Messages::WebPage::ExecuteKeypressCommands(commands), Messages::WebPage::ExecuteKeypressCommands::Reply(result, m_editorState), m_pageID);
240     return result;
241 }
242
243 bool WebPageProxy::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes)
244 {
245     if (!isValid())
246         return false;
247
248     bool result = false;
249     const double messageTimeout = 20;
250     process()->sendSync(Messages::WebPage::WriteSelectionToPasteboard(pasteboardName, pasteboardTypes), Messages::WebPage::WriteSelectionToPasteboard::Reply(result), m_pageID, messageTimeout);
251     return result;
252 }
253
254 bool WebPageProxy::readSelectionFromPasteboard(const String& pasteboardName)
255 {
256     if (!isValid())
257         return false;
258
259     bool result = false;
260     const double messageTimeout = 20;
261     process()->sendSync(Messages::WebPage::ReadSelectionFromPasteboard(pasteboardName), Messages::WebPage::ReadSelectionFromPasteboard::Reply(result), m_pageID, messageTimeout);
262     return result;
263 }
264
265 void WebPageProxy::setDragImage(const WebCore::IntPoint& clientPosition, const ShareableBitmap::Handle& dragImageHandle, bool isLinkDrag)
266 {
267     RefPtr<ShareableBitmap> dragImage = ShareableBitmap::create(dragImageHandle);
268     if (!dragImage)
269         return;
270     
271     m_pageClient->setDragImage(clientPosition, dragImage.release(), isLinkDrag);
272 }
273
274 void WebPageProxy::performDictionaryLookupAtLocation(const WebCore::FloatPoint& point)
275 {
276     if (!isValid())
277         return;
278
279     process()->send(Messages::WebPage::PerformDictionaryLookupAtLocation(point), m_pageID); 
280 }
281
282 void WebPageProxy::interpretQueuedKeyEvent(const EditorState& state, bool& handled, Vector<WebCore::KeypressCommand>& commands)
283 {
284     m_editorState = state;
285     handled = m_pageClient->interpretKeyEvent(m_keyEventQueue.first(), commands);
286 }
287
288 // Complex text input support for plug-ins.
289 void WebPageProxy::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput)
290 {
291     if (!isValid())
292         return;
293     
294     process()->send(Messages::WebPage::SendComplexTextInputToPlugin(pluginComplexTextInputIdentifier, textInput), m_pageID);
295 }
296
297 void WebPageProxy::uppercaseWord()
298 {
299     process()->send(Messages::WebPage::UppercaseWord(), m_pageID);
300 }
301
302 void WebPageProxy::lowercaseWord()
303 {
304     process()->send(Messages::WebPage::LowercaseWord(), m_pageID);
305 }
306
307 void WebPageProxy::capitalizeWord()
308 {
309     process()->send(Messages::WebPage::CapitalizeWord(), m_pageID);
310 }
311
312 void WebPageProxy::setSmartInsertDeleteEnabled(bool isSmartInsertDeleteEnabled)
313
314     if (m_isSmartInsertDeleteEnabled == isSmartInsertDeleteEnabled)
315         return;
316
317     TextChecker::setSmartInsertDeleteEnabled(isSmartInsertDeleteEnabled);
318     m_isSmartInsertDeleteEnabled = isSmartInsertDeleteEnabled;
319     process()->send(Messages::WebPage::SetSmartInsertDeleteEnabled(isSmartInsertDeleteEnabled), m_pageID);
320 }
321
322 void WebPageProxy::didPerformDictionaryLookup(const String& text, const DictionaryPopupInfo& dictionaryPopupInfo)
323 {
324     m_pageClient->didPerformDictionaryLookup(text, m_pageScaleFactor, dictionaryPopupInfo);
325 }
326     
327 void WebPageProxy::registerWebProcessAccessibilityToken(const CoreIPC::DataReference& data)
328 {
329     m_pageClient->accessibilityWebProcessTokenReceived(data);
330 }    
331     
332 void WebPageProxy::makeFirstResponder()
333 {
334     m_pageClient->makeFirstResponder();
335 }
336     
337 void WebPageProxy::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elementToken, const CoreIPC::DataReference& windowToken)
338 {
339     if (!isValid())
340         return;
341
342     process()->send(Messages::WebPage::RegisterUIProcessAccessibilityTokens(elementToken, windowToken), m_pageID);
343 }
344
345 void WebPageProxy::pluginFocusOrWindowFocusChanged(uint64_t pluginComplexTextInputIdentifier, bool pluginHasFocusAndWindowHasFocus)
346 {
347     m_pageClient->pluginFocusOrWindowFocusChanged(pluginComplexTextInputIdentifier, pluginHasFocusAndWindowHasFocus);
348 }
349
350 void WebPageProxy::setPluginComplexTextInputState(uint64_t pluginComplexTextInputIdentifier, uint64_t pluginComplexTextInputState)
351 {
352     MESSAGE_CHECK(isValidPluginComplexTextInputState(pluginComplexTextInputState));
353
354     m_pageClient->setPluginComplexTextInputState(pluginComplexTextInputIdentifier, static_cast<PluginComplexTextInputState>(pluginComplexTextInputState));
355 }
356
357 void WebPageProxy::executeSavedCommandBySelector(const String& selector, bool& handled)
358 {
359     handled = m_pageClient->executeSavedCommandBySelector(selector);
360 }
361
362 bool WebPageProxy::shouldDelayWindowOrderingForEvent(const WebKit::WebMouseEvent& event)
363 {
364     if (!process()->isValid())
365         return false;
366
367     bool result = false;
368     const double messageTimeout = 3;
369     process()->sendSync(Messages::WebPage::ShouldDelayWindowOrderingEvent(event), Messages::WebPage::ShouldDelayWindowOrderingEvent::Reply(result), m_pageID, messageTimeout);
370     return result;
371 }
372
373 bool WebPageProxy::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event)
374 {
375     if (!isValid())
376         return false;
377
378     bool result = false;
379     const double messageTimeout = 3;
380     process()->sendSync(Messages::WebPage::AcceptsFirstMouse(eventNumber, event), Messages::WebPage::AcceptsFirstMouse::Reply(result), m_pageID, messageTimeout);
381     return result;
382 }
383
384 WKView* WebPageProxy::wkView() const
385 {
386     return m_pageClient->wkView();
387 }
388
389 } // namespace WebKit