diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 | 
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 | 
| commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
| tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebKit2/UIProcess/mac | |
| download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz | |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
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  | 
