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