diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/mac')
21 files changed, 3539 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/mac/BackingStoreMac.mm b/Source/WebKit2/UIProcess/mac/BackingStoreMac.mm new file mode 100644 index 000000000..646962f7e --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/BackingStoreMac.mm @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "BackingStore.h" + +#import "CGUtilities.h" +#import "ShareableBitmap.h" +#import "UpdateInfo.h" +#import "WebPageProxy.h" +#import <WebCore/GraphicsContext.h> + +using namespace WebCore; + +namespace WebKit { + +void BackingStore::paint(PlatformGraphicsContext context, const IntRect& rect) +{ + if (m_cgLayer) { + CGContextSaveGState(context); + CGContextClipToRect(context, rect); + + CGContextScaleCTM(context, 1, -1); + CGContextDrawLayerAtPoint(context, CGPointMake(0, -m_size.height()), m_cgLayer.get()); + + CGContextRestoreGState(context); + return; + } + + ASSERT(m_bitmapContext); + paintBitmapContext(context, m_bitmapContext.get(), rect.location(), rect); +} + +CGContextRef BackingStore::backingStoreContext() +{ + if (m_cgLayer) + return CGLayerGetContext(m_cgLayer.get()); + + // Try to create a layer. + if (CGContextRef containingWindowContext = m_webPageProxy->containingWindowGraphicsContext()) { + m_cgLayer.adoptCF(CGLayerCreateWithContext(containingWindowContext, NSSizeToCGSize(m_size), 0)); + CGContextRef layerContext = CGLayerGetContext(m_cgLayer.get()); + + CGContextSetBlendMode(layerContext, kCGBlendModeCopy); + + // We want the origin to be in the top left corner so flip the backing store context. + CGContextTranslateCTM(layerContext, 0, m_size.height()); + CGContextScaleCTM(layerContext, 1, -1); + + if (m_bitmapContext) { + // Paint the contents of the bitmap into the layer context. + paintBitmapContext(layerContext, m_bitmapContext.get(), CGPointZero, CGRectMake(0, 0, m_size.width(), m_size.height())); + m_bitmapContext = nullptr; + } + + return layerContext; + } + + if (!m_bitmapContext) { + RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); + + m_bitmapContext.adoptCF(CGBitmapContextCreate(0, m_size.width(), m_size.height(), 8, m_size.width() * 4, colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + + CGContextSetBlendMode(m_bitmapContext.get(), kCGBlendModeCopy); + + // We want the origin to be in the top left corner so flip the backing store context. + CGContextTranslateCTM(m_bitmapContext.get(), 0, m_size.height()); + CGContextScaleCTM(m_bitmapContext.get(), 1, -1); + } + + return m_bitmapContext.get(); +} + +void BackingStore::incorporateUpdate(ShareableBitmap* bitmap, const UpdateInfo& updateInfo) +{ + CGContextRef context = backingStoreContext(); + + scroll(updateInfo.scrollRect, updateInfo.scrollOffset); + + IntPoint updateRectLocation = updateInfo.updateRectBounds.location(); + + GraphicsContext graphicsContext(context); + + // Paint all update rects. + for (size_t i = 0; i < updateInfo.updateRects.size(); ++i) { + IntRect updateRect = updateInfo.updateRects[i]; + IntRect srcRect = updateRect; + srcRect.move(-updateRectLocation.x(), -updateRectLocation.y()); + + bitmap->paint(graphicsContext, updateInfo.deviceScaleFactor, updateRect.location(), srcRect); + } +} + +void BackingStore::scroll(const IntRect& scrollRect, const IntSize& scrollOffset) +{ + if (scrollOffset.isZero()) + return; + + if (m_cgLayer) { + CGContextRef layerContext = CGLayerGetContext(m_cgLayer.get()); + + // Scroll the layer by painting it into itself with the given offset. + CGContextSaveGState(layerContext); + CGContextClipToRect(layerContext, scrollRect); + CGContextScaleCTM(layerContext, 1, -1); + CGContextDrawLayerAtPoint(layerContext, CGPointMake(scrollOffset.width(), -m_size.height() - scrollOffset.height()), m_cgLayer.get()); + CGContextRestoreGState(layerContext); + + return; + } + + ASSERT(m_bitmapContext); + + CGContextSaveGState(m_bitmapContext.get()); + CGContextClipToRect(m_bitmapContext.get(), scrollRect); + CGPoint destination = CGPointMake(scrollRect.x() + scrollOffset.width(), scrollRect.y() + scrollOffset.height()); + paintBitmapContext(m_bitmapContext.get(), m_bitmapContext.get(), destination, scrollRect); + CGContextRestoreGState(m_bitmapContext.get()); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/CorrectionPanel.h b/Source/WebKit2/UIProcess/mac/CorrectionPanel.h new file mode 100644 index 000000000..66793a974 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/CorrectionPanel.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CorrectionPanel_h +#define CorrectionPanel_h + +#if !defined(BUILDING_ON_SNOW_LEOPARD) +#import <AppKit/NSSpellChecker.h> +#import <WebCore/SpellingCorrectionController.h> +#import <wtf/RetainPtr.h> + +@class WKView; + +namespace WebKit { + +class CorrectionPanel { +public: + CorrectionPanel(); + ~CorrectionPanel(); + void show(WKView*, WebCore::CorrectionPanelInfo::PanelType, const WebCore::FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings); + String dismiss(WebCore::ReasonForDismissingCorrectionPanel); + static void recordAutocorrectionResponse(WKView*, NSCorrectionResponse, const String& replacedString, const String& replacementString); + +private: + bool isShowing() const { return m_view; } + String dismissInternal(WebCore::ReasonForDismissingCorrectionPanel, bool dismissingExternally); + void handleAcceptedReplacement(NSString* acceptedReplacement, NSString* replaced, NSString* proposedReplacement, NSCorrectionIndicatorType); + + bool m_wasDismissedExternally; + WebCore::ReasonForDismissingCorrectionPanel m_reasonForDismissing; + RetainPtr<WKView> m_view; + RetainPtr<NSString> m_resultForDismissal; +}; + +} // namespace WebKit + +#endif // !defined(BUILDING_ON_SNOW_LEOPARD) + +#endif // CorrectionPanel_h diff --git a/Source/WebKit2/UIProcess/mac/CorrectionPanel.mm b/Source/WebKit2/UIProcess/mac/CorrectionPanel.mm new file mode 100644 index 000000000..86dd16a56 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/CorrectionPanel.mm @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#if !defined(BUILDING_ON_SNOW_LEOPARD) +#import "CorrectionPanel.h" + +#import "WebPageProxy.h" +#import "WKView.h" +#import "WKViewInternal.h" + +using namespace WebCore; + +static inline NSCorrectionIndicatorType correctionIndicatorType(CorrectionPanelInfo::PanelType panelType) +{ + switch (panelType) { + case CorrectionPanelInfo::PanelTypeCorrection: + return NSCorrectionIndicatorTypeDefault; + case CorrectionPanelInfo::PanelTypeReversion: + return NSCorrectionIndicatorTypeReversion; + case CorrectionPanelInfo::PanelTypeSpellingSuggestions: + return NSCorrectionIndicatorTypeGuesses; + } + ASSERT_NOT_REACHED(); + return NSCorrectionIndicatorTypeDefault; +} + +namespace WebKit { + +CorrectionPanel::CorrectionPanel() + : m_wasDismissedExternally(false) + , m_reasonForDismissing(ReasonForDismissingCorrectionPanelIgnored) +{ +} + +CorrectionPanel::~CorrectionPanel() +{ + dismissInternal(ReasonForDismissingCorrectionPanelIgnored, false); +} + +void CorrectionPanel::show(WKView* view, CorrectionPanelInfo::PanelType type, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings) +{ + dismissInternal(ReasonForDismissingCorrectionPanelIgnored, false); + + if (!view) + return; + + NSString* replacedStringAsNSString = replacedString; + NSString* replacementStringAsNSString = replacementString; + m_view = view; + NSCorrectionIndicatorType indicatorType = correctionIndicatorType(type); + + NSMutableArray* alternativeStrings = 0; + if (!alternativeReplacementStrings.isEmpty()) { + size_t size = alternativeReplacementStrings.size(); + alternativeStrings = [NSMutableArray arrayWithCapacity:size]; + for (size_t i = 0; i < size; ++i) + [alternativeStrings addObject:(NSString*)alternativeReplacementStrings[i]]; + } + + NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker]; + [spellChecker showCorrectionIndicatorOfType:indicatorType primaryString:replacementStringAsNSString alternativeStrings:alternativeStrings forStringInRect:boundingBoxOfReplacedString view:m_view.get() completionHandler:^(NSString* acceptedString) { + handleAcceptedReplacement(acceptedString, replacedStringAsNSString, replacementStringAsNSString, indicatorType); + }]; +} + +String CorrectionPanel::dismiss(ReasonForDismissingCorrectionPanel reason) +{ + return dismissInternal(reason, true); +} + +String CorrectionPanel::dismissInternal(ReasonForDismissingCorrectionPanel reason, bool dismissingExternally) +{ + if (!isShowing()) + return String(); + + m_wasDismissedExternally = dismissingExternally; + m_reasonForDismissing = reason; + m_resultForDismissal.clear(); + [[NSSpellChecker sharedSpellChecker] dismissCorrectionIndicatorForView:m_view.get()]; + return m_resultForDismissal.get(); +} + +void CorrectionPanel::recordAutocorrectionResponse(WKView* view, NSCorrectionResponse response, const String& replacedString, const String& replacementString) +{ + [[NSSpellChecker sharedSpellChecker] recordResponse:response toCorrection:replacementString forWord:replacedString language:nil inSpellDocumentWithTag:[view spellCheckerDocumentTag]]; +} + +void CorrectionPanel::handleAcceptedReplacement(NSString* acceptedReplacement, NSString* replaced, NSString* proposedReplacement, NSCorrectionIndicatorType correctionIndicatorType) +{ + if (!m_view) + return; + + NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker]; + NSInteger documentTag = [m_view.get() spellCheckerDocumentTag]; + + switch (correctionIndicatorType) { + case NSCorrectionIndicatorTypeDefault: + if (acceptedReplacement) + [spellChecker recordResponse:NSCorrectionResponseAccepted toCorrection:acceptedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag]; + else { + if (!m_wasDismissedExternally || m_reasonForDismissing == ReasonForDismissingCorrectionPanelCancelled) + [spellChecker recordResponse:NSCorrectionResponseRejected toCorrection:proposedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag]; + else + [spellChecker recordResponse:NSCorrectionResponseIgnored toCorrection:proposedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag]; + } + break; + case NSCorrectionIndicatorTypeReversion: + if (acceptedReplacement) + [spellChecker recordResponse:NSCorrectionResponseReverted toCorrection:replaced forWord:acceptedReplacement language:nil inSpellDocumentWithTag:documentTag]; + break; + case NSCorrectionIndicatorTypeGuesses: + if (acceptedReplacement) + [spellChecker recordResponse:NSCorrectionResponseAccepted toCorrection:acceptedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag]; + break; + } + + [m_view.get() handleCorrectionPanelResult:acceptedReplacement]; + m_view.clear(); + if (acceptedReplacement) + m_resultForDismissal.adoptNS([acceptedReplacement copy]); +} + +} // namespace WebKit + +#endif //!defined(BUILDING_ON_SNOW_LEOPARD) + diff --git a/Source/WebKit2/UIProcess/mac/TextCheckerMac.mm b/Source/WebKit2/UIProcess/mac/TextCheckerMac.mm new file mode 100644 index 000000000..20a63ea03 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/TextCheckerMac.mm @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "TextChecker.h" + +#import "TextCheckerState.h" +#import <WebCore/NotImplemented.h> +#import <wtf/RetainPtr.h> + +#ifndef BUILDING_ON_SNOW_LEOPARD +@interface NSSpellChecker (WebNSSpellCheckerDetails) +- (NSString *)languageForWordRange:(NSRange)range inString:(NSString *)string orthography:(NSOrthography *)orthography; +@end +#endif + +static NSString* const WebAutomaticSpellingCorrectionEnabled = @"WebAutomaticSpellingCorrectionEnabled"; +static NSString* const WebContinuousSpellCheckingEnabled = @"WebContinuousSpellCheckingEnabled"; +static NSString* const WebGrammarCheckingEnabled = @"WebGrammarCheckingEnabled"; +static NSString* const WebSmartInsertDeleteEnabled = @"WebSmartInsertDeleteEnabled"; +static NSString* const WebAutomaticQuoteSubstitutionEnabled = @"WebAutomaticQuoteSubstitutionEnabled"; +static NSString* const WebAutomaticDashSubstitutionEnabled = @"WebAutomaticDashSubstitutionEnabled"; +static NSString* const WebAutomaticLinkDetectionEnabled = @"WebAutomaticLinkDetectionEnabled"; +static NSString* const WebAutomaticTextReplacementEnabled = @"WebAutomaticTextReplacementEnabled"; + +using namespace WebCore; + +namespace WebKit { + +TextCheckerState textCheckerState; + +static void initializeState() +{ + static bool didInitializeState; + if (didInitializeState) + return; + + textCheckerState.isContinuousSpellCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebContinuousSpellCheckingEnabled] && TextChecker::isContinuousSpellCheckingAllowed(); + textCheckerState.isGrammarCheckingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebGrammarCheckingEnabled]; + textCheckerState.isAutomaticSpellingCorrectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticSpellingCorrectionEnabled]; + textCheckerState.isAutomaticQuoteSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticQuoteSubstitutionEnabled]; + textCheckerState.isAutomaticDashSubstitutionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticDashSubstitutionEnabled]; + textCheckerState.isAutomaticLinkDetectionEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticLinkDetectionEnabled]; + textCheckerState.isAutomaticTextReplacementEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:WebAutomaticTextReplacementEnabled]; + +#if !defined(BUILDING_ON_SNOW_LEOPARD) + if (![[NSUserDefaults standardUserDefaults] objectForKey:WebAutomaticSpellingCorrectionEnabled]) + textCheckerState.isAutomaticSpellingCorrectionEnabled = [NSSpellChecker isAutomaticSpellingCorrectionEnabled]; +#endif + + didInitializeState = true; +} + +const TextCheckerState& TextChecker::state() +{ + initializeState(); + return textCheckerState; +} + +bool TextChecker::isContinuousSpellCheckingAllowed() +{ + static bool allowContinuousSpellChecking = true; + static bool readAllowContinuousSpellCheckingDefault = false; + + if (!readAllowContinuousSpellCheckingDefault) { + if ([[NSUserDefaults standardUserDefaults] objectForKey:@"NSAllowContinuousSpellChecking"]) + allowContinuousSpellChecking = [[NSUserDefaults standardUserDefaults] boolForKey:@"NSAllowContinuousSpellChecking"]; + + readAllowContinuousSpellCheckingDefault = true; + } + + return allowContinuousSpellChecking; +} + +void TextChecker::setContinuousSpellCheckingEnabled(bool isContinuousSpellCheckingEnabled) +{ + if (state().isContinuousSpellCheckingEnabled == isContinuousSpellCheckingEnabled) + return; + + textCheckerState.isContinuousSpellCheckingEnabled = isContinuousSpellCheckingEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isContinuousSpellCheckingEnabled forKey:WebContinuousSpellCheckingEnabled]; + + // FIXME: preflight the spell checker. +} + +void TextChecker::setGrammarCheckingEnabled(bool isGrammarCheckingEnabled) +{ + if (state().isGrammarCheckingEnabled == isGrammarCheckingEnabled) + return; + + textCheckerState.isGrammarCheckingEnabled = isGrammarCheckingEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isGrammarCheckingEnabled forKey:WebGrammarCheckingEnabled]; + [[NSSpellChecker sharedSpellChecker] updatePanels]; + + // We call preflightSpellChecker() when turning continuous spell checking on, but we don't need to do that here + // because grammar checking only occurs on code paths that already preflight spell checking appropriately. +} + +void TextChecker::setAutomaticSpellingCorrectionEnabled(bool isAutomaticSpellingCorrectionEnabled) +{ + if (state().isAutomaticSpellingCorrectionEnabled == isAutomaticSpellingCorrectionEnabled) + return; + + textCheckerState.isAutomaticSpellingCorrectionEnabled = isAutomaticSpellingCorrectionEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isAutomaticSpellingCorrectionEnabled forKey:WebAutomaticSpellingCorrectionEnabled]; + + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +void TextChecker::setAutomaticQuoteSubstitutionEnabled(bool isAutomaticQuoteSubstitutionEnabled) +{ + if (state().isAutomaticQuoteSubstitutionEnabled == isAutomaticQuoteSubstitutionEnabled) + return; + + textCheckerState.isAutomaticQuoteSubstitutionEnabled = isAutomaticQuoteSubstitutionEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isAutomaticQuoteSubstitutionEnabled forKey:WebAutomaticQuoteSubstitutionEnabled]; + + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +void TextChecker::setAutomaticDashSubstitutionEnabled(bool isAutomaticDashSubstitutionEnabled) +{ + if (state().isAutomaticDashSubstitutionEnabled == isAutomaticDashSubstitutionEnabled) + return; + + textCheckerState.isAutomaticDashSubstitutionEnabled = isAutomaticDashSubstitutionEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isAutomaticDashSubstitutionEnabled forKey:WebAutomaticDashSubstitutionEnabled]; + + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +void TextChecker::setAutomaticLinkDetectionEnabled(bool isAutomaticLinkDetectionEnabled) +{ + if (state().isAutomaticLinkDetectionEnabled == isAutomaticLinkDetectionEnabled) + return; + + textCheckerState.isAutomaticLinkDetectionEnabled = isAutomaticLinkDetectionEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isAutomaticLinkDetectionEnabled forKey:WebAutomaticLinkDetectionEnabled]; + + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +void TextChecker::setAutomaticTextReplacementEnabled(bool isAutomaticTextReplacementEnabled) +{ + if (state().isAutomaticTextReplacementEnabled == isAutomaticTextReplacementEnabled) + return; + + textCheckerState.isAutomaticTextReplacementEnabled = isAutomaticTextReplacementEnabled; + [[NSUserDefaults standardUserDefaults] setBool:isAutomaticTextReplacementEnabled forKey:WebAutomaticTextReplacementEnabled]; + + [[NSSpellChecker sharedSpellChecker] updatePanels]; +} + +static bool smartInsertDeleteEnabled; + +bool TextChecker::isSmartInsertDeleteEnabled() +{ + static bool readSmartInsertDeleteEnabledDefault; + + if (!readSmartInsertDeleteEnabledDefault) { + smartInsertDeleteEnabled = ![[NSUserDefaults standardUserDefaults] objectForKey:WebSmartInsertDeleteEnabled] || [[NSUserDefaults standardUserDefaults] boolForKey:WebSmartInsertDeleteEnabled]; + + readSmartInsertDeleteEnabledDefault = true; + } + + return smartInsertDeleteEnabled; +} + +void TextChecker::setSmartInsertDeleteEnabled(bool flag) +{ + if (flag == isSmartInsertDeleteEnabled()) + return; + + smartInsertDeleteEnabled = flag; + + [[NSUserDefaults standardUserDefaults] setBool:flag forKey:WebSmartInsertDeleteEnabled]; +} + +bool TextChecker::substitutionsPanelIsShowing() +{ + return [[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible]; +} + +void TextChecker::toggleSubstitutionsPanelIsShowing() +{ + NSPanel *substitutionsPanel = [[NSSpellChecker sharedSpellChecker] substitutionsPanel]; + if ([substitutionsPanel isVisible]) { + [substitutionsPanel orderOut:nil]; + return; + } + [substitutionsPanel orderFront:nil]; +} + +void TextChecker::continuousSpellCheckingEnabledStateChanged(bool enabled) +{ + textCheckerState.isContinuousSpellCheckingEnabled = enabled; +} + +void TextChecker::grammarCheckingEnabledStateChanged(bool enabled) +{ + textCheckerState.isGrammarCheckingEnabled = enabled; +} + +int64_t TextChecker::uniqueSpellDocumentTag(WebPageProxy*) +{ + return [NSSpellChecker uniqueSpellDocumentTag]; +} + +void TextChecker::closeSpellDocumentWithTag(int64_t tag) +{ + [[NSSpellChecker sharedSpellChecker] closeSpellDocumentWithTag:tag]; +} + +#if USE(UNIFIED_TEXT_CHECKING) + +Vector<TextCheckingResult> TextChecker::checkTextOfParagraph(int64_t spellDocumentTag, const UChar* text, int length, uint64_t checkingTypes) +{ + Vector<TextCheckingResult> results; + + RetainPtr<NSString> textString(AdoptNS, [[NSString alloc] initWithCharactersNoCopy:const_cast<UChar*>(text) length:length freeWhenDone:NO]); + NSArray *incomingResults = [[NSSpellChecker sharedSpellChecker] checkString:textString .get() + range:NSMakeRange(0, length) + types:checkingTypes | NSTextCheckingTypeOrthography + options:nil + inSpellDocumentWithTag:spellDocumentTag + orthography:NULL + wordCount:NULL]; + for (NSTextCheckingResult *incomingResult in incomingResults) { + NSRange resultRange = [incomingResult range]; + NSTextCheckingType resultType = [incomingResult resultType]; + ASSERT(resultRange.location != NSNotFound); + ASSERT(resultRange.length > 0); + if (resultType == NSTextCheckingTypeSpelling && (checkingTypes & NSTextCheckingTypeSpelling)) { + TextCheckingResult result; + result.type = TextCheckingTypeSpelling; + result.location = resultRange.location; + result.length = resultRange.length; + results.append(result); + } else if (resultType == NSTextCheckingTypeGrammar && (checkingTypes & NSTextCheckingTypeGrammar)) { + TextCheckingResult result; + NSArray *details = [incomingResult grammarDetails]; + result.type = TextCheckingTypeGrammar; + result.location = resultRange.location; + result.length = resultRange.length; + for (NSDictionary *incomingDetail in details) { + ASSERT(incomingDetail); + GrammarDetail detail; + NSValue *detailRangeAsNSValue = [incomingDetail objectForKey:NSGrammarRange]; + ASSERT(detailRangeAsNSValue); + NSRange detailNSRange = [detailRangeAsNSValue rangeValue]; + ASSERT(detailNSRange.location != NSNotFound); + ASSERT(detailNSRange.length > 0); + detail.location = detailNSRange.location; + detail.length = detailNSRange.length; + detail.userDescription = [incomingDetail objectForKey:NSGrammarUserDescription]; + NSArray *guesses = [incomingDetail objectForKey:NSGrammarCorrections]; + for (NSString *guess in guesses) + detail.guesses.append(String(guess)); + result.details.append(detail); + } + results.append(result); + } else if (resultType == NSTextCheckingTypeLink && (checkingTypes & NSTextCheckingTypeLink)) { + TextCheckingResult result; + result.type = TextCheckingTypeLink; + result.location = resultRange.location; + result.length = resultRange.length; + result.replacement = [[incomingResult URL] absoluteString]; + results.append(result); + } else if (resultType == NSTextCheckingTypeQuote && (checkingTypes & NSTextCheckingTypeQuote)) { + TextCheckingResult result; + result.type = TextCheckingTypeQuote; + result.location = resultRange.location; + result.length = resultRange.length; + result.replacement = [incomingResult replacementString]; + results.append(result); + } else if (resultType == NSTextCheckingTypeDash && (checkingTypes & NSTextCheckingTypeDash)) { + TextCheckingResult result; + result.type = TextCheckingTypeDash; + result.location = resultRange.location; + result.length = resultRange.length; + result.replacement = [incomingResult replacementString]; + results.append(result); + } else if (resultType == NSTextCheckingTypeReplacement && (checkingTypes & NSTextCheckingTypeReplacement)) { + TextCheckingResult result; + result.type = TextCheckingTypeReplacement; + result.location = resultRange.location; + result.length = resultRange.length; + result.replacement = [incomingResult replacementString]; + results.append(result); + } else if (resultType == NSTextCheckingTypeCorrection && (checkingTypes & NSTextCheckingTypeCorrection)) { + TextCheckingResult result; + result.type = TextCheckingTypeCorrection; + result.location = resultRange.location; + result.length = resultRange.length; + result.replacement = [incomingResult replacementString]; + results.append(result); + } + } + + return results; +} + +#endif + +void TextChecker::checkSpellingOfString(int64_t, const UChar*, uint32_t, int32_t&, int32_t&) +{ + // Mac uses checkTextOfParagraph instead. + notImplemented(); +} + +void TextChecker::checkGrammarOfString(int64_t, const UChar*, uint32_t, Vector<WebCore::GrammarDetail>&, int32_t&, int32_t&) +{ + // Mac uses checkTextOfParagraph instead. + notImplemented(); +} + +bool TextChecker::spellingUIIsShowing() +{ + return [[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible]; +} + +void TextChecker::toggleSpellingUIIsShowing() +{ + NSPanel *spellingPanel = [[NSSpellChecker sharedSpellChecker] spellingPanel]; + if ([spellingPanel isVisible]) + [spellingPanel orderOut:nil]; + else + [spellingPanel orderFront:nil]; +} + +void TextChecker::updateSpellingUIWithMisspelledWord(int64_t, const String& misspelledWord) +{ + [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithMisspelledWord:misspelledWord]; +} + +void TextChecker::updateSpellingUIWithGrammarString(int64_t, const String& badGrammarPhrase, const GrammarDetail& grammarDetail) +{ + RetainPtr<NSMutableArray> corrections(AdoptNS, [[NSMutableArray alloc] init]); + for (size_t i = 0; i < grammarDetail.guesses.size(); ++i) { + NSString *guess = grammarDetail.guesses[i]; + [corrections.get() addObject:guess]; + } + + NSRange grammarRange = NSMakeRange(grammarDetail.location, grammarDetail.length); + NSString *grammarUserDescription = grammarDetail.userDescription; + RetainPtr<NSDictionary> grammarDetailDict(AdoptNS, [[NSDictionary alloc] initWithObjectsAndKeys:[NSValue valueWithRange:grammarRange], NSGrammarRange, grammarUserDescription, NSGrammarUserDescription, corrections.get(), NSGrammarCorrections, nil]); + + [[NSSpellChecker sharedSpellChecker] updateSpellingPanelWithGrammarString:badGrammarPhrase detail:grammarDetailDict.get()]; +} + +void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word, const String& context, Vector<String>& guesses) +{ +#if !defined(BUILDING_ON_SNOW_LEOPARD) + NSString* language = nil; + NSOrthography* orthography = nil; + NSSpellChecker *checker = [NSSpellChecker sharedSpellChecker]; + if (context.length()) { + [checker checkString:context range:NSMakeRange(0, context.length()) types:NSTextCheckingTypeOrthography options:0 inSpellDocumentWithTag:spellDocumentTag orthography:&orthography wordCount:0]; + language = [checker languageForWordRange:NSMakeRange(0, context.length()) inString:context orthography:orthography]; + } + NSArray* stringsArray = [checker guessesForWordRange:NSMakeRange(0, word.length()) inString:word language:language inSpellDocumentWithTag:spellDocumentTag]; +#else + NSArray* stringsArray = [[NSSpellChecker sharedSpellChecker] guessesForWord:word]; +#endif + + for (NSString *guess in stringsArray) + guesses.append(guess); +} + +void TextChecker::learnWord(int64_t, const String& word) +{ + [[NSSpellChecker sharedSpellChecker] learnWord:word]; +} + +void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word) +{ + [[NSSpellChecker sharedSpellChecker] ignoreWord:word inSpellDocumentWithTag:spellDocumentTag]; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.h b/Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.h new file mode 100644 index 000000000..75b95c408 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TiledCoreAnimationDrawingAreaProxy_h +#define TiledCoreAnimationDrawingAreaProxy_h + +#include "DrawingAreaProxy.h" +#include <wtf/PassOwnPtr.h> + +namespace WebKit { + +class TiledCoreAnimationDrawingAreaProxy : public DrawingAreaProxy { +public: + static PassOwnPtr<TiledCoreAnimationDrawingAreaProxy> create(WebPageProxy*); + virtual ~TiledCoreAnimationDrawingAreaProxy(); + +private: + explicit TiledCoreAnimationDrawingAreaProxy(WebPageProxy*); + + // DrawingAreaProxy + virtual void deviceScaleFactorDidChange() OVERRIDE; + virtual void sizeDidChange() OVERRIDE; + virtual void enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) OVERRIDE; + virtual void exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo&) OVERRIDE; + + // Message handlers. + virtual void didUpdateGeometry() OVERRIDE; + + void sendUpdateGeometry(); + + // Whether we're waiting for a DidUpdateGeometry message from the web process. + bool m_isWaitingForDidUpdateGeometry; + + // The last size we sent to the web process. + WebCore::IntSize m_lastSentSize; +}; + +} // namespace WebKit + +#endif // TiledCoreAnimationDrawingAreaProxy_h diff --git a/Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.mm b/Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.mm new file mode 100644 index 000000000..25d4e44a1 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/TiledCoreAnimationDrawingAreaProxy.mm @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "TiledCoreAnimationDrawingAreaProxy.h" + +#import "DrawingAreaMessages.h" +#import "DrawingAreaProxyMessages.h" +#import "LayerTreeContext.h" +#import "WebPageProxy.h" +#import "WebProcessProxy.h" + +using namespace WebCore; + +namespace WebKit { + +PassOwnPtr<TiledCoreAnimationDrawingAreaProxy> TiledCoreAnimationDrawingAreaProxy::create(WebPageProxy* webPageProxy) +{ + return adoptPtr(new TiledCoreAnimationDrawingAreaProxy(webPageProxy)); +} + +TiledCoreAnimationDrawingAreaProxy::TiledCoreAnimationDrawingAreaProxy(WebPageProxy* webPageProxy) + : DrawingAreaProxy(DrawingAreaTypeTiledCoreAnimation, webPageProxy) + , m_isWaitingForDidUpdateGeometry(false) +{ +} + +TiledCoreAnimationDrawingAreaProxy::~TiledCoreAnimationDrawingAreaProxy() +{ +} + +void TiledCoreAnimationDrawingAreaProxy::deviceScaleFactorDidChange() +{ + // FIXME: Implement. +} + +void TiledCoreAnimationDrawingAreaProxy::sizeDidChange() +{ + if (!m_webPageProxy->isValid()) + return; + + // We only want one UpdateGeometry message in flight at once, so if we've already sent one but + // haven't yet received the reply we'll just return early here. + if (m_isWaitingForDidUpdateGeometry) + return; + + sendUpdateGeometry(); + + if (m_webPageProxy->process()->isLaunching()) + return; + + // The timeout, in seconds, we use when waiting for a DidUpdateGeometry message. + static const double didUpdateBackingStoreStateTimeout = 0.5; + m_webPageProxy->process()->connection()->waitForAndDispatchImmediately<Messages::DrawingAreaProxy::DidUpdateGeometry>(m_webPageProxy->pageID(), didUpdateBackingStoreStateTimeout); +} + +void TiledCoreAnimationDrawingAreaProxy::enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext& layerTreeContext) +{ + m_webPageProxy->enterAcceleratedCompositingMode(layerTreeContext); +} + +void TiledCoreAnimationDrawingAreaProxy::exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo&) +{ + // This should never be called. + ASSERT_NOT_REACHED(); +} + +void TiledCoreAnimationDrawingAreaProxy::didUpdateGeometry() +{ + ASSERT(m_isWaitingForDidUpdateGeometry); + + m_isWaitingForDidUpdateGeometry = false; + + // If the WKView was resized while we were waiting for a DidUpdateGeometry reply from the web process, + // we need to resend the new size here. + if (m_lastSentSize != m_size) + sendUpdateGeometry(); +} + +void TiledCoreAnimationDrawingAreaProxy::sendUpdateGeometry() +{ + ASSERT(!m_isWaitingForDidUpdateGeometry); + + m_lastSentSize = m_size; + m_webPageProxy->process()->send(Messages::DrawingArea::UpdateGeometry(m_size), m_webPageProxy->pageID()); + m_isWaitingForDidUpdateGeometry = true; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/WKFullKeyboardAccessWatcher.h b/Source/WebKit2/UIProcess/mac/WKFullKeyboardAccessWatcher.h new file mode 100644 index 000000000..8b9e81dbc --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WKFullKeyboardAccessWatcher.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WKFullKeyboardAccessWatcher_h +#define WKFullKeyboardAccessWatcher_h + +#import <Cocoa/Cocoa.h> + +@interface WKFullKeyboardAccessWatcher : NSObject { +@private + BOOL fullKeyboardAccessEnabled; +} + ++ (BOOL)fullKeyboardAccessEnabled; + +@end; + +#endif // WKFullKeyboardAccessWatcher_h diff --git a/Source/WebKit2/UIProcess/mac/WKFullKeyboardAccessWatcher.mm b/Source/WebKit2/UIProcess/mac/WKFullKeyboardAccessWatcher.mm new file mode 100644 index 000000000..0908a46cb --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WKFullKeyboardAccessWatcher.mm @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WKFullKeyboardAccessWatcher.h" + +#import "WebContext.h" + +NSString * const KeyboardUIModeDidChangeNotification = @"com.apple.KeyboardUIModeDidChange"; +const CFStringRef AppleKeyboardUIMode = CFSTR("AppleKeyboardUIMode"); +const CFStringRef UniversalAccessDomain = CFSTR("com.apple.universalaccess"); + +using namespace WebKit; + +@implementation WKFullKeyboardAccessWatcher + +- (void)notifyAllWebContexts +{ + const Vector<WebContext*>& contexts = WebContext::allContexts(); + for (size_t i = 0; i < contexts.size(); ++i) + contexts[i]->fullKeyboardAccessModeChanged(fullKeyboardAccessEnabled); +} + +- (void)retrieveKeyboardUIModeFromPreferences:(NSNotification *)notification +{ + BOOL oldValue = fullKeyboardAccessEnabled; + + CFPreferencesAppSynchronize(UniversalAccessDomain); + + Boolean keyExistsAndHasValidFormat; + int mode = CFPreferencesGetAppIntegerValue(AppleKeyboardUIMode, UniversalAccessDomain, &keyExistsAndHasValidFormat); + if (keyExistsAndHasValidFormat) { + // The keyboard access mode is reported by two bits: + // Bit 0 is set if feature is on + // Bit 1 is set if full keyboard access works for any control, not just text boxes and lists. + fullKeyboardAccessEnabled = (mode & 0x2); + } + + if (fullKeyboardAccessEnabled != oldValue) + [self notifyAllWebContexts]; +} + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + + [self retrieveKeyboardUIModeFromPreferences:nil]; + + [[NSDistributedNotificationCenter defaultCenter] + addObserver:self selector:@selector(retrieveKeyboardUIModeFromPreferences:) + name:KeyboardUIModeDidChangeNotification object:nil]; + + return self; +} + ++ (BOOL)fullKeyboardAccessEnabled +{ + static WKFullKeyboardAccessWatcher *watcher = [[WKFullKeyboardAccessWatcher alloc] init]; + return watcher->fullKeyboardAccessEnabled; +} + +@end diff --git a/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.h b/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.h new file mode 100644 index 000000000..74e794704 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if ENABLE(FULLSCREEN_API) + +#import <wtf/OwnPtr.h> +#import <wtf/RetainPtr.h> + +namespace WebKit { +class LayerTreeContext; +} + +namespace WebCore { +class DisplaySleepDisabler; +class IntRect; +} + +@class WKView; + +@interface WKFullScreenWindowController : NSWindowController { +@private + WKView *_webView; + RetainPtr<NSView> _webViewPlaceholder; + RetainPtr<NSView> _layerHostingView; + + BOOL _isEnteringFullScreen; + BOOL _isExitingFullScreen; + BOOL _isFullScreen; + BOOL _forceDisableAnimation; + BOOL _isPlaying; + OwnPtr<WebCore::DisplaySleepDisabler> _displaySleepDisabler; +} + +- (WKView*)webView; +- (void)setWebView:(WKView*)webView; + +- (void)enterFullScreen:(NSScreen *)screen; +- (void)exitFullScreen; +- (void)beganEnterFullScreenAnimation; +- (void)beganExitFullScreenAnimation; +- (void)finishedEnterFullScreenAnimation:(bool)completed; +- (void)finishedExitFullScreenAnimation:(bool)completed; +- (void)enterAcceleratedCompositingMode:(const WebKit::LayerTreeContext&)context; +- (void)exitAcceleratedCompositingMode; +- (WebCore::IntRect)getFullScreenRect; +- (void)close; + +@end + +#endif diff --git a/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.mm b/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.mm new file mode 100644 index 000000000..204439fa9 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WKFullScreenWindowController.mm @@ -0,0 +1,644 @@ +/* + * Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" + +#if ENABLE(FULLSCREEN_API) + +#import "WKFullScreenWindowController.h" + +#import "LayerTreeContext.h" +#import "WKAPICast.h" +#import "WKViewInternal.h" +#import "WKViewPrivate.h" +#import "WebFullScreenManagerProxy.h" +#import "WebPageProxy.h" +#import <Carbon/Carbon.h> // For SetSystemUIMode() +#import <QuartzCore/QuartzCore.h> +#import <WebCore/DisplaySleepDisabler.h> +#import <WebCore/FloatRect.h> +#import <WebCore/IntRect.h> +#import <WebKit/WebNSWindowExtras.h> +#import <WebKitSystemInterface.h> +#import <wtf/UnusedParam.h> + +using namespace WebKit; +using namespace WebCore; + +#if defined(BUILDING_ON_LEOPARD) +@interface CATransaction(SnowLeopardConvenienceFunctions) ++ (void)setDisableActions:(BOOL)flag; ++ (void)setAnimationDuration:(CFTimeInterval)dur; +@end + +@implementation CATransaction(SnowLeopardConvenienceFunctions) ++ (void)setDisableActions:(BOOL)flag +{ + [self setValue:[NSNumber numberWithBool:flag] forKey:kCATransactionDisableActions]; +} + ++ (void)setAnimationDuration:(CFTimeInterval)dur +{ + [self setValue:[NSNumber numberWithDouble:dur] forKey:kCATransactionAnimationDuration]; +} +@end + +#endif + +@interface WKFullScreenWindow : NSWindow +{ + NSView* _animationView; + CALayer* _backgroundLayer; +} +- (CALayer*)backgroundLayer; +- (NSView*)animationView; +@end + +static void continueExitCompositingModeAfterRepaintCallback(WKErrorRef error, void* context); + +@interface WKFullScreenWindowController(Private) +- (void)_requestExitFullScreenWithAnimation:(BOOL)animation; +- (void)_updateMenuAndDockForFullScreen; +- (void)_updatePowerAssertions; +- (WKFullScreenWindow *)_fullScreenWindow; +- (CFTimeInterval)_animationDuration; +- (void)_swapView:(NSView*)view with:(NSView*)otherView; +- (WebPageProxy*)_page; +- (WebFullScreenManagerProxy*)_manager; +- (void)_continueExitCompositingModeAfterRepaint; +@end + +@interface NSWindow(IsOnActiveSpaceAdditionForTigerAndLeopard) +- (BOOL)isOnActiveSpace; +@end + +@implementation WKFullScreenWindowController + +#pragma mark - +#pragma mark Initialization +- (id)init +{ + NSWindow *window = [[WKFullScreenWindow alloc] initWithContentRect:NSZeroRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; + self = [super initWithWindow:window]; + [window release]; + if (!self) + return nil; + [self windowDidLoad]; + + return self; +} + +- (void)dealloc +{ + [self setWebView:nil]; + + [NSObject cancelPreviousPerformRequestsWithTarget:self]; + + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)windowDidLoad +{ + [super windowDidLoad]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidResignActive:) name:NSApplicationDidResignActiveNotification object:NSApp]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangeScreenParameters:) name:NSApplicationDidChangeScreenParametersNotification object:NSApp]; +} + +#pragma mark - +#pragma mark Accessors + +- (WKView*)webView +{ + return _webView; +} + +- (void)setWebView:(WKView *)webView +{ + [webView retain]; + [_webView release]; + _webView = webView; +} + +#pragma mark - +#pragma mark Notifications + +- (void)applicationDidResignActive:(NSNotification*)notification +{ + // Check to see if the fullScreenWindow is on the active space; this function is available + // on 10.6 and later, so default to YES if the function is not available: + NSWindow* fullScreenWindow = [self _fullScreenWindow]; + BOOL isOnActiveSpace = ([fullScreenWindow respondsToSelector:@selector(isOnActiveSpace)] ? [fullScreenWindow isOnActiveSpace] : YES); + + // Replicate the QuickTime Player (X) behavior when losing active application status: + // Is the fullScreen screen the main screen? (Note: this covers the case where only a + // single screen is available.) Is the fullScreen screen on the current space? IFF so, + // then exit fullScreen mode. + if ([fullScreenWindow screen] == [[NSScreen screens] objectAtIndex:0] && isOnActiveSpace) + [self _requestExitFullScreenWithAnimation:NO]; +} + +- (void)applicationDidChangeScreenParameters:(NSNotification*)notification +{ + // The user may have changed the main screen by moving the menu bar, or they may have changed + // the Dock's size or location, or they may have changed the fullScreen screen's dimensions. + // Update our presentation parameters, and ensure that the full screen window occupies the + // entire screen: + [self _updateMenuAndDockForFullScreen]; + NSWindow* window = [self window]; + [window setFrame:[[window screen] frame] display:YES]; +} + +#pragma mark - +#pragma mark Exposed Interface + +- (void)enterFullScreen:(NSScreen *)screen +{ + if (_isFullScreen) + return; + + _isFullScreen = YES; + + NSDisableScreenUpdates(); + + if (!screen) + screen = [NSScreen mainScreen]; + NSRect screenFrame = [screen frame]; + +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) + NSRect webViewFrame = [_webView convertRectToBase:[_webView frame]]; + webViewFrame.origin = [[_webView window] convertBaseToScreen:webViewFrame.origin]; +#else + NSRect webViewFrame = [[_webView window] convertRectToScreen: + [_webView convertRect:[_webView frame] toView:nil]]; +#endif + + // In the case of a multi-monitor setup where the webView straddles two + // monitors, we must create a window large enough to contain the destination + // frame and the initial frame. + NSRect windowFrame = NSUnionRect(screenFrame, webViewFrame); + + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + [[self window] setFrame:windowFrame display:YES]; + + CALayer* backgroundLayer = [[self _fullScreenWindow] backgroundLayer]; + NSRect backgroundFrame = {[[self window] convertScreenToBase:screenFrame.origin], screenFrame.size}; + backgroundFrame = [[[self window] contentView] convertRectFromBase:backgroundFrame]; + + [backgroundLayer setFrame:NSRectToCGRect(backgroundFrame)]; + [CATransaction commit]; + + CFTimeInterval duration = [self _animationDuration]; + [self _manager]->willEnterFullScreen(); + [self _manager]->beginEnterFullScreenAnimation(duration); +} + +- (void)beganEnterFullScreenAnimation +{ + if (_isEnteringFullScreen) + return; + _isEnteringFullScreen = YES; + + if (_isExitingFullScreen) + [self finishedExitFullScreenAnimation:NO]; + + [self _updateMenuAndDockForFullScreen]; + [self _updatePowerAssertions]; + + // In a previous incarnation, the NSWindow attached to this controller may have + // been on a different screen. Temporarily change the collectionBehavior of the window: + NSWindow* fullScreenWindow = [self window]; + NSWindowCollectionBehavior behavior = [fullScreenWindow collectionBehavior]; + [fullScreenWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; + [fullScreenWindow makeKeyAndOrderFront:self]; + [fullScreenWindow setCollectionBehavior:behavior]; + + // Start the opacity animation. We can use implicit animations here because we don't care when + // the animation finishes. + [CATransaction begin]; + [CATransaction setAnimationDuration:[self _animationDuration]]; + [[[self _fullScreenWindow] backgroundLayer] setOpacity:1]; + [CATransaction commit]; + + NSEnableScreenUpdates(); +} + +- (void)finishedEnterFullScreenAnimation:(bool)completed +{ + if (!_isEnteringFullScreen) + return; + _isEnteringFullScreen = NO; + + if (completed) { + NSDisableScreenUpdates(); + + // Swap the webView placeholder into place. + if (!_webViewPlaceholder) + _webViewPlaceholder.adoptNS([[NSView alloc] init]); + NSResponder *webWindowFirstResponder = [[_webView window] firstResponder]; + [self _swapView:_webView with:_webViewPlaceholder.get()]; + + // Then insert the WebView into the full screen window + NSView* contentView = [[self _fullScreenWindow] contentView]; + [contentView addSubview:_webView positioned:NSWindowBelow relativeTo:nil]; + [_webView setFrame:[contentView bounds]]; + [[self window] makeResponder:webWindowFirstResponder firstResponderIfDescendantOfView:_webView]; + + NSWindow *webWindow = [_webViewPlaceholder.get() window]; +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + // In Lion, NSWindow will animate into and out of orderOut operations. Suppress that + // behavior here, making sure to reset the animation behavior afterward. + NSWindowAnimationBehavior animationBehavior = [webWindow animationBehavior]; + [webWindow setAnimationBehavior:NSWindowAnimationBehaviorNone]; +#endif + [webWindow orderOut:self]; +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + [webWindow setAnimationBehavior:animationBehavior]; +#endif + [self _manager]->didEnterFullScreen(); + } + + // Complete the animation once -(void)exitCompositingMode is called. +} + +- (void)exitFullScreen +{ + if (!_isFullScreen) + return; + + _isFullScreen = NO; + + NSDisableScreenUpdates(); + + [self _manager]->willExitFullScreen(); + [self _manager]->beginExitFullScreenAnimation([self _animationDuration]); +} + +- (void)beganExitFullScreenAnimation +{ + if (_isExitingFullScreen) + return; + _isExitingFullScreen = YES; + + if (_isEnteringFullScreen) + [self finishedEnterFullScreenAnimation:NO]; + + [self _updateMenuAndDockForFullScreen]; + [self _updatePowerAssertions]; + + // Swap the webView back into its original position: + if ([_webView window] == [self window]) { + NSResponder *fullScreenWindowFirstResponder = [[self _fullScreenWindow] firstResponder]; +#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) + // Work around a bug in AppKit <rdar://problem/9443385> where moving a + // layer-hosted view from a layer-backed view to a non-layer-backed view + // generates an exception. + if (![_webView wantsLayer] && [_webView layer]) { + [_webView removeFromSuperview]; + for (NSView* child in [_webView subviews]) + [[child layer] removeFromSuperlayer]; + } +#endif + [self _swapView:_webViewPlaceholder.get() with:_webView]; + [[_webView window] makeResponder:fullScreenWindowFirstResponder firstResponderIfDescendantOfView:_webView]; + NSWindow* webWindow = [_webView window]; +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + // In Lion, NSWindow will animate into and out of orderOut operations. Suppress that + // behavior here, making sure to reset the animation behavior afterward. + NSWindowAnimationBehavior animationBehavior = [webWindow animationBehavior]; + [webWindow setAnimationBehavior:NSWindowAnimationBehaviorNone]; +#endif + // If the user has moved the fullScreen window into a new space, temporarily change + // the collectionBehavior of the webView's window so that it is pulled into the active space: + if (![webWindow isOnActiveSpace]) { + NSWindowCollectionBehavior behavior = [webWindow collectionBehavior]; + [webWindow setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; + [webWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; + [webWindow setCollectionBehavior:behavior]; + } else + [webWindow orderWindow:NSWindowBelow relativeTo:[[self window] windowNumber]]; + +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + [webWindow setAnimationBehavior:animationBehavior]; +#endif + } + + [CATransaction begin]; + [CATransaction setAnimationDuration:[self _animationDuration]]; + [[[self _fullScreenWindow] backgroundLayer] setOpacity:0]; + [CATransaction commit]; + + NSEnableScreenUpdates(); +} + +- (void)finishedExitFullScreenAnimation:(bool)completed +{ + if (!_isExitingFullScreen) + return; + _isExitingFullScreen = NO; + + NSDisableScreenUpdates(); + + [self _updateMenuAndDockForFullScreen]; + [self _updatePowerAssertions]; + [NSCursor setHiddenUntilMouseMoves:YES]; + + [self _manager]->didExitFullScreen(); +} + +- (void)enterAcceleratedCompositingMode:(const WebKit::LayerTreeContext&)layerTreeContext +{ + if (_layerHostingView) + return; + + // Create an NSView that will host our layer tree. + _layerHostingView.adoptNS([[NSView alloc] initWithFrame:[[self window] frame]]); + [_layerHostingView.get() setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + WKFullScreenWindow* window = [self _fullScreenWindow]; + [[window contentView] addSubview:_layerHostingView.get() positioned:NSWindowAbove relativeTo:nil]; + + // Create a root layer that will back the NSView. + RetainPtr<CALayer> rootLayer(AdoptNS, [[CALayer alloc] init]); +#ifndef NDEBUG + [rootLayer.get() setName:@"Hosting root layer"]; +#endif + + CALayer *renderLayer = WKMakeRenderLayer(layerTreeContext.contextID); + [rootLayer.get() addSublayer:renderLayer]; + + [_layerHostingView.get() setLayer:rootLayer.get()]; + [_layerHostingView.get() setWantsLayer:YES]; + [[window backgroundLayer] setHidden:NO]; + [CATransaction commit]; +} + +- (void)exitAcceleratedCompositingMode +{ + if (!_layerHostingView) + return; + + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + [_layerHostingView.get() removeFromSuperview]; + [_layerHostingView.get() setLayer:nil]; + [_layerHostingView.get() setWantsLayer:NO]; + [[[self _fullScreenWindow] backgroundLayer] setHidden:YES]; + [CATransaction commit]; + + // Complete the animation out of full-screen mode + // by hiding the full-screen window: + if (!_isFullScreen) { + [[_webView window] display]; + [[self window] orderOut:self]; + [[_webView window] makeKeyAndOrderFront:self]; + } + + _layerHostingView = 0; + [self _page]->forceRepaint(VoidCallback::create(self, continueExitCompositingModeAfterRepaintCallback)); +} + +static void continueExitCompositingModeAfterRepaintCallback(WKErrorRef error, void* context) +{ + [(WKFullScreenWindowController*)context _continueExitCompositingModeAfterRepaint]; +} + +- (void)_continueExitCompositingModeAfterRepaint +{ + NSEnableScreenUpdates(); + + [self _manager]->disposeOfLayerClient(); +} + +- (WebCore::IntRect)getFullScreenRect +{ + return enclosingIntRect([[self window] frame]); +} + +- (void)close +{ + // We are being asked to close rapidly, most likely because the page + // has closed or the web process has crashed. Just walk through our + // normal exit full screen sequence, but don't wait to be called back + // in response. + if (_isFullScreen) { + [self exitFullScreen]; + [self beganExitFullScreenAnimation]; + } + + if (_isExitingFullScreen) + [self finishedExitFullScreenAnimation:YES]; + + [super close]; +} + +#pragma mark - +#pragma mark Internal Interface + +- (void)_updateMenuAndDockForFullScreen +{ + // NSApplicationPresentationOptions is available on > 10.6 only: +#ifndef BUILDING_ON_LEOPARD + NSApplicationPresentationOptions options = NSApplicationPresentationDefault; + NSScreen* fullScreenScreen = [[self window] screen]; + + if (_isFullScreen) { + // Auto-hide the menu bar if the fullScreenScreen contains the menu bar: + // NOTE: if the fullScreenScreen contains the menu bar but not the dock, we must still + // auto-hide the dock, or an exception will be thrown. + if ([[NSScreen screens] objectAtIndex:0] == fullScreenScreen) + options |= (NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock); + // Check if the current screen contains the dock by comparing the screen's frame to its + // visibleFrame; if a dock is present, the visibleFrame will differ. If the current screen + // contains the dock, hide it. + else if (!NSEqualRects([fullScreenScreen frame], [fullScreenScreen visibleFrame])) + options |= NSApplicationPresentationAutoHideDock; + } + + if ([NSApp respondsToSelector:@selector(setPresentationOptions:)]) + [NSApp setPresentationOptions:options]; + else +#endif + SetSystemUIMode(_isFullScreen ? kUIModeNormal : kUIModeAllHidden, 0); +} + +- (void)_updatePowerAssertions +{ + // FIXME: _isPlaying is never modified so we never disable display sleep here! (<rdar://problem/10151029>) + if (_isPlaying && _isFullScreen) { + if (!_displaySleepDisabler) + _displaySleepDisabler = DisplaySleepDisabler::create("com.apple.WebKit2 - Fullscreen video"); + } else + _displaySleepDisabler = nullptr; +} + +- (WebPageProxy*)_page +{ + return toImpl([_webView pageRef]); +} + +- (WebFullScreenManagerProxy*)_manager +{ + WebPageProxy* webPage = [self _page]; + if (!webPage) + return 0; + return webPage->fullScreenManager(); +} + +- (void)_requestExit +{ + [self exitFullScreen]; + _forceDisableAnimation = NO; +} + +- (void)_requestExitFullScreenWithAnimation:(BOOL)animation +{ + _forceDisableAnimation = !animation; + [self performSelector:@selector(_requestExit) withObject:nil afterDelay:0]; + +} + +- (void)_swapView:(NSView*)view with:(NSView*)otherView +{ + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + [otherView setFrame:[view frame]]; + [otherView setAutoresizingMask:[view autoresizingMask]]; + [otherView removeFromSuperview]; + [[view superview] replaceSubview:view with:otherView]; + [CATransaction commit]; +} + +#pragma mark - +#pragma mark Utility Functions + +- (WKFullScreenWindow *)_fullScreenWindow +{ + ASSERT([[self window] isKindOfClass:[WKFullScreenWindow class]]); + return (WKFullScreenWindow *)[self window]; +} + +- (CFTimeInterval)_animationDuration +{ + static const CFTimeInterval defaultDuration = 0.5; + CFTimeInterval duration = defaultDuration; +#ifndef BUILDING_ON_LEOPARD + NSUInteger modifierFlags = [NSEvent modifierFlags]; +#else + NSUInteger modifierFlags = [[NSApp currentEvent] modifierFlags]; +#endif + if ((modifierFlags & NSControlKeyMask) == NSControlKeyMask) + duration *= 2; + if ((modifierFlags & NSShiftKeyMask) == NSShiftKeyMask) + duration *= 10; + if (_forceDisableAnimation) { + // This will disable scale animation + duration = 0; + } + return duration; +} + +@end + +#pragma mark - +@implementation WKFullScreenWindow + +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag +{ + UNUSED_PARAM(aStyle); + self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag]; + if (!self) + return nil; + [self setOpaque:NO]; + [self setBackgroundColor:[NSColor clearColor]]; + [self setIgnoresMouseEvents:NO]; + [self setAcceptsMouseMovedEvents:YES]; + [self setReleasedWhenClosed:NO]; + [self setHasShadow:YES]; +#ifndef BUILDING_ON_LEOPARD + [self setMovable:NO]; +#else + [self setMovableByWindowBackground:NO]; +#endif + + NSView* contentView = [self contentView]; + [contentView setWantsLayer:YES]; + _animationView = [[NSView alloc] initWithFrame:[contentView bounds]]; + + CALayer* contentLayer = [[CALayer alloc] init]; + [_animationView setLayer:contentLayer]; + [_animationView setWantsLayer:YES]; + [_animationView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; + [contentView addSubview:_animationView]; + + _backgroundLayer = [[CALayer alloc] init]; + [contentLayer addSublayer:_backgroundLayer]; + + [_backgroundLayer setBackgroundColor:CGColorGetConstantColor(kCGColorBlack)]; + [_backgroundLayer setOpacity:0]; + return self; +} + +- (void)dealloc +{ + [_animationView release]; + [_backgroundLayer release]; + [super dealloc]; +} + +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +- (void)keyDown:(NSEvent *)theEvent +{ + if ([[theEvent charactersIgnoringModifiers] isEqual:@"\e"]) // Esacpe key-code + [self cancelOperation:self]; + else [super keyDown:theEvent]; +} + +- (void)cancelOperation:(id)sender +{ + UNUSED_PARAM(sender); + [[self windowController] _requestExitFullScreenWithAnimation:YES]; +} + +- (CALayer*)backgroundLayer +{ + return _backgroundLayer; +} + +- (NSView*)animationView +{ + return _animationView; +} +@end + +#endif diff --git a/Source/WebKit2/UIProcess/mac/WebContextMac.mm b/Source/WebKit2/UIProcess/mac/WebContextMac.mm new file mode 100644 index 000000000..5270b7396 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebContextMac.mm @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebContext.h" + +#import "WebKitSystemInterface.h" +#import "WebProcessCreationParameters.h" +#import <WebCore/FileSystem.h> +#import <sys/param.h> + +using namespace WebCore; + +NSString *WebDatabaseDirectoryDefaultsKey = @"WebDatabaseDirectory"; +NSString *WebKitLocalCacheDefaultsKey = @"WebKitLocalCache"; +NSString *WebStorageDirectoryDefaultsKey = @"WebKitLocalStorageDatabasePathPreferenceKey"; + +static NSString *WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification = @"NSApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification"; + +// FIXME: <rdar://problem/9138817> - After this "backwards compatibility" radar is removed, this code should be removed to only return an empty String. +NSString *WebIconDatabaseDirectoryDefaultsKey = @"WebIconDatabaseDirectoryDefaultsKey"; + +namespace WebKit { + +String WebContext::applicationCacheDirectory() +{ + NSString *appName = [[NSBundle mainBundle] bundleIdentifier]; + if (!appName) + appName = [[NSProcessInfo processInfo] processName]; + + ASSERT(appName); + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *cacheDir = [defaults objectForKey:WebKitLocalCacheDefaultsKey]; + + if (!cacheDir || ![cacheDir isKindOfClass:[NSString class]]) { + char cacheDirectory[MAXPATHLEN]; + size_t cacheDirectoryLen = confstr(_CS_DARWIN_USER_CACHE_DIR, cacheDirectory, MAXPATHLEN); + + if (cacheDirectoryLen) + cacheDir = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:cacheDirectory length:cacheDirectoryLen - 1]; + } + + return [cacheDir stringByAppendingPathComponent:appName]; +} + + +void WebContext::platformInitializeWebProcess(WebProcessCreationParameters& parameters) +{ + if (!omitPDFSupport()) { + // We want to use a PDF view in the UI process for PDF MIME types. + HashSet<String, CaseFoldingHash> mimeType = pdfAndPostScriptMIMETypes(); + parameters.mimeTypesWithCustomRepresentation.appendRange(mimeType.begin(), mimeType.end()); + } + + RetainPtr<CFStringRef> cachePath(AdoptCF, WKCopyFoundationCacheDirectory()); + if (!cachePath) + cachePath = reinterpret_cast<CFStringRef>(NSHomeDirectory()); + + NSURLCache *urlCache = [NSURLCache sharedURLCache]; + + parameters.parentProcessName = [[NSProcessInfo processInfo] processName]; + parameters.nsURLCachePath = [(NSString *)cachePath.get() stringByStandardizingPath]; + parameters.nsURLCacheMemoryCapacity = [urlCache memoryCapacity]; + parameters.nsURLCacheDiskCapacity = [urlCache diskCapacity]; + + ASSERT(!parameters.nsURLCachePath.isEmpty()); + +#if ENABLE(PLUGIN_PROCESS) + parameters.disablePluginProcessMessageTimeout = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitDisablePluginProcessMessageTimeout"]; +#endif + +#if USE(ACCELERATED_COMPOSITING) && HAVE(HOSTED_CORE_ANIMATION) + mach_port_t renderServerPort = WKInitializeRenderServer(); + if (renderServerPort != MACH_PORT_NULL) + parameters.acceleratedCompositingPort = CoreIPC::MachPort(renderServerPort, MACH_MSG_TYPE_COPY_SEND); +#endif + + // FIXME: This should really be configurable; we shouldn't just blindly allow read access to the UI process bundle. + parameters.uiProcessBundleResourcePath = [[NSBundle mainBundle] resourcePath]; + +#if USE(CFURLSTORAGESESSIONS) + parameters.uiProcessBundleIdentifier = String([[NSBundle mainBundle] bundleIdentifier]); +#endif + + // Listen for enhanced accessibility changes and propagate them to the WebProcess. + m_enhancedAccessibilityObserver = [[NSNotificationCenter defaultCenter] addObserverForName:WebKitApplicationDidChangeAccessibilityEnhancedUserInterfaceNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *note) { + setEnhancedAccessibility([[[note userInfo] objectForKey:@"AXEnhancedUserInterface"] boolValue]); + }]; +} + +void WebContext::platformInvalidateContext() +{ + [[NSNotificationCenter defaultCenter] removeObserver:(id)m_enhancedAccessibilityObserver.get()]; +} + +String WebContext::platformDefaultDatabaseDirectory() const +{ + NSString *databasesDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebDatabaseDirectoryDefaultsKey]; + if (!databasesDirectory || ![databasesDirectory isKindOfClass:[NSString class]]) + databasesDirectory = @"~/Library/WebKit/Databases"; + return [databasesDirectory stringByStandardizingPath]; +} + +String WebContext::platformDefaultIconDatabasePath() const +{ + // FIXME: <rdar://problem/9138817> - After this "backwards compatibility" radar is removed, this code should be removed to only return an empty String. + NSString *databasesDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebIconDatabaseDirectoryDefaultsKey]; + if (!databasesDirectory || ![databasesDirectory isKindOfClass:[NSString class]]) + databasesDirectory = @"~/Library/Icons/WebpageIcons.db"; + return [databasesDirectory stringByStandardizingPath]; +} + +String WebContext::platformDefaultLocalStorageDirectory() const +{ + NSString *localStorageDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebStorageDirectoryDefaultsKey]; + if (!localStorageDirectory || ![localStorageDirectory isKindOfClass:[NSString class]]) + localStorageDirectory = @"~/Library/WebKit/LocalStorage"; + return [localStorageDirectory stringByStandardizingPath]; +} + +bool WebContext::omitPDFSupport() +{ + // Since this is a "secret default" we don't bother registering it. + return [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"]; +} + +} // namespace WebKit + diff --git a/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.h b/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.h new file mode 100644 index 000000000..20ffd0b67 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebContextMenuProxyMac_h +#define WebContextMenuProxyMac_h + +#include "WebContextMenuProxy.h" +#include <wtf/RetainPtr.h> + +OBJC_CLASS NSPopUpButtonCell; +OBJC_CLASS WKView; + +namespace WebKit { + +class WebPageProxy; + +class WebContextMenuProxyMac : public WebContextMenuProxy { +public: + static PassRefPtr<WebContextMenuProxyMac> create(WKView* webView, WebPageProxy* page) + { + return adoptRef(new WebContextMenuProxyMac(webView, page)); + } + ~WebContextMenuProxyMac(); + + virtual void showContextMenu(const WebCore::IntPoint&, const Vector<WebContextMenuItemData>&); + virtual void hideContextMenu(); + + void contextMenuItemSelected(const WebContextMenuItemData&); + +private: + WebContextMenuProxyMac(WKView*, WebPageProxy*); + + void populate(const Vector<WebContextMenuItemData>&); + + RetainPtr<NSPopUpButtonCell> m_popup; + WKView* m_webView; + WebPageProxy* m_page; +}; + +} // namespace WebKit + +#endif // WebContextMenuProxyMac_h diff --git a/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm new file mode 100644 index 000000000..81552dc5e --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebContextMenuProxyMac.mm @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebContextMenuProxyMac.h" + +#import "PageClientImpl.h" +#import "WebContextMenuItemData.h" +#import "WKView.h" + +#import <WebCore/IntRect.h> +#import <WebKitSystemInterface.h> + +using namespace WebCore; + +@interface WKUserDataWrapper : NSObject { + RefPtr<WebKit::APIObject> _webUserData; +} +- (id)initWithUserData:(WebKit::APIObject*)userData; +- (WebKit::APIObject*)userData; +@end + +@implementation WKUserDataWrapper + +- (id)initWithUserData:(WebKit::APIObject*)userData +{ + self = [super init]; + if (!self) + return nil; + + _webUserData = userData; + return self; +} + +- (WebKit::APIObject*)userData +{ + return _webUserData.get(); +} + +@end + +@interface WKMenuTarget : NSObject { + WebKit::WebContextMenuProxyMac* _menuProxy; +} ++ (WKMenuTarget*)sharedMenuTarget; +- (WebKit::WebContextMenuProxyMac*)menuProxy; +- (void)setMenuProxy:(WebKit::WebContextMenuProxyMac*)menuProxy; +- (void)forwardContextMenuAction:(id)sender; +@end + +@implementation WKMenuTarget + ++ (WKMenuTarget*)sharedMenuTarget +{ + static WKMenuTarget* target = [[WKMenuTarget alloc] init]; + return target; +} + +- (WebKit::WebContextMenuProxyMac*)menuProxy +{ + return _menuProxy; +} + +- (void)setMenuProxy:(WebKit::WebContextMenuProxyMac*)menuProxy +{ + _menuProxy = menuProxy; +} + +- (void)forwardContextMenuAction:(id)sender +{ + WebKit::WebContextMenuItemData item(ActionType, static_cast<ContextMenuAction>([sender tag]), [sender title], [sender isEnabled], [sender state] == NSOnState); + + if (id representedObject = [sender representedObject]) { + ASSERT([representedObject isKindOfClass:[WKUserDataWrapper class]]); + item.setUserData([static_cast<WKUserDataWrapper *>(representedObject) userData]); + } + + _menuProxy->contextMenuItemSelected(item); +} + +@end + +namespace WebKit { + +WebContextMenuProxyMac::WebContextMenuProxyMac(WKView* webView, WebPageProxy* page) + : m_webView(webView) + , m_page(page) +{ +} + +WebContextMenuProxyMac::~WebContextMenuProxyMac() +{ + if (m_popup) + [m_popup.get() setControlView:nil]; +} + +void WebContextMenuProxyMac::contextMenuItemSelected(const WebContextMenuItemData& item) +{ + m_page->contextMenuItemSelected(item); +} + +static void populateNSMenu(NSMenu* menu, const Vector<RetainPtr<NSMenuItem> >& menuItemVector) +{ + for (unsigned i = 0; i < menuItemVector.size(); ++i) { + NSInteger oldState = [menuItemVector[i].get() state]; + [menu addItem:menuItemVector[i].get()]; + [menuItemVector[i].get() setState:oldState]; + } +} + +static Vector<RetainPtr<NSMenuItem> > nsMenuItemVector(const Vector<WebContextMenuItemData>& items) +{ + Vector<RetainPtr<NSMenuItem> > result; + + unsigned size = items.size(); + result.reserveCapacity(size); + for (unsigned i = 0; i < size; i++) { + switch (items[i].type()) { + case ActionType: + case CheckableActionType: { + NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:nsStringFromWebCoreString(items[i].title()) action:@selector(forwardContextMenuAction:) keyEquivalent:@""]; + [menuItem setTag:items[i].action()]; + [menuItem setEnabled:items[i].enabled()]; + [menuItem setState:items[i].checked() ? NSOnState : NSOffState]; + + if (items[i].userData()) { + WKUserDataWrapper *wrapper = [[WKUserDataWrapper alloc] initWithUserData:items[i].userData()]; + [menuItem setRepresentedObject:wrapper]; + [wrapper release]; + } + + result.append(RetainPtr<NSMenuItem>(AdoptNS, menuItem)); + break; + } + case SeparatorType: + result.append([NSMenuItem separatorItem]); + break; + case SubmenuType: { + NSMenu* menu = [[NSMenu alloc] initWithTitle:nsStringFromWebCoreString(items[i].title())]; + [menu setAutoenablesItems:NO]; + populateNSMenu(menu, nsMenuItemVector(items[i].submenu())); + + NSMenuItem* menuItem = [[NSMenuItem alloc] initWithTitle:nsStringFromWebCoreString(items[i].title()) action:@selector(forwardContextMenuAction:) keyEquivalent:@""]; + [menuItem setEnabled:items[i].enabled()]; + [menuItem setSubmenu:menu]; + [menu release]; + + result.append(RetainPtr<NSMenuItem>(AdoptNS, menuItem)); + + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + WKMenuTarget* target = [WKMenuTarget sharedMenuTarget]; + for (unsigned i = 0; i < size; ++i) + [result[i].get() setTarget:target]; + + return result; +} + +void WebContextMenuProxyMac::populate(const Vector<WebContextMenuItemData>& items) +{ + if (m_popup) + [m_popup.get() removeAllItems]; + else { + m_popup.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); + [m_popup.get() setUsesItemFromMenu:NO]; + [m_popup.get() setAutoenablesItems:NO]; + } + + NSMenu* menu = [m_popup.get() menu]; + populateNSMenu(menu, nsMenuItemVector(items)); +} + +void WebContextMenuProxyMac::showContextMenu(const IntPoint& menuLocation, const Vector<WebContextMenuItemData>& items) +{ + if (items.isEmpty()) + return; + + populate(items); + [[WKMenuTarget sharedMenuTarget] setMenuProxy:this]; + + NSRect menuRect = NSMakeRect(menuLocation.x(), menuLocation.y(), 0, 0); + + [m_popup.get() attachPopUpWithFrame:menuRect inView:m_webView]; + + NSMenu* menu = [m_popup.get() menu]; + + // These values were borrowed from AppKit to match their placement of the menu. + NSRect titleFrame = [m_popup.get() titleRectForBounds:menuRect]; + if (titleFrame.size.width <= 0 || titleFrame.size.height <= 0) + titleFrame = menuRect; + float vertOffset = roundf((NSMaxY(menuRect) - NSMaxY(titleFrame)) + NSHeight(titleFrame)); + NSPoint location = NSMakePoint(NSMinX(menuRect), NSMaxY(menuRect) - vertOffset); + + location = [m_webView convertPoint:location toView:nil]; + location = [m_webView.window convertBaseToScreen:location]; + + WKPopupContextMenu(menu, location); + + [m_popup.get() dismissPopUp]; +} + +void WebContextMenuProxyMac::hideContextMenu() +{ + [m_popup.get() dismissPopUp]; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/WebCookieManagerProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebCookieManagerProxyMac.mm new file mode 100644 index 000000000..6a3134647 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebCookieManagerProxyMac.mm @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebCookieManagerProxy.h" + +namespace WebKit { + +void WebCookieManagerProxy::persistHTTPCookieAcceptPolicy(HTTPCookieAcceptPolicy policy) +{ + // FIXME: The sandbox appears to prevent persisting the new policy to disk, so we must set the + // policy in the UI Process as well as in the Web Process (to make sure it gets set on any + // Private Browsing Cookie Storage). + [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:policy]; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/WebFullScreenManagerProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebFullScreenManagerProxyMac.mm new file mode 100644 index 000000000..20e92c054 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebFullScreenManagerProxyMac.mm @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebFullScreenManagerProxy.h" + +#import "LayerTreeContext.h" +#import "WKFullScreenWindowController.h" +#import "WKViewInternal.h" +#import <WebCore/IntRect.h> + +#if ENABLE(FULLSCREEN_API) + +namespace WebKit { + +void WebFullScreenManagerProxy::invalidate() +{ + if (!m_webView) + return; + + [m_webView closeFullScreenWindowController]; + m_webView = 0; +} + +void WebFullScreenManagerProxy::enterFullScreen() +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] enterFullScreen:nil]; +} + +void WebFullScreenManagerProxy::exitFullScreen() +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] exitFullScreen]; +} + +void WebFullScreenManagerProxy::beganEnterFullScreenAnimation() +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] beganEnterFullScreenAnimation]; +} + +void WebFullScreenManagerProxy::finishedEnterFullScreenAnimation(bool completed) +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] finishedEnterFullScreenAnimation:completed]; +} + +void WebFullScreenManagerProxy::beganExitFullScreenAnimation() +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] beganExitFullScreenAnimation]; +} + +void WebFullScreenManagerProxy::finishedExitFullScreenAnimation(bool completed) +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] finishedExitFullScreenAnimation:completed]; +} + +void WebFullScreenManagerProxy::enterAcceleratedCompositingMode(const LayerTreeContext& context) +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] enterAcceleratedCompositingMode:context]; +} + +void WebFullScreenManagerProxy::exitAcceleratedCompositingMode() +{ + if (!m_webView) + return; + [[m_webView fullScreenWindowController] exitAcceleratedCompositingMode]; +} + +void WebFullScreenManagerProxy::getFullScreenRect(WebCore::IntRect& rect) +{ + if (!m_webView) + return; + rect = [[m_webView fullScreenWindowController] getFullScreenRect]; +} + +} // namespace WebKit + +#endif diff --git a/Source/WebKit2/UIProcess/mac/WebInspectorProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebInspectorProxyMac.mm new file mode 100644 index 000000000..26410bce0 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebInspectorProxyMac.mm @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebInspectorProxy.h" + +#if ENABLE(INSPECTOR) + +#import "WKAPICast.h" +#import "WebContext.h" +#import "WKInspectorMac.h" +#import "WKViewPrivate.h" +#import "WebPageProxy.h" +#import "WebProcessProxy.h" +#import <WebKitSystemInterface.h> +#import <WebCore/InspectorFrontendClientLocal.h> +#import <WebCore/LocalizedStrings.h> +#import <WebCore/NotImplemented.h> +#import <wtf/text/WTFString.h> + +using namespace WebCore; +using namespace WebKit; + +// The height needed to match a typical NSToolbar. +static const CGFloat windowContentBorderThickness = 55; + +// WKWebInspectorProxyObjCAdapter is a helper ObjC object used as a delegate or notification observer +// for the sole purpose of getting back into the C++ code from an ObjC caller. + +@interface WKWebInspectorProxyObjCAdapter : NSObject <NSWindowDelegate> { + WebInspectorProxy* _inspectorProxy; // Not retained to prevent cycles +} + +- (id)initWithWebInspectorProxy:(WebInspectorProxy*)inspectorProxy; + +@end + +@implementation WKWebInspectorProxyObjCAdapter + +- (id)initWithWebInspectorProxy:(WebInspectorProxy*)inspectorProxy +{ + ASSERT_ARG(inspectorProxy, inspectorProxy); + + if (!(self = [super init])) + return nil; + + _inspectorProxy = inspectorProxy; // Not retained to prevent cycles + + return self; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + _inspectorProxy->close(); +} + +- (void)inspectedViewFrameDidChange:(NSNotification *)notification +{ + _inspectorProxy->inspectedViewFrameDidChange(); +} + +@end + +@interface WKWebInspectorWKView : WKView +@end + +@implementation WKWebInspectorWKView + +- (NSInteger)tag +{ + return WKInspectorViewTag; +} + +@end + +namespace WebKit { + +WebPageProxy* WebInspectorProxy::platformCreateInspectorPage() +{ + ASSERT(m_page); + ASSERT(!m_inspectorView); + + m_inspectorView.adoptNS([[WKWebInspectorWKView alloc] initWithFrame:NSMakeRect(0, 0, initialWindowWidth, initialWindowHeight) contextRef:toAPI(page()->process()->context()) pageGroupRef:toAPI(inspectorPageGroup())]); + ASSERT(m_inspectorView); + + [m_inspectorView.get() setDrawsBackground:NO]; + + return toImpl(m_inspectorView.get().pageRef); +} + +void WebInspectorProxy::platformOpen() +{ + ASSERT(!m_inspectorWindow); + + m_inspectorProxyObjCAdapter.adoptNS([[WKWebInspectorProxyObjCAdapter alloc] initWithWebInspectorProxy:this]); + + bool useTexturedWindow = page()->process()->context()->overrideWebInspectorPagePath().isEmpty(); + + NSUInteger styleMask = (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask); + if (useTexturedWindow) + styleMask |= NSTexturedBackgroundWindowMask; + + NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, initialWindowWidth, initialWindowHeight) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; + [window setDelegate:m_inspectorProxyObjCAdapter.get()]; + [window setMinSize:NSMakeSize(minimumWindowWidth, minimumWindowHeight)]; + [window setReleasedWhenClosed:NO]; + + if (useTexturedWindow) { + [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; + [window setContentBorderThickness:windowContentBorderThickness forEdge:NSMaxYEdge]; + WKNSWindowMakeBottomCornersSquare(window); + } + + // Center the window initially before setting the frame autosave name so that the window will be in a good + // position if there is no saved frame yet. + [window center]; + [window setFrameAutosaveName:@"Web Inspector 2"]; + + NSView *contentView = [window contentView]; + [m_inspectorView.get() setFrame:[contentView bounds]]; + [m_inspectorView.get() setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + [contentView addSubview:m_inspectorView.get()]; + + m_inspectorWindow.adoptNS(window); + + if (m_isAttached) + platformAttach(); + else + [window makeKeyAndOrderFront:nil]; +} + +void WebInspectorProxy::platformDidClose() +{ + [m_inspectorWindow.get() setDelegate:nil]; + [m_inspectorWindow.get() orderOut:nil]; + + m_inspectorWindow = 0; + m_inspectorView = 0; + m_inspectorProxyObjCAdapter = 0; +} + +void WebInspectorProxy::platformBringToFront() +{ + // FIXME: this will not bring a background tab in Safari to the front, only its window. + [m_inspectorView.get().window makeKeyAndOrderFront:nil]; +} + +void WebInspectorProxy::platformInspectedURLChanged(const String& urlString) +{ + NSString *title = [NSString stringWithFormat:WEB_UI_STRING("Web Inspector — %@", "Web Inspector window title"), (NSString *)urlString]; + [m_inspectorWindow.get() setTitle:title]; +} + +void WebInspectorProxy::inspectedViewFrameDidChange() +{ + if (!m_isAttached) + return; + + WKView *inspectedView = m_page->wkView(); + NSRect inspectedViewFrame = [inspectedView frame]; + + CGFloat inspectedLeft = NSMinX(inspectedViewFrame); + CGFloat inspectedTop = NSMaxY(inspectedViewFrame); + CGFloat inspectedWidth = NSWidth(inspectedViewFrame); + CGFloat inspectorHeight = NSHeight([m_inspectorView.get() frame]); + + CGFloat parentHeight = NSHeight([[inspectedView superview] frame]); + inspectorHeight = InspectorFrontendClientLocal::constrainedAttachedWindowHeight(inspectorHeight, parentHeight); + + [m_inspectorView.get() setFrame:NSMakeRect(inspectedLeft, 0.0, inspectedWidth, inspectorHeight)]; + [inspectedView setFrame:NSMakeRect(inspectedLeft, inspectorHeight, inspectedWidth, inspectedTop - inspectorHeight)]; +} + +unsigned WebInspectorProxy::platformInspectedWindowHeight() +{ + WKView *inspectedView = m_page->wkView(); + NSRect inspectedViewRect = [inspectedView frame]; + return static_cast<unsigned>(inspectedViewRect.size.height); +} + +void WebInspectorProxy::platformAttach() +{ + WKView *inspectedView = m_page->wkView(); + [[NSNotificationCenter defaultCenter] addObserver:m_inspectorProxyObjCAdapter.get() selector:@selector(inspectedViewFrameDidChange:) name:NSViewFrameDidChangeNotification object:inspectedView]; + + [m_inspectorView.get() removeFromSuperview]; + + [[inspectedView superview] addSubview:m_inspectorView.get() positioned:NSWindowBelow relativeTo:inspectedView]; + + [m_inspectorWindow.get() orderOut:nil]; + + inspectedViewFrameDidChange(); +} + +void WebInspectorProxy::platformDetach() +{ + WKView *inspectedView = m_page->wkView(); + [[NSNotificationCenter defaultCenter] removeObserver:m_inspectorProxyObjCAdapter.get() name:NSViewFrameDidChangeNotification object:inspectedView]; + + [m_inspectorView.get() removeFromSuperview]; + + // Move the inspector view back into the inspector window. + NSView *inspectorWindowContentView = [m_inspectorWindow.get() contentView]; + [m_inspectorView.get() setFrame:[inspectorWindowContentView bounds]]; + [inspectorWindowContentView addSubview:m_inspectorView.get()]; + + // Make sure that we size the inspected view's frame after detaching so that it takes up the space that the + // attached inspector used to. This assumes the previous height was the Y origin. + NSRect inspectedViewRect = [inspectedView frame]; + inspectedViewRect.size.height += NSMinY(inspectedViewRect); + inspectedViewRect.origin.y = 0.0; + [inspectedView setFrame:inspectedViewRect]; + + if (m_isVisible) + [m_inspectorWindow.get() makeKeyAndOrderFront:nil]; +} + +void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned height) +{ + if (!m_isAttached) + return; + + WKView *inspectedView = m_page->wkView(); + NSRect inspectedViewFrame = [inspectedView frame]; + + // The inspector view shares the width and the left starting point of the inspected view. + [m_inspectorView.get() setFrame:NSMakeRect(NSMinX(inspectedViewFrame), 0.0, NSWidth(inspectedViewFrame), height)]; + + inspectedViewFrameDidChange(); + + [m_inspectorView.get() setNeedsDisplay:YES]; + [inspectedView setNeedsDisplay:YES]; +} + +String WebInspectorProxy::inspectorPageURL() const +{ + NSString *path = page()->process()->context()->overrideWebInspectorPagePath(); + if (![path length]) + path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"inspector" ofType:@"html" inDirectory:@"inspector"]; + + ASSERT([path length]); + + return [[NSURL fileURLWithPath:path] absoluteString]; +} + +String WebInspectorProxy::inspectorBaseURL() const +{ + NSString *path = page()->process()->context()->overrideWebInspectorBaseDirectory(); + if (![path length]) { + // WebCore's Web Inspector uses localized strings, which are not contained within inspector directory. + path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] resourcePath]; + } + + ASSERT([path length]); + + return [[NSURL fileURLWithPath:path] absoluteString]; +} + +} // namespace WebKit + +#endif // ENABLE(INSPECTOR) diff --git a/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm new file mode 100644 index 000000000..192eb419f --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebPageProxyMac.mm @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebPageProxy.h" + +#import "AttributedString.h" +#import "DataReference.h" +#import "DictionaryPopupInfo.h" +#import "EditorState.h" +#import "NativeWebKeyboardEvent.h" +#import "PluginComplexTextInputState.h" +#import "PageClient.h" +#import "PageClientImpl.h" +#import "TextChecker.h" +#import "WebPageMessages.h" +#import "WebProcessProxy.h" +#import <WebKitSystemInterface.h> +#import <wtf/text/StringConcatenate.h> + +@interface NSApplication (Details) +- (void)speakString:(NSString *)string; +@end + +#define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, process()->connection()) + +using namespace WebCore; + +namespace WebKit { + +#if defined(__ppc__) || defined(__ppc64__) +#define PROCESSOR "PPC" +#elif defined(__i386__) || defined(__x86_64__) +#define PROCESSOR "Intel" +#else +#error Unknown architecture +#endif + +#if !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) + +static String macOSXVersionString() +{ + // Use underscores instead of dots because when we first added the Mac OS X version to the user agent string + // we were concerned about old DHTML libraries interpreting "4." as Netscape 4. That's no longer a concern for us + // but we're sticking with the underscores for compatibility with the format used by older versions of Safari. + return [WKGetMacOSXVersionString() stringByReplacingOccurrencesOfString:@"." withString:@"_"]; +} + +#else + +static inline int callGestalt(OSType selector) +{ + SInt32 value = 0; + Gestalt(selector, &value); + return value; +} + +// Uses underscores instead of dots because if "4." ever appears in a user agent string, old DHTML libraries treat it as Netscape 4. +static String macOSXVersionString() +{ + // Can't use -[NSProcessInfo operatingSystemVersionString] because it has too much stuff we don't want. + int major = callGestalt(gestaltSystemVersionMajor); + ASSERT(major); + + int minor = callGestalt(gestaltSystemVersionMinor); + int bugFix = callGestalt(gestaltSystemVersionBugFix); + if (bugFix) + return String::format("%d_%d_%d", major, minor, bugFix); + if (minor) + return String::format("%d_%d", major, minor); + return String::format("%d", major); +} + +#endif // !defined(BUILDING_ON_SNOW_LEOPARD) && !defined(BUILDING_ON_LION) + +static String userVisibleWebKitVersionString() +{ + // If the version is 4 digits long or longer, then the first digit represents + // the version of the OS. Our user agent string should not include this first digit, + // so strip it off and report the rest as the version. <rdar://problem/4997547> + NSString *fullVersion = [[NSBundle bundleForClass:NSClassFromString(@"WKView")] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + NSRange nonDigitRange = [fullVersion rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]]; + if (nonDigitRange.location == NSNotFound && [fullVersion length] >= 4) + return [fullVersion substringFromIndex:1]; + if (nonDigitRange.location != NSNotFound && nonDigitRange.location >= 4) + return [fullVersion substringFromIndex:1]; + return fullVersion; +} + +String WebPageProxy::standardUserAgent(const String& applicationNameForUserAgent) +{ + DEFINE_STATIC_LOCAL(String, osVersion, (macOSXVersionString())); + DEFINE_STATIC_LOCAL(String, webKitVersion, (userVisibleWebKitVersionString())); + + if (applicationNameForUserAgent.isEmpty()) + return makeString("Mozilla/5.0 (Macintosh; " PROCESSOR " Mac OS X ", osVersion, ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko)"); + return makeString("Mozilla/5.0 (Macintosh; " PROCESSOR " Mac OS X ", osVersion, ") AppleWebKit/", webKitVersion, " (KHTML, like Gecko) ", applicationNameForUserAgent); +} + +void WebPageProxy::getIsSpeaking(bool& isSpeaking) +{ + isSpeaking = [NSApp isSpeaking]; +} + +void WebPageProxy::speak(const String& string) +{ + [NSApp speakString:nsStringFromWebCoreString(string)]; +} + +void WebPageProxy::stopSpeaking() +{ + [NSApp stopSpeaking:nil]; +} + +void WebPageProxy::searchWithSpotlight(const String& string) +{ + [[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:nsStringFromWebCoreString(string)]; +} + +CGContextRef WebPageProxy::containingWindowGraphicsContext() +{ + return m_pageClient->containingWindowGraphicsContext(); +} + +void WebPageProxy::updateWindowIsVisible(bool windowIsVisible) +{ + if (!isValid()) + return; + process()->send(Messages::WebPage::SetWindowIsVisible(windowIsVisible), m_pageID); +} + +void WebPageProxy::windowAndViewFramesChanged(const IntRect& windowFrameInScreenCoordinates, const IntRect& viewFrameInWindowCoordinates, const IntPoint& accessibilityViewCoordinates) +{ + if (!isValid()) + return; + + process()->send(Messages::WebPage::WindowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates, accessibilityViewCoordinates), m_pageID); +} + +void WebPageProxy::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) +{ + if (!isValid()) { + // If this fails, we should call -discardMarkedText on input context to notify the input method. + // This will happen naturally later, as part of reloading the page. + return; + } + + process()->sendSync(Messages::WebPage::SetComposition(text, underlines, selectionStart, selectionEnd, replacementRangeStart, replacementRangeEnd), Messages::WebPage::SetComposition::Reply(m_editorState), m_pageID); +} + +void WebPageProxy::confirmComposition() +{ + if (!isValid()) + return; + + process()->sendSync(Messages::WebPage::ConfirmComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID); +} + +void WebPageProxy::cancelComposition() +{ + if (!isValid()) + return; + + process()->sendSync(Messages::WebPage::CancelComposition(), Messages::WebPage::ConfirmComposition::Reply(m_editorState), m_pageID); +} + +bool WebPageProxy::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) +{ + if (!isValid()) + return true; + + bool handled = true; + process()->sendSync(Messages::WebPage::InsertText(text, replacementRangeStart, replacementRangeEnd), Messages::WebPage::InsertText::Reply(handled, m_editorState), m_pageID); + return handled; +} + +void WebPageProxy::getMarkedRange(uint64_t& location, uint64_t& length) +{ + location = NSNotFound; + length = 0; + + if (!isValid()) + return; + + process()->sendSync(Messages::WebPage::GetMarkedRange(), Messages::WebPage::GetMarkedRange::Reply(location, length), m_pageID); +} + +void WebPageProxy::getSelectedRange(uint64_t& location, uint64_t& length) +{ + location = NSNotFound; + length = 0; + + if (!isValid()) + return; + + process()->sendSync(Messages::WebPage::GetSelectedRange(), Messages::WebPage::GetSelectedRange::Reply(location, length), m_pageID); +} + +void WebPageProxy::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result) +{ + if (!isValid()) + return; + process()->sendSync(Messages::WebPage::GetAttributedSubstringFromRange(location, length), Messages::WebPage::GetAttributedSubstringFromRange::Reply(result), m_pageID); +} + +uint64_t WebPageProxy::characterIndexForPoint(const IntPoint point) +{ + if (!isValid()) + return 0; + + uint64_t result = 0; + process()->sendSync(Messages::WebPage::CharacterIndexForPoint(point), Messages::WebPage::CharacterIndexForPoint::Reply(result), m_pageID); + return result; +} + +IntRect WebPageProxy::firstRectForCharacterRange(uint64_t location, uint64_t length) +{ + if (!isValid()) + return IntRect(); + + IntRect resultRect; + process()->sendSync(Messages::WebPage::FirstRectForCharacterRange(location, length), Messages::WebPage::FirstRectForCharacterRange::Reply(resultRect), m_pageID); + return resultRect; +} + +bool WebPageProxy::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands) +{ + if (!isValid()) + return false; + + bool result = false; + process()->sendSync(Messages::WebPage::ExecuteKeypressCommands(commands), Messages::WebPage::ExecuteKeypressCommands::Reply(result, m_editorState), m_pageID); + return result; +} + +bool WebPageProxy::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes) +{ + if (!isValid()) + return false; + + bool result = false; + const double messageTimeout = 20; + process()->sendSync(Messages::WebPage::WriteSelectionToPasteboard(pasteboardName, pasteboardTypes), Messages::WebPage::WriteSelectionToPasteboard::Reply(result), m_pageID, messageTimeout); + return result; +} + +bool WebPageProxy::readSelectionFromPasteboard(const String& pasteboardName) +{ + if (!isValid()) + return false; + + bool result = false; + const double messageTimeout = 20; + process()->sendSync(Messages::WebPage::ReadSelectionFromPasteboard(pasteboardName), Messages::WebPage::ReadSelectionFromPasteboard::Reply(result), m_pageID, messageTimeout); + return result; +} + +void WebPageProxy::setDragImage(const WebCore::IntPoint& clientPosition, const ShareableBitmap::Handle& dragImageHandle, bool isLinkDrag) +{ + RefPtr<ShareableBitmap> dragImage = ShareableBitmap::create(dragImageHandle); + if (!dragImage) + return; + + m_pageClient->setDragImage(clientPosition, dragImage.release(), isLinkDrag); +} + +void WebPageProxy::performDictionaryLookupAtLocation(const WebCore::FloatPoint& point) +{ + if (!isValid()) + return; + + process()->send(Messages::WebPage::PerformDictionaryLookupAtLocation(point), m_pageID); +} + +void WebPageProxy::interpretQueuedKeyEvent(const EditorState& state, bool& handled, Vector<WebCore::KeypressCommand>& commands) +{ + m_editorState = state; + handled = m_pageClient->interpretKeyEvent(m_keyEventQueue.first(), commands); +} + +// Complex text input support for plug-ins. +void WebPageProxy::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput) +{ + if (!isValid()) + return; + + process()->send(Messages::WebPage::SendComplexTextInputToPlugin(pluginComplexTextInputIdentifier, textInput), m_pageID); +} + +void WebPageProxy::uppercaseWord() +{ + process()->send(Messages::WebPage::UppercaseWord(), m_pageID); +} + +void WebPageProxy::lowercaseWord() +{ + process()->send(Messages::WebPage::LowercaseWord(), m_pageID); +} + +void WebPageProxy::capitalizeWord() +{ + process()->send(Messages::WebPage::CapitalizeWord(), m_pageID); +} + +void WebPageProxy::setSmartInsertDeleteEnabled(bool isSmartInsertDeleteEnabled) +{ + if (m_isSmartInsertDeleteEnabled == isSmartInsertDeleteEnabled) + return; + + TextChecker::setSmartInsertDeleteEnabled(isSmartInsertDeleteEnabled); + m_isSmartInsertDeleteEnabled = isSmartInsertDeleteEnabled; + process()->send(Messages::WebPage::SetSmartInsertDeleteEnabled(isSmartInsertDeleteEnabled), m_pageID); +} + +void WebPageProxy::didPerformDictionaryLookup(const String& text, const DictionaryPopupInfo& dictionaryPopupInfo) +{ + m_pageClient->didPerformDictionaryLookup(text, m_pageScaleFactor, dictionaryPopupInfo); +} + +void WebPageProxy::registerWebProcessAccessibilityToken(const CoreIPC::DataReference& data) +{ + m_pageClient->accessibilityWebProcessTokenReceived(data); +} + +void WebPageProxy::makeFirstResponder() +{ + m_pageClient->makeFirstResponder(); +} + +void WebPageProxy::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elementToken, const CoreIPC::DataReference& windowToken) +{ + if (!isValid()) + return; + + process()->send(Messages::WebPage::RegisterUIProcessAccessibilityTokens(elementToken, windowToken), m_pageID); +} + +void WebPageProxy::pluginFocusOrWindowFocusChanged(uint64_t pluginComplexTextInputIdentifier, bool pluginHasFocusAndWindowHasFocus) +{ + m_pageClient->pluginFocusOrWindowFocusChanged(pluginComplexTextInputIdentifier, pluginHasFocusAndWindowHasFocus); +} + +void WebPageProxy::setPluginComplexTextInputState(uint64_t pluginComplexTextInputIdentifier, uint64_t pluginComplexTextInputState) +{ + MESSAGE_CHECK(isValidPluginComplexTextInputState(pluginComplexTextInputState)); + + m_pageClient->setPluginComplexTextInputState(pluginComplexTextInputIdentifier, static_cast<PluginComplexTextInputState>(pluginComplexTextInputState)); +} + +void WebPageProxy::executeSavedCommandBySelector(const String& selector, bool& handled) +{ + handled = m_pageClient->executeSavedCommandBySelector(selector); +} + +bool WebPageProxy::shouldDelayWindowOrderingForEvent(const WebKit::WebMouseEvent& event) +{ + if (!process()->isValid()) + return false; + + bool result = false; + const double messageTimeout = 3; + process()->sendSync(Messages::WebPage::ShouldDelayWindowOrderingEvent(event), Messages::WebPage::ShouldDelayWindowOrderingEvent::Reply(result), m_pageID, messageTimeout); + return result; +} + +bool WebPageProxy::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event) +{ + if (!isValid()) + return false; + + bool result = false; + const double messageTimeout = 3; + process()->sendSync(Messages::WebPage::AcceptsFirstMouse(eventNumber, event), Messages::WebPage::AcceptsFirstMouse::Reply(result), m_pageID, messageTimeout); + return result; +} + +WKView* WebPageProxy::wkView() const +{ + return m_pageClient->wkView(); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/WebPopupMenuProxyMac.h b/Source/WebKit2/UIProcess/mac/WebPopupMenuProxyMac.h new file mode 100644 index 000000000..ad22e0a81 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebPopupMenuProxyMac.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebPopupMenuProxyMac_h +#define WebPopupMenuProxyMac_h + +#include "WebPopupMenuProxy.h" +#include <wtf/RetainPtr.h> + +OBJC_CLASS NSPopUpButtonCell; +OBJC_CLASS WKView; + +namespace WebKit { + +class WebPageProxy; + +class WebPopupMenuProxyMac : public WebPopupMenuProxy { +public: + static PassRefPtr<WebPopupMenuProxyMac> create(WKView *webView, WebPopupMenuProxy::Client* client) + { + return adoptRef(new WebPopupMenuProxyMac(webView, client)); + } + ~WebPopupMenuProxyMac(); + + virtual void showPopupMenu(const WebCore::IntRect&, WebCore::TextDirection, double pageScaleFactor, const Vector<WebPopupItem>&, const PlatformPopupMenuData&, int32_t selectedIndex); + virtual void hidePopupMenu(); + +private: + WebPopupMenuProxyMac(WKView *, WebPopupMenuProxy::Client*); + + void populate(const Vector<WebPopupItem>&, NSFont *, WebCore::TextDirection); + + RetainPtr<NSPopUpButtonCell> m_popup; + WKView *m_webView; +}; + +} // namespace WebKit + +#endif // WebPopupMenuProxyMac_h diff --git a/Source/WebKit2/UIProcess/mac/WebPopupMenuProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebPopupMenuProxyMac.mm new file mode 100644 index 000000000..30e2e2087 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebPopupMenuProxyMac.mm @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebPopupMenuProxyMac.h" + +#import "NativeWebMouseEvent.h" +#import "PageClientImpl.h" +#import "PlatformPopupMenuData.h" +#import "WKView.h" +#import "WebPopupItem.h" +#import <WebKitSystemInterface.h> + +using namespace WebCore; + +namespace WebKit { + +WebPopupMenuProxyMac::WebPopupMenuProxyMac(WKView *webView, WebPopupMenuProxy::Client* client) + : WebPopupMenuProxy(client) + , m_webView(webView) +{ +} + +WebPopupMenuProxyMac::~WebPopupMenuProxyMac() +{ + if (m_popup) + [m_popup.get() setControlView:nil]; +} + +void WebPopupMenuProxyMac::populate(const Vector<WebPopupItem>& items, NSFont *font, TextDirection menuTextDirection) +{ + if (m_popup) + [m_popup.get() removeAllItems]; + else { + m_popup.adoptNS([[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:NO]); + [m_popup.get() setUsesItemFromMenu:NO]; + [m_popup.get() setAutoenablesItems:NO]; + } + + int size = items.size(); + + for (int i = 0; i < size; i++) { + if (items[i].m_type == WebPopupItem::Separator) + [[m_popup.get() menu] addItem:[NSMenuItem separatorItem]]; + else { + [m_popup.get() addItemWithTitle:@""]; + NSMenuItem *menuItem = [m_popup.get() lastItem]; + + RetainPtr<NSMutableParagraphStyle> paragraphStyle(AdoptNS, [[NSParagraphStyle defaultParagraphStyle] mutableCopy]); + NSWritingDirection writingDirection = items[i].m_textDirection == LTR ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft; + [paragraphStyle.get() setBaseWritingDirection:writingDirection]; + [paragraphStyle.get() setAlignment:menuTextDirection == LTR ? NSLeftTextAlignment : NSRightTextAlignment]; + RetainPtr<NSMutableDictionary> attributes(AdoptNS, [[NSMutableDictionary alloc] initWithObjectsAndKeys: + paragraphStyle.get(), NSParagraphStyleAttributeName, + font, NSFontAttributeName, + nil]); + if (items[i].m_hasTextDirectionOverride) { + RetainPtr<NSNumber> writingDirectionValue(AdoptNS, [[NSNumber alloc] initWithInteger:writingDirection + NSTextWritingDirectionOverride]); + RetainPtr<NSArray> writingDirectionArray(AdoptNS, [[NSArray alloc] initWithObjects:writingDirectionValue.get(), nil]); + [attributes.get() setObject:writingDirectionArray.get() forKey:NSWritingDirectionAttributeName]; + } + RetainPtr<NSAttributedString> string(AdoptNS, [[NSAttributedString alloc] initWithString:nsStringFromWebCoreString(items[i].m_text) attributes:attributes.get()]); + + [menuItem setAttributedTitle:string.get()]; + [menuItem setEnabled:items[i].m_isEnabled]; + [menuItem setToolTip:nsStringFromWebCoreString(items[i].m_toolTip)]; + } + } +} + +void WebPopupMenuProxyMac::showPopupMenu(const IntRect& rect, TextDirection textDirection, double pageScaleFactor, const Vector<WebPopupItem>& items, const PlatformPopupMenuData& data, int32_t selectedIndex) +{ + NSFont *font; + if (data.fontInfo.fontAttributeDictionary) { + NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:(NSDictionary *)data.fontInfo.fontAttributeDictionary.get()]; + font = [NSFont fontWithDescriptor:fontDescriptor size:((pageScaleFactor != 1) ? [fontDescriptor pointSize] * pageScaleFactor : 0)]; + } else + font = [NSFont menuFontOfSize:0]; + + populate(items, font, textDirection); + + [m_popup.get() attachPopUpWithFrame:rect inView:m_webView]; + [m_popup.get() selectItemAtIndex:selectedIndex]; + [m_popup.get() setUserInterfaceLayoutDirection:textDirection == LTR ? NSUserInterfaceLayoutDirectionLeftToRight : NSUserInterfaceLayoutDirectionRightToLeft]; + + NSMenu *menu = [m_popup.get() menu]; + + // These values were borrowed from AppKit to match their placement of the menu. + const int popOverHorizontalAdjust = -10; + const int popUnderHorizontalAdjust = 6; + const int popUnderVerticalAdjust = 6; + + // Menus that pop-over directly obscure the node that generated the popup menu. + // Menus that pop-under are offset underneath it. + NSPoint location; + if (data.shouldPopOver) { + NSRect titleFrame = [m_popup.get() titleRectForBounds:rect]; + if (titleFrame.size.width <= 0 || titleFrame.size.height <= 0) + titleFrame = rect; + float vertOffset = roundf((NSMaxY(rect) - NSMaxY(titleFrame)) + NSHeight(titleFrame)); + location = NSMakePoint(NSMinX(rect) + popOverHorizontalAdjust, NSMaxY(rect) - vertOffset); + } else + location = NSMakePoint(NSMinX(rect) + popUnderHorizontalAdjust, NSMaxY(rect) + popUnderVerticalAdjust); + + RetainPtr<NSView> dummyView(AdoptNS, [[NSView alloc] initWithFrame:rect]); + [m_webView addSubview:dummyView.get()]; + location = [dummyView.get() convertPoint:location fromView:m_webView]; + + WKPopupMenu(menu, location, roundf(NSWidth(rect)), dummyView.get(), selectedIndex, font); + + [m_popup.get() dismissPopUp]; + [dummyView.get() removeFromSuperview]; + + if (!m_client) + return; + + m_client->valueChangedForPopupMenu(this, [m_popup.get() indexOfSelectedItem]); + + // <https://bugs.webkit.org/show_bug.cgi?id=57904> This code is adopted from EventHandler::sendFakeEventsAfterWidgetTracking(). + if (!m_client->currentlyProcessedMouseDownEvent()) + return; + + NSEvent* initiatingNSEvent = m_client->currentlyProcessedMouseDownEvent()->nativeEvent(); + if ([initiatingNSEvent type] != NSLeftMouseDown) + return; + + NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSLeftMouseUp + location:[initiatingNSEvent locationInWindow] + modifierFlags:[initiatingNSEvent modifierFlags] + timestamp:[initiatingNSEvent timestamp] + windowNumber:[initiatingNSEvent windowNumber] + context:[initiatingNSEvent context] + eventNumber:[initiatingNSEvent eventNumber] + clickCount:[initiatingNSEvent clickCount] + pressure:[initiatingNSEvent pressure]]; + + [NSApp postEvent:fakeEvent atStart:YES]; + fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved + location:[[m_webView window] convertScreenToBase:[NSEvent mouseLocation]] + modifierFlags:[initiatingNSEvent modifierFlags] + timestamp:[initiatingNSEvent timestamp] + windowNumber:[initiatingNSEvent windowNumber] + context:[initiatingNSEvent context] + eventNumber:0 + clickCount:0 + pressure:0]; + [NSApp postEvent:fakeEvent atStart:YES]; +} + +void WebPopupMenuProxyMac::hidePopupMenu() +{ + [m_popup.get() dismissPopUp]; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/WebPreferencesMac.mm b/Source/WebKit2/UIProcess/mac/WebPreferencesMac.mm new file mode 100644 index 000000000..f2f41d331 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebPreferencesMac.mm @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebPreferences.h" + +#import "PageClientImpl.h" +#import <wtf/text/StringConcatenate.h> + +namespace WebKit { + +static inline NSString* makeKey(const String& identifier, const String& baseKey) +{ + return nsStringFromWebCoreString(makeString(identifier, ".WebKit2", baseKey)); +} + +static void setStringValueIfInUserDefaults(const String& identifier, const String& key, WebPreferencesStore& store) +{ + id object = [[NSUserDefaults standardUserDefaults] objectForKey:makeKey(identifier, key)]; + if (!object) + return; + if (![object isKindOfClass:[NSString class]]) + return; + + store.setStringValueForKey(key, (NSString *)object); +} + +static void setBoolValueIfInUserDefaults(const String& identifier, const String& key, WebPreferencesStore& store) +{ + id object = [[NSUserDefaults standardUserDefaults] objectForKey:makeKey(identifier, key)]; + if (!object) + return; + if (![object respondsToSelector:@selector(boolValue)]) + return; + + store.setBoolValueForKey(key, [object boolValue]); +} + +static void setUInt32ValueIfInUserDefaults(const String& identifier, const String& key, WebPreferencesStore& store) +{ + id object = [[NSUserDefaults standardUserDefaults] objectForKey:makeKey(identifier, key)]; + if (!object) + return; + if (![object respondsToSelector:@selector(intValue)]) + return; + + store.setUInt32ValueForKey(key, [object intValue]); +} + +static void setDoubleValueIfInUserDefaults(const String& identifier, const String& key, WebPreferencesStore& store) +{ + id object = [[NSUserDefaults standardUserDefaults] objectForKey:makeKey(identifier, key)]; + if (!object) + return; + if (![object respondsToSelector:@selector(doubleValue)]) + return; + + store.setDoubleValueForKey(key, [object doubleValue]); +} + +void WebPreferences::platformInitializeStore() +{ + if (!m_identifier) + return; + +#define INITIALIZE_PREFERENCE_FROM_NSUSERDEFAULTS(KeyUpper, KeyLower, TypeName, Type, DefaultValue) \ + set##TypeName##ValueIfInUserDefaults(m_identifier, WebPreferencesKey::KeyLower##Key(), m_store); + + FOR_EACH_WEBKIT_PREFERENCE(INITIALIZE_PREFERENCE_FROM_NSUSERDEFAULTS) + +#undef INITIALIZE_PREFERENCE_FROM_NSUSERDEFAULTS +} + +void WebPreferences::platformUpdateStringValueForKey(const String& key, const String& value) +{ + if (!m_identifier) + return; + + [[NSUserDefaults standardUserDefaults] setObject:nsStringFromWebCoreString(value) forKey:makeKey(m_identifier, key)]; +} + +void WebPreferences::platformUpdateBoolValueForKey(const String& key, bool value) +{ + if (!m_identifier) + return; + + [[NSUserDefaults standardUserDefaults] setBool:value forKey:makeKey(m_identifier, key)]; +} + +void WebPreferences::platformUpdateUInt32ValueForKey(const String& key, uint32_t value) +{ + if (!m_identifier) + return; + + [[NSUserDefaults standardUserDefaults] setInteger:value forKey:makeKey(m_identifier, key)]; +} + +void WebPreferences::platformUpdateDoubleValueForKey(const String& key, double value) +{ + if (!m_identifier) + return; + + [[NSUserDefaults standardUserDefaults] setDouble:value forKey:makeKey(m_identifier, key)]; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/mac/WebProcessProxyMac.mm b/Source/WebKit2/UIProcess/mac/WebProcessProxyMac.mm new file mode 100644 index 000000000..467155e92 --- /dev/null +++ b/Source/WebKit2/UIProcess/mac/WebProcessProxyMac.mm @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebProcessProxy.h" + +#import "SecItemRequestData.h" +#import "SecItemResponseData.h" +#import "SecKeychainItemRequestData.h" +#import "SecKeychainItemResponseData.h" +#import "WKFullKeyboardAccessWatcher.h" +#import <Security/SecItem.h> + +namespace WebKit { + +void WebProcessProxy::secItemCopyMatching(const SecItemRequestData& queryData, SecItemResponseData& result) +{ + CFDictionaryRef query = queryData.query(); + CFTypeRef resultObjectRef; + OSStatus resultCode = SecItemCopyMatching(query, &resultObjectRef); + + RetainPtr<CFTypeRef> resultObject(AdoptCF, resultObjectRef); + result = SecItemResponseData(resultCode, resultObject.get()); +} + +void WebProcessProxy::secItemAdd(const SecItemRequestData& queryData, SecItemResponseData& result) +{ + CFDictionaryRef query = queryData.query(); + CFTypeRef resultObjectRef; + OSStatus resultCode = SecItemAdd(query, &resultObjectRef); + + RetainPtr<CFTypeRef> resultObject(AdoptCF, resultObjectRef); + result = SecItemResponseData(resultCode, resultObject.get()); +} + +void WebProcessProxy::secItemUpdate(const SecItemRequestData& queryData, SecItemResponseData& result) +{ + CFDictionaryRef query = queryData.query(); + CFDictionaryRef attributesToMatch = queryData.attributesToMatch(); + OSStatus resultCode; + + resultCode = SecItemUpdate(query, attributesToMatch); + + result = SecItemResponseData(resultCode, 0); +} + +void WebProcessProxy::secItemDelete(const SecItemRequestData& queryData, SecItemResponseData& result) +{ + CFDictionaryRef query = queryData.query(); + OSStatus resultCode; + + resultCode = SecItemDelete(query); + + result = SecItemResponseData(resultCode, 0); +} + +void WebProcessProxy::secKeychainItemCopyContent(const SecKeychainItemRequestData& request, SecKeychainItemResponseData& response) +{ + SecKeychainItemRef item = request.keychainItem(); + SecItemClass itemClass; + SecKeychainAttributeList* attrList = request.attributeList(); + UInt32 length = 0; + void* outData = 0; + + OSStatus resultCode = SecKeychainItemCopyContent(item, &itemClass, attrList, &length, &outData); + + RetainPtr<CFDataRef> data(AdoptCF, CFDataCreate(0, static_cast<const UInt8*>(outData), length)); + response = SecKeychainItemResponseData(resultCode, itemClass, attrList, data.get()); + + SecKeychainItemFreeContent(attrList, outData); +} + +void WebProcessProxy::secKeychainItemCreateFromContent(const SecKeychainItemRequestData& request, SecKeychainItemResponseData& response) +{ + SecKeychainItemRef keychainItem; + + OSStatus resultCode = SecKeychainItemCreateFromContent(request.itemClass(), request.attributeList(), request.length(), request.data(), 0, 0, &keychainItem); + + response = SecKeychainItemResponseData(resultCode, RetainPtr<SecKeychainItemRef>(AdoptCF, keychainItem)); +} + +void WebProcessProxy::secKeychainItemModifyContent(const SecKeychainItemRequestData& request, SecKeychainItemResponseData& response) +{ + OSStatus resultCode = SecKeychainItemModifyContent(request.keychainItem(), request.attributeList(), request.length(), request.data()); + + response = resultCode; +} + +bool WebProcessProxy::fullKeyboardAccessEnabled() +{ + return [WKFullKeyboardAccessWatcher fullKeyboardAccessEnabled]; +} + +} // namespace WebKit |
