blob: 0f894d0f3e4490618f2db3a11fe125edb526c650 [file] [log] [blame]
// Copyright 2010-2015, Google 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:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
// OWNER OR 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.
#include "win32/tip/tip_candidate_list.h"
#include <Windows.h>
#define _ATL_NO_AUTOMATIC_NAMESPACE
#define _WTL_NO_AUTOMATIC_NAMESPACE
#include <atlbase.h>
#include <atlcom.h>
#include <ctffunc.h>
#include <memory>
#include <vector>
#include "base/util.h"
#include "win32/tip/tip_ref_count.h"
using ::ATL::CComPtr;
using ::std::unique_ptr;
namespace mozc {
namespace win32 {
namespace tsf {
namespace {
class CandidateStringImpl : public ITfCandidateString {
public:
CandidateStringImpl(ULONG index, const wstring &value)
: index_(index),
value_(value) {
}
// The IUnknown interface methods.
virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &interface_id,
void **object) {
if (!object) {
return E_INVALIDARG;
}
// Find a matching interface from the ones implemented by this object.
// This object implements IUnknown and ITfEditSession.
if (::IsEqualIID(interface_id, IID_IUnknown)) {
*object = static_cast<IUnknown *>(this);
} else if (IsEqualIID(interface_id, IID_ITfCandidateString)) {
*object = static_cast<ITfCandidateString *>(this);
} else {
*object = nullptr;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
virtual ULONG STDMETHODCALLTYPE AddRef() {
return ref_count_.AddRefImpl();
}
virtual ULONG STDMETHODCALLTYPE Release() {
const ULONG count = ref_count_.ReleaseImpl();
if (count == 0) {
delete this;
}
return count;
}
private:
// The ITfCandidateString interface methods.
virtual HRESULT STDMETHODCALLTYPE GetString(BSTR *str) {
if (str == nullptr) {
return E_INVALIDARG;
}
*str = ::SysAllocStringLen(value_.data(), value_.size());
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetIndex(ULONG *index) {
if (index == nullptr) {
return E_INVALIDARG;
}
*index = index_;
return S_OK;
}
TipRefCount ref_count_;
const ULONG index_;
const wstring value_;
DISALLOW_COPY_AND_ASSIGN(CandidateStringImpl);
};
class EnumTfCandidatesImpl : public IEnumTfCandidates {
public:
explicit EnumTfCandidatesImpl(const vector<wstring> &candidates)
: candidates_(candidates),
current_(0) {
}
// The IUnknown interface methods.
virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &interface_id,
void **object) {
if (!object) {
return E_INVALIDARG;
}
// Find a matching interface from the ones implemented by this object.
// This object implements IUnknown and ITfEditSession.
if (::IsEqualIID(interface_id, IID_IUnknown)) {
*object = static_cast<IUnknown *>(this);
} else if (IsEqualIID(interface_id, IID_IEnumTfCandidates)) {
*object = static_cast<IEnumTfCandidates *>(this);
} else {
*object = nullptr;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
virtual ULONG STDMETHODCALLTYPE AddRef() {
return ref_count_.AddRefImpl();
}
virtual ULONG STDMETHODCALLTYPE Release() {
const ULONG count = ref_count_.ReleaseImpl();
if (count == 0) {
delete this;
}
return count;
}
private:
virtual HRESULT STDMETHODCALLTYPE Clone(IEnumTfCandidates **enum_candidates) {
if (enum_candidates == nullptr) {
return E_INVALIDARG;
}
*enum_candidates = new EnumTfCandidatesImpl(candidates_);
(*enum_candidates)->AddRef();
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Next(ULONG count,
ITfCandidateString **candidate_string,
ULONG *fetched_count) {
if (candidate_string == nullptr) {
return E_INVALIDARG;
}
ULONG dummy = 0;
if (fetched_count == nullptr) {
fetched_count = &dummy;
}
const auto candidates_size = candidates_.size();
*fetched_count = 0;
for (ULONG i = 0; i < count; ++i) {
if (current_ >= candidates_size) {
*fetched_count = i;
return S_FALSE;
}
candidate_string[i] = new CandidateStringImpl(current_,
candidates_[current_]);
candidate_string[i]->AddRef();
++current_;
}
*fetched_count = count;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Reset() {
current_ = 0;
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE Skip(ULONG count) {
if ((candidates_.size() - current_) < count) {
current_ = candidates_.size();
return S_FALSE;
}
current_ += count;
return S_OK;
}
TipRefCount ref_count_;
vector<wstring> candidates_;
size_t current_;
DISALLOW_COPY_AND_ASSIGN(EnumTfCandidatesImpl);
};
class CandidateListImpl : public ITfCandidateList {
public:
CandidateListImpl(const vector<wstring> &candidates,
TipCandidateListCallback *callback)
: candidates_(candidates),
callback_(callback) {
}
// The IUnknown interface methods.
virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID &interface_id,
void **object) {
if (!object) {
return E_INVALIDARG;
}
// Find a matching interface from the ones implemented by this object.
// This object implements IUnknown and ITfEditSession.
if (::IsEqualIID(interface_id, IID_IUnknown)) {
*object = static_cast<IUnknown *>(this);
} else if (IsEqualIID(interface_id, IID_ITfCandidateList)) {
*object = static_cast<ITfCandidateList *>(this);
} else {
*object = nullptr;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
virtual ULONG STDMETHODCALLTYPE AddRef() {
return ref_count_.AddRefImpl();
}
virtual ULONG STDMETHODCALLTYPE Release() {
const ULONG count = ref_count_.ReleaseImpl();
if (count == 0) {
delete this;
}
return count;
}
private:
// The ITfCandidateList interface methods.
virtual HRESULT STDMETHODCALLTYPE EnumCandidates(
IEnumTfCandidates **enum_candidate) {
if (enum_candidate == nullptr) {
return E_INVALIDARG;
}
*enum_candidate = new EnumTfCandidatesImpl(candidates_);
(*enum_candidate)->AddRef();
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetCandidate(
ULONG index,
ITfCandidateString **candidate_string) {
if (candidate_string == nullptr) {
return E_INVALIDARG;
}
if (index >= candidates_.size()) {
return E_FAIL;
}
*candidate_string = new CandidateStringImpl(index, candidates_[index]);
(*candidate_string)->AddRef();
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE GetCandidateNum(ULONG *count) {
if (count == nullptr) {
return E_INVALIDARG;
}
*count = static_cast<ULONG>(candidates_.size());
return S_OK;
}
virtual HRESULT STDMETHODCALLTYPE SetResult(
ULONG index,
TfCandidateResult candidate_result) {
if (candidates_.size() <= index) {
return E_INVALIDARG;
}
if ((candidate_result == CAND_FINALIZED) && (callback_.get() != nullptr)) {
callback_->OnFinalize(index, candidates_[index]);
callback_.reset();
}
return S_OK;
}
TipRefCount ref_count_;
vector<wstring> candidates_;
unique_ptr<TipCandidateListCallback> callback_;
DISALLOW_COPY_AND_ASSIGN(CandidateListImpl);
};
} // namespace
TipCandidateListCallback::~TipCandidateListCallback() {
}
// static
ITfCandidateList *TipCandidateList::New(const vector<wstring> &candidates,
TipCandidateListCallback *callback) {
return new CandidateListImpl(candidates, callback);
}
} // namespace tsf
} // namespace win32
} // namespace mozc