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 45 using namespace WebCore; 46 47 namespace 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 57 static 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. 65 static 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 80 static 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 94 String 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 104 void WebPageProxy::getIsSpeaking(bool& isSpeaking) 105 { 106 isSpeaking = [NSApp isSpeaking]; 107 } 108 109 void WebPageProxy::speak(const String& string) 110 { 111 [NSApp speakString:nsStringFromWebCoreString(string)]; 112 } 113 114 void WebPageProxy::stopSpeaking() 115 { 116 [NSApp stopSpeaking:nil]; 117 } 118 119 void WebPageProxy::searchWithSpotlight(const String& string) 120 { 121 [[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:nsStringFromWebCoreString(string)]; 122 } 123 124 CGContextRef WebPageProxy::containingWindowGraphicsContext() 125 { 126 return m_pageClient->containingWindowGraphicsContext(); 127 } 128 129 void WebPageProxy::updateWindowIsVisible(bool windowIsVisible) 130 { 131 if (!isValid()) 132 return; 133 process()->send(Messages::WebPage::SetWindowIsVisible(windowIsVisible), m_pageID); 134 } 135 136 void 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 144 void 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 149 void WebPageProxy::confirmComposition() 150 { 151 process()->sendSync(Messages::WebPage::ConfirmComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID); 152 } 153 154 bool 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 161 void 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 166 void 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 171 void 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 176 uint64_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 183 WebCore::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 190 bool 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 197 bool 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 205 bool 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 213 void 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 222 void WebPageProxy::performDictionaryLookupAtLocation(const WebCore::FloatPoint& point) 223 { 224 if (!isValid()) 225 return; 226 227 process()->send(Messages::WebPage::PerformDictionaryLookupAtLocation(point), m_pageID); 228 } 229 230 void 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. 237 void 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 245 void WebPageProxy::uppercaseWord() 246 { 247 process()->send(Messages::WebPage::UppercaseWord(), m_pageID); 248 } 249 250 void WebPageProxy::lowercaseWord() 251 { 252 process()->send(Messages::WebPage::LowercaseWord(), m_pageID); 253 } 254 255 void WebPageProxy::capitalizeWord() 256 { 257 process()->send(Messages::WebPage::CapitalizeWord(), m_pageID); 258 } 259 260 void 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 270 void WebPageProxy::didPerformDictionaryLookup(const String& text, const DictionaryPopupInfo& dictionaryPopupInfo) 271 { 272 m_pageClient->didPerformDictionaryLookup(text, m_viewScaleFactor, dictionaryPopupInfo); 273 } 274 275 void WebPageProxy::registerWebProcessAccessibilityToken(const CoreIPC::DataReference& data) 276 { 277 m_pageClient->accessibilityWebProcessTokenReceived(data); 278 } 279 280 void 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 288 void WebPageProxy::setComplexTextInputEnabled(uint64_t pluginComplexTextInputIdentifier, bool complexTextInputEnabled) 289 { 290 m_pageClient->setComplexTextInputEnabled(pluginComplexTextInputIdentifier, complexTextInputEnabled); 291 } 292 293 void WebPageProxy::executeSavedCommandBySelector(const String& selector, bool& handled) 294 { 295 handled = m_pageClient->executeSavedCommandBySelector(selector); 296 } 297 298 bool 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 306 bool 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