Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #import "config.h"
     27 #if !defined(BUILDING_ON_SNOW_LEOPARD)
     28 #import "CorrectionPanel.h"
     29 
     30 #import "WebPageProxy.h"
     31 #import "WKView.h"
     32 #import "WKViewPrivate.h"
     33 
     34 using namespace WebCore;
     35 
     36 static inline NSCorrectionIndicatorType correctionIndicatorType(CorrectionPanelInfo::PanelType panelType)
     37 {
     38     switch (panelType) {
     39     case CorrectionPanelInfo::PanelTypeCorrection:
     40         return NSCorrectionIndicatorTypeDefault;
     41     case CorrectionPanelInfo::PanelTypeReversion:
     42         return NSCorrectionIndicatorTypeReversion;
     43     case CorrectionPanelInfo::PanelTypeSpellingSuggestions:
     44         return NSCorrectionIndicatorTypeGuesses;
     45     }
     46     ASSERT_NOT_REACHED();
     47     return NSCorrectionIndicatorTypeDefault;
     48 }
     49 
     50 namespace WebKit {
     51 
     52 CorrectionPanel::CorrectionPanel()
     53     : m_wasDismissedExternally(false)
     54     , m_reasonForDismissing(ReasonForDismissingCorrectionPanelIgnored)
     55     , m_resultCondition(AdoptNS, [[NSCondition alloc] init])
     56 {
     57 }
     58 
     59 CorrectionPanel::~CorrectionPanel()
     60 {
     61     dismissInternal(ReasonForDismissingCorrectionPanelIgnored, false);
     62 }
     63 
     64 void CorrectionPanel::show(WKView* view, CorrectionPanelInfo::PanelType type, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
     65 {
     66     dismissInternal(ReasonForDismissingCorrectionPanelIgnored, false);
     67 
     68     if (!view)
     69         return;
     70 
     71     NSString* replacedStringAsNSString = replacedString;
     72     NSString* replacementStringAsNSString = replacementString;
     73     m_view = view;
     74     NSCorrectionIndicatorType indicatorType = correctionIndicatorType(type);
     75 
     76     NSMutableArray* alternativeStrings = 0;
     77     if (!alternativeReplacementStrings.isEmpty()) {
     78         size_t size = alternativeReplacementStrings.size();
     79         alternativeStrings = [NSMutableArray arrayWithCapacity:size];
     80         for (size_t i = 0; i < size; ++i)
     81             [alternativeStrings addObject:(NSString*)alternativeReplacementStrings[i]];
     82     }
     83 
     84     NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker];
     85     [spellChecker showCorrectionIndicatorOfType:indicatorType primaryString:replacementStringAsNSString alternativeStrings:alternativeStrings forStringInRect:boundingBoxOfReplacedString view:m_view.get() completionHandler:^(NSString* acceptedString) {
     86         handleAcceptedReplacement(acceptedString, replacedStringAsNSString, replacementStringAsNSString, indicatorType);
     87     }];
     88 }
     89 
     90 void CorrectionPanel::dismiss(ReasonForDismissingCorrectionPanel reason)
     91 {
     92     dismissInternal(reason, true);
     93 }
     94 
     95 String CorrectionPanel::dismissSoon(ReasonForDismissingCorrectionPanel reason)
     96 {
     97     if (!isShowing())
     98         return String();
     99 
    100     dismissInternal(reason, true);
    101     [m_resultCondition.get() lock];
    102     while (!m_resultForSynchronousDismissal)
    103         [m_resultCondition.get() wait];
    104     [m_resultCondition.get() unlock];
    105     return m_resultForSynchronousDismissal.get();
    106 }
    107 
    108 void CorrectionPanel::dismissInternal(ReasonForDismissingCorrectionPanel reason, bool dismissingExternally)
    109 {
    110     m_wasDismissedExternally = dismissingExternally;
    111     if (!isShowing())
    112         return;
    113 
    114     m_reasonForDismissing = reason;
    115     m_resultForSynchronousDismissal.clear();
    116     [[NSSpellChecker sharedSpellChecker] dismissCorrectionIndicatorForView:m_view.get()];
    117     m_view.clear();
    118 }
    119 
    120 void CorrectionPanel::recordAutocorrectionResponse(WKView* view, NSCorrectionResponse response, const String& replacedString, const String& replacementString)
    121 {
    122     [[NSSpellChecker sharedSpellChecker] recordResponse:response toCorrection:replacementString forWord:replacedString language:nil inSpellDocumentWithTag:[view spellCheckerDocumentTag]];
    123 }
    124 
    125 void CorrectionPanel::handleAcceptedReplacement(NSString* acceptedReplacement, NSString* replaced, NSString* proposedReplacement,  NSCorrectionIndicatorType correctionIndicatorType)
    126 {
    127     NSSpellChecker* spellChecker = [NSSpellChecker sharedSpellChecker];
    128     NSInteger documentTag = [m_view.get() spellCheckerDocumentTag];
    129 
    130     switch (correctionIndicatorType) {
    131     case NSCorrectionIndicatorTypeDefault:
    132         if (acceptedReplacement)
    133             [spellChecker recordResponse:NSCorrectionResponseAccepted toCorrection:acceptedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag];
    134         else {
    135             if (!m_wasDismissedExternally || m_reasonForDismissing == ReasonForDismissingCorrectionPanelCancelled)
    136                 [spellChecker recordResponse:NSCorrectionResponseRejected toCorrection:proposedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag];
    137             else
    138                 [spellChecker recordResponse:NSCorrectionResponseIgnored toCorrection:proposedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag];
    139         }
    140         break;
    141     case NSCorrectionIndicatorTypeReversion:
    142         if (acceptedReplacement)
    143             [spellChecker recordResponse:NSCorrectionResponseReverted toCorrection:replaced forWord:acceptedReplacement language:nil inSpellDocumentWithTag:documentTag];
    144         break;
    145     case NSCorrectionIndicatorTypeGuesses:
    146         if (acceptedReplacement)
    147             [spellChecker recordResponse:NSCorrectionResponseAccepted toCorrection:acceptedReplacement forWord:replaced language:nil inSpellDocumentWithTag:documentTag];
    148         break;
    149     }
    150 
    151     if (!m_wasDismissedExternally) {
    152         [m_view.get() handleCorrectionPanelResult:acceptedReplacement];
    153         return;
    154     }
    155 
    156     [m_resultCondition.get() lock];
    157     if (acceptedReplacement)
    158         m_resultForSynchronousDismissal.adoptNS([acceptedReplacement copy]);
    159     [m_resultCondition.get() signal];
    160     [m_resultCondition.get() unlock];
    161 }
    162 
    163 } // namespace WebKit
    164 
    165 #endif //!defined(BUILDING_ON_SNOW_LEOPARD)
    166 
    167