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