blob: 73280c0449728f962ee1a16f655bf357c9c7fc31 [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 "unix/ibus/surrounding_text_util.h"
#include <limits>
#include <string>
#include "base/logging.h"
#include "base/port.h"
#include "base/util.h"
namespace mozc {
namespace ibus {
bool SurroundingTextUtil::GetSafeDelta(guint from, guint to, int32 *delta) {
DCHECK(delta);
static_assert(sizeof(int64) >= sizeof(guint),
"int64 must be sufficient to store a guint value.");
static_assert(sizeof(int64) == sizeof(llabs(0)),
"|llabs(0)| must returns a 64-bit integer.");
const int64 kInt32AbsMax =
llabs(static_cast<int64>(numeric_limits<int32>::max()));
const int64 kInt32AbsMin =
llabs(static_cast<int64>(numeric_limits<int32>::min()));
const int64 kInt32SafeAbsMax =
min(kInt32AbsMax, kInt32AbsMin);
const int64 diff = static_cast<int64>(from) - static_cast<int64>(to);
if (llabs(diff) > kInt32SafeAbsMax) {
return false;
}
*delta = static_cast<int32>(diff);
return true;
}
namespace {
// Moves |iter| with |skip_count| characters.
// Returns false if |iter| reaches to the end before skipping
// |skip_count| characters.
bool Skip(ConstChar32Iterator *iter, size_t skip_count) {
for (size_t i = 0; i < skip_count; ++i) {
if (iter->Done()) {
return false;
}
iter->Next();
}
return true;
}
// Returns true if |prefix_iter| is the prefix of |iter|.
// Returns false if |prefix_iter| is an empty sequence.
// Otherwise returns false.
// This function receives ConstChar32Iterator as pointer because
// ConstChar32Iterator is defined as non-copyable.
bool StartsWith(ConstChar32Iterator *iter,
ConstChar32Iterator *prefix_iter) {
if (iter->Done() || prefix_iter->Done()) {
return false;
}
while (true) {
if (iter->Get() != prefix_iter->Get()) {
return false;
}
prefix_iter->Next();
if (prefix_iter->Done()) {
return true;
}
iter->Next();
if (iter->Done()) {
return false;
}
}
}
// Returns true if |surrounding_text| contains |selected_text|
// from |cursor_pos| to |*anchor_pos|.
// Otherwise returns false.
bool SearchAnchorPosForward(
const string &surrounding_text,
const string &selected_text,
size_t selected_chars_len,
guint cursor_pos,
guint *anchor_pos) {
ConstChar32Iterator iter(surrounding_text);
// Move |iter| to cursor pos.
if (!Skip(&iter, cursor_pos)) {
return false;
}
ConstChar32Iterator sel_iter(selected_text);
if (!StartsWith(&iter, &sel_iter)) {
return false;
}
*anchor_pos = cursor_pos + selected_chars_len;
return true;
}
// Returns true if |surrounding_text| contains |selected_text|
// from |*anchor_pos| to |cursor_pos|.
// Otherwise returns false.
bool SearchAnchorPosBackward(
const string &surrounding_text,
const string &selected_text,
size_t selected_chars_len,
guint cursor_pos,
guint *anchor_pos) {
if (cursor_pos < selected_chars_len) {
return false;
}
ConstChar32Iterator iter(surrounding_text);
// Skip |iter| to (potential) anchor pos.
const guint skip_count = cursor_pos - selected_chars_len;
DCHECK_LE(skip_count, cursor_pos);
if (!Skip(&iter, skip_count)) {
return false;
}
ConstChar32Iterator sel_iter(selected_text);
if (!StartsWith(&iter, &sel_iter)) {
return false;
}
*anchor_pos = cursor_pos - selected_chars_len;
return true;
}
} // namespace
bool SurroundingTextUtil::GetAnchorPosFromSelection(
const string &surrounding_text,
const string &selected_text,
guint cursor_pos,
guint *anchor_pos) {
DCHECK(anchor_pos);
if (surrounding_text.empty()) {
return false;
}
if (selected_text.empty()) {
return false;
}
const size_t selected_chars_len = Util::CharsLen(selected_text);
if (SearchAnchorPosForward(surrounding_text, selected_text,
selected_chars_len,
cursor_pos, anchor_pos)) {
return true;
}
return SearchAnchorPosBackward(surrounding_text, selected_text,
selected_chars_len,
cursor_pos, anchor_pos);
}
} // namespace ibus
} // namespace mozc