aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-07-05 19:48:49 +0800
committercrupest <crupest@outlook.com>2020-07-05 19:48:49 +0800
commitbbec59718bf8a824583869126762013112f8e568 (patch)
tree1c0917e7c12a7af9ff3482f452a9da684a74ed81
parentce56ab59a6d68c220fcc47c6977c618eaa43de7a (diff)
downloadcru-bbec59718bf8a824583869126762013112f8e568.tar.gz
cru-bbec59718bf8a824583869126762013112f8e568.tar.bz2
cru-bbec59718bf8a824583869126762013112f8e568.zip
...
-rw-r--r--include/cru/common/StringUtil.hpp39
-rw-r--r--include/cru/platform/GraphBase.hpp1
-rw-r--r--include/cru/ui/Base.hpp4
-rw-r--r--include/cru/ui/UiEvent.hpp5
-rw-r--r--include/cru/ui/render/ScrollRenderObject.hpp3
-rw-r--r--include/cru/win/String.hpp46
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/StringUtil.cpp69
-rw-r--r--src/ui/CMakeLists.txt1
-rw-r--r--src/ui/UiEvent.cpp10
-rw-r--r--src/ui/controls/TextControlService.hpp72
-rw-r--r--src/ui/render/ScrollRenderObject.cpp5
-rw-r--r--src/win/String.cpp89
13 files changed, 202 insertions, 144 deletions
diff --git a/include/cru/common/StringUtil.hpp b/include/cru/common/StringUtil.hpp
new file mode 100644
index 00000000..a44ae6b4
--- /dev/null
+++ b/include/cru/common/StringUtil.hpp
@@ -0,0 +1,39 @@
+#pragma once
+#include "Base.hpp"
+
+namespace cru {
+using CodePoint = std::int32_t;
+constexpr CodePoint k_code_point_end = -1;
+
+class TextEncodeException : public std::runtime_error {
+ public:
+ using runtime_error::runtime_error;
+};
+
+class Utf8Iterator : public Object {
+ public:
+ explicit Utf8Iterator(const std::string_view& string) : string_(string) {}
+ Utf8Iterator(const std::string_view& string, Index position)
+ : string_(string), position_(position) {}
+
+ CRU_DEFAULT_COPY(Utf8Iterator)
+ CRU_DEFAULT_MOVE(Utf8Iterator)
+
+ ~Utf8Iterator() = default;
+
+ public:
+ void SetToHead() { position_ = 0; }
+ void SetPosition(Index position) { position_ = position; }
+
+ // Advance current position and get next code point. Return k_code_point_end
+ // if there is no next code unit(point). Throw TextEncodeException if decoding
+ // fails.
+ CodePoint Next();
+
+ Index CurrentPosition() const { return this->position_; }
+
+ private:
+ std::string_view string_;
+ Index position_ = 0;
+};
+} // namespace cru
diff --git a/include/cru/platform/GraphBase.hpp b/include/cru/platform/GraphBase.hpp
index 0d4effd4..28dab1e6 100644
--- a/include/cru/platform/GraphBase.hpp
+++ b/include/cru/platform/GraphBase.hpp
@@ -249,6 +249,7 @@ struct TextRange final {
constexpr TextRange(const gsl::index position, const gsl::index count = 0)
: position(position), count(count) {}
+ gsl::index GetStart() const { return position; }
gsl::index GetEnd() const { return position + count; }
TextRange Normalize() const {
diff --git a/include/cru/ui/Base.hpp b/include/cru/ui/Base.hpp
index c59d1b60..9036a47b 100644
--- a/include/cru/ui/Base.hpp
+++ b/include/cru/ui/Base.hpp
@@ -185,6 +185,10 @@ class Control;
class ClickDetector;
class UiHost;
+namespace render {
+class RenderObject;
+}
+
//-------------------- region: basic types --------------------
namespace internal {
constexpr int align_start = 0;
diff --git a/include/cru/ui/UiEvent.hpp b/include/cru/ui/UiEvent.hpp
index 79d0f7e3..39f26aee 100644
--- a/include/cru/ui/UiEvent.hpp
+++ b/include/cru/ui/UiEvent.hpp
@@ -13,10 +13,6 @@ namespace cru::platform::graph {
struct IPainter;
}
-namespace cru::ui {
-class Control;
-}
-
namespace cru::ui::event {
class UiEventArgs : public Object {
public:
@@ -88,6 +84,7 @@ class MouseEventArgs : public UiEventArgs {
// This point is relative to window client lefttop.
Point GetPoint() const { return point_.value_or(Point{}); }
+ Point GetPointToContent(render::RenderObject* render_target) const;
private:
std::optional<Point> point_;
diff --git a/include/cru/ui/render/ScrollRenderObject.hpp b/include/cru/ui/render/ScrollRenderObject.hpp
index 0c1fb16b..20b7278c 100644
--- a/include/cru/ui/render/ScrollRenderObject.hpp
+++ b/include/cru/ui/render/ScrollRenderObject.hpp
@@ -28,6 +28,9 @@ class ScrollRenderObject : public RenderObject {
void SetScrollOffset(const Point& offset);
Point GetRawScrollOffset() const { return scroll_offset_; }
+ // Rect lefttop relative to content rect.
+ void ScrollToContain(const Rect& rect);
+
protected:
void OnDrawCore(platform::graph::IPainter* painter) override;
diff --git a/include/cru/win/String.hpp b/include/cru/win/String.hpp
index 3d68cff7..ac07f57b 100644
--- a/include/cru/win/String.hpp
+++ b/include/cru/win/String.hpp
@@ -16,7 +16,7 @@ way.)
#pragma once
#include "WinPreConfig.hpp"
-#include "cru/common/Base.hpp"
+#include "cru/common/StringUtil.hpp"
#include <cstdint>
#include <stdexcept>
@@ -37,38 +37,6 @@ inline bool IsSurrogatePairTrailing(wchar_t c) {
return c >= 0xDC00 && c <= 0xDFFF;
}
-using CodePoint = std::int32_t;
-constexpr CodePoint k_code_point_end = -1;
-
-class TextEncodeException : public std::runtime_error {
- public:
- using runtime_error::runtime_error;
-};
-
-class Utf8Iterator : public Object {
- public:
- Utf8Iterator(const std::string_view& string) : string_(string) {}
-
- CRU_DEFAULT_COPY(Utf8Iterator)
- CRU_DEFAULT_MOVE(Utf8Iterator)
-
- ~Utf8Iterator() = default;
-
- public:
- void SetToHead() { position_ = 0; }
-
- // Advance current position and get next code point. Return k_code_point_end
- // if there is no next code unit(point). Throw TextEncodeException if decoding
- // fails.
- CodePoint Next();
-
- int CurrentPosition() const { return this->position_; }
-
- private:
- std::string_view string_;
- int position_ = 0;
-};
-
class Utf16Iterator : public Object {
static_assert(
sizeof(wchar_t) == 2,
@@ -91,17 +59,17 @@ class Utf16Iterator : public Object {
// fails.
CodePoint Next();
- int CurrentPosition() const { return this->position_; }
+ Index CurrentPosition() const { return this->position_; }
private:
std::wstring_view string_;
- int position_ = 0;
+ Index position_ = 0;
};
-int IndexUtf8ToUtf16(const std::string_view& utf8_string, int utf8_index,
- const std::wstring_view& utf16_string);
+Index IndexUtf8ToUtf16(const std::string_view& utf8_string, Index utf8_index,
+ const std::wstring_view& utf16_string);
-int IndexUtf16ToUtf8(const std::wstring_view& utf16_string, int utf16_index,
- const std::string_view& utf8_string);
+Index IndexUtf16ToUtf8(const std::wstring_view& utf16_string, Index utf16_index,
+ const std::string_view& utf8_string);
} // namespace cru::platform::win
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d53b9740..6a18ef2b 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -1,6 +1,7 @@
set(CRU_BASE_INCLUDE_DIR ${CRU_INCLUDE_DIR}/cru/common)
add_library(cru_base STATIC
Logger.cpp
+ StringUtil.cpp
)
target_sources(cru_base PUBLIC
${CRU_BASE_INCLUDE_DIR}/Base.hpp
@@ -9,6 +10,7 @@ target_sources(cru_base PUBLIC
${CRU_BASE_INCLUDE_DIR}/Logger.hpp
${CRU_BASE_INCLUDE_DIR}/PreConfig.hpp
${CRU_BASE_INCLUDE_DIR}/SelfResolvable.hpp
+ ${CRU_BASE_INCLUDE_DIR}/StringUtil.hpp
)
target_include_directories(cru_base PUBLIC ${CRU_INCLUDE_DIR})
target_compile_definitions(cru_base PUBLIC $<$<CONFIG:Debug>:CRU_DEBUG>)
diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp
new file mode 100644
index 00000000..31a5effd
--- /dev/null
+++ b/src/common/StringUtil.cpp
@@ -0,0 +1,69 @@
+#include "cru/common/StringUtil.hpp"
+
+namespace cru {
+template <typename UInt, int number_of_bit>
+inline std::enable_if_t<std::is_unsigned_v<UInt>, CodePoint> ExtractBits(
+ UInt n) {
+ return static_cast<CodePoint>(n & ((1u << number_of_bit) - 1));
+}
+
+CodePoint Utf8Iterator::Next() {
+ if (position_ == static_cast<Index>(string_.length()))
+ return k_code_point_end;
+
+ const auto cu0 = static_cast<std::uint8_t>(string_[position_++]);
+
+ auto read_next_folowing_code = [this]() -> CodePoint {
+ if (this->position_ == static_cast<Index>(string_.length()))
+ throw TextEncodeException(
+ "Unexpected end when read continuing byte of multi-byte code point.");
+
+#ifdef CRU_DEBUG
+ const auto u = static_cast<std::uint8_t>(string_[position_]);
+ if (!(u & (1u << 7)) || (u & (1u << 6))) {
+ throw TextEncodeException(
+ "Unexpected bad-format (not 0b10xxxxxx) continuing byte of "
+ "multi-byte code point.");
+ }
+#endif
+
+ return ExtractBits<std::uint8_t, 6>(string_[position_++]);
+ };
+
+ if ((1u << 7) & cu0) {
+ if ((1u << 6) & cu0) { // 2~4-length code point
+ if ((1u << 5) & cu0) { // 3~4-length code point
+ if ((1u << 4) & cu0) { // 4-length code point
+#ifdef CRU_DEBUG
+ if (cu0 & (1u << 3)) {
+ throw TextEncodeException(
+ "Unexpected bad-format begin byte (not 0b10xxxxxx) of 4-byte "
+ "code point.");
+ }
+#endif
+
+ const CodePoint s0 = ExtractBits<std::uint8_t, 3>(cu0) << (6 * 3);
+ const CodePoint s1 = read_next_folowing_code() << (6 * 2);
+ const CodePoint s2 = read_next_folowing_code() << 6;
+ const CodePoint s3 = read_next_folowing_code();
+ return s0 + s1 + s2 + s3;
+ } else { // 3-length code point
+ const CodePoint s0 = ExtractBits<std::uint8_t, 4>(cu0) << (6 * 2);
+ const CodePoint s1 = read_next_folowing_code() << 6;
+ const CodePoint s2 = read_next_folowing_code();
+ return s0 + s1 + s2;
+ }
+ } else { // 2-length code point
+ const CodePoint s0 = ExtractBits<std::uint8_t, 5>(cu0) << 6;
+ const CodePoint s1 = read_next_folowing_code();
+ return s0 + s1;
+ }
+ } else {
+ throw TextEncodeException(
+ "Unexpected bad-format (0b10xxxxxx) begin byte of a code point.");
+ }
+ } else {
+ return static_cast<CodePoint>(cu0);
+ }
+}
+} // namespace cru
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 954dacb0..6c50ec57 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -10,6 +10,7 @@ add_library(cru_ui STATIC
Helper.cpp
LayoutControl.cpp
NoChildControl.cpp
+ UiEvent.cpp
UiHost.cpp
UiManager.cpp
Window.cpp
diff --git a/src/ui/UiEvent.cpp b/src/ui/UiEvent.cpp
new file mode 100644
index 00000000..74dd54dc
--- /dev/null
+++ b/src/ui/UiEvent.cpp
@@ -0,0 +1,10 @@
+#include "cru/ui/UiEvent.hpp"
+
+#include "cru/ui/render/RenderObject.hpp"
+
+namespace cru::ui::event {
+Point MouseEventArgs::GetPointToContent(
+ render::RenderObject* render_object) const {
+ return render_object->FromRootToContent(GetPoint());
+}
+} // namespace cru::ui::event
diff --git a/src/ui/controls/TextControlService.hpp b/src/ui/controls/TextControlService.hpp
index 5fc8d987..94d9ebf8 100644
--- a/src/ui/controls/TextControlService.hpp
+++ b/src/ui/controls/TextControlService.hpp
@@ -78,11 +78,12 @@ class TextControlService : public Object {
}
}
- std::optional<TextRange> GetSelection() {
- return this->control_->GetTextRenderObject()->GetSelectionRange();
+ gsl::not_null<render::TextRenderObject*> GetTextRenderObject() {
+ return this->control_->GetTextRenderObject();
}
- void SetSelection(std::optional<TextRange> selection) {
- this->control_->GetTextRenderObject()->SetSelectionRange(selection);
+
+ render::ScrollRenderObject* GetScrollRenderObject() {
+ return this->control_->GetScrollRenderObject();
}
private:
@@ -91,7 +92,7 @@ class TextControlService : public Object {
this->control_->ReleaseMouse();
this->select_down_button_ = std::nullopt;
}
- this->control_->GetTextRenderObject()->SetSelectionRange(std::nullopt);
+ this->GetTextRenderObject()->SetSelectionRange(std::nullopt);
}
void SetupCaret() {
@@ -100,16 +101,16 @@ class TextControlService : public Object {
// Cancel first anyhow for safety.
application->CancelTimer(this->caret_timer_id_);
- this->control_->GetTextRenderObject()->SetDrawCaret(true);
+ this->GetTextRenderObject()->SetDrawCaret(true);
this->caret_timer_id_ = application->SetInterval(
std::chrono::milliseconds(this->caret_blink_duration_),
- [this] { this->control_->GetTextRenderObject()->ToggleDrawCaret(); });
+ [this] { this->GetTextRenderObject()->ToggleDrawCaret(); });
}
void TearDownCaret() {
const auto application = GetUiApplication();
application->CancelTimer(this->caret_timer_id_);
- this->control_->GetTextRenderObject()->SetDrawCaret(false);
+ this->GetTextRenderObject()->SetDrawCaret(false);
}
template <typename TArgs>
@@ -121,6 +122,29 @@ class TextControlService : public Object {
std::bind(handler, this, std::placeholders::_1))});
}
+ void StartSelection(Index start) {
+ const auto text_render_object = this->GetTextRenderObject();
+ text_render_object->SetSelectionRange(TextRange{start, 0});
+ text_render_object->SetCaretPosition(start);
+ log::TagDebug(log_tag, "Text selection started, position: {}.", position);
+ }
+
+ void UpdateSelection(Index new_end) {
+ if (!old_selection.has_value()) return;
+
+ const auto text_render_object = this->GetTextRenderObject();
+ const auto old_selection = text_render_object->GetSelectionRange();
+ const auto old_start = old_selection->GetStart();
+ this->GetTextRenderObject()->SetSelectionRange(
+ TextRange::FromTwoSides(old_start, new_end));
+ text_render_object->SetCaretPosition(new_end);
+ log::TagDebug(log_tag, "Text selection updated, range: {}, {}.", old_start,
+ new_end);
+ if (const auto scroll_render_object = this->GetScrollRenderObject()) {
+ //TODO: Implement this.
+ }
+ }
+
void SetupHandlers() {
Expects(event_revoker_guards_.empty());
@@ -130,22 +154,20 @@ class TextControlService : public Object {
&TextControlService::MouseDownHandler);
SetupOneHandler(&Control::MouseUpEvent,
&TextControlService::MouseUpHandler);
+ SetupOneHandler(&Control::KeyDownEvent,
+ &TextControlService::KeyDownHandler);
+ SetupOneHandler(&Control::KeyUpEvent, &TextControlService::KeyUpHandler);
SetupOneHandler(&Control::LoseFocusEvent,
&TextControlService::LoseFocusHandler);
}
void MouseMoveHandler(event::MouseEventArgs& args) {
if (this->select_down_button_.has_value()) {
- const auto text_render_object = this->control_->GetTextRenderObject();
+ const auto text_render_object = this->GetTextRenderObject();
const auto result = text_render_object->TextHitTest(
- text_render_object->FromRootToContent(args.GetPoint()));
+ args.GetPointToContent(text_render_object));
const auto position = result.position + (result.trailing ? 1 : 0);
- log::TagDebug(log_tag,
- "Text selection changed on mouse move, range: {}, {}.",
- position, this->select_start_position_);
- this->control_->GetTextRenderObject()->SetSelectionRange(
- TextRange::FromTwoSides(position, this->select_start_position_));
- text_render_object->SetCaretPosition(position);
+ UpdateSelection(position);
}
}
@@ -155,16 +177,12 @@ class TextControlService : public Object {
} else {
if (!this->control_->CaptureMouse()) return;
if (!this->control_->RequestFocus()) return;
- const auto text_render_object = this->control_->GetTextRenderObject();
+ const auto text_render_object = this->GetTextRenderObject();
this->select_down_button_ = args.GetButton();
const auto result = text_render_object->TextHitTest(
- text_render_object->FromRootToContent(args.GetPoint()));
+ args.GetPointToContent(text_render_object));
const auto position = result.position + (result.trailing ? 1 : 0);
- text_render_object->SetSelectionRange(std::nullopt);
- text_render_object->SetCaretPosition(position);
- this->select_start_position_ = position;
- log::TagDebug(log_tag, "Begin to select text, start position: {}.",
- position);
+ StartSelection(position);
}
}
@@ -173,10 +191,13 @@ class TextControlService : public Object {
this->select_down_button_.value() == args.GetButton()) {
this->control_->ReleaseMouse();
this->select_down_button_ = std::nullopt;
- log::TagDebug(log_tag, "End selecting text.");
}
}
+ void KeyDownHandler(event::KeyEventArgs& args) {}
+
+ void KeyUpHandler(event::KeyEventArgs& args) {}
+
void LoseFocusHandler(event::FocusChangeEventArgs& args) {
if (!args.IsWindow()) this->AbortSelection();
}
@@ -193,8 +214,5 @@ class TextControlService : public Object {
// nullopt means not selecting
std::optional<MouseButton> select_down_button_;
-
- // before the char
- int select_start_position_;
};
} // namespace cru::ui::controls
diff --git a/src/ui/render/ScrollRenderObject.cpp b/src/ui/render/ScrollRenderObject.cpp
index a367afd9..77367970 100644
--- a/src/ui/render/ScrollRenderObject.cpp
+++ b/src/ui/render/ScrollRenderObject.cpp
@@ -67,6 +67,11 @@ void ScrollRenderObject::SetScrollOffset(const Point& offset) {
InvalidateLayout();
}
+void ScrollToContain(const Rect& rect) {
+ // TODO: Implement this.
+ throw std::runtime_error("Not implemented.");
+}
+
Size ScrollRenderObject::OnMeasureContent(const MeasureRequirement& requirement,
const MeasureSize& preferred_size) {
if (const auto child = GetSingleChild()) {
diff --git a/src/win/String.cpp b/src/win/String.cpp
index 65a280f2..eb585523 100644
--- a/src/win/String.cpp
+++ b/src/win/String.cpp
@@ -54,74 +54,16 @@ inline std::enable_if_t<std::is_unsigned_v<UInt>, CodePoint> ExtractBits(
return static_cast<CodePoint>(n & ((1u << number_of_bit) - 1));
}
-CodePoint Utf8Iterator::Next() {
- if (position_ == static_cast<int>(string_.length())) return k_code_point_end;
-
- const auto cu0 = static_cast<std::uint8_t>(string_[position_++]);
-
- auto read_next_folowing_code = [this]() -> CodePoint {
- if (this->position_ == static_cast<int>(string_.length()))
- throw TextEncodeException(
- "Unexpected end when read continuing byte of multi-byte code point.");
-
-#ifdef CRU_DEBUG
- const auto u = static_cast<std::uint8_t>(string_[position_]);
- if (!(u & (1u << 7)) || (u & (1u << 6))) {
- throw TextEncodeException(
- "Unexpected bad-format (not 0b10xxxxxx) continuing byte of "
- "multi-byte code point.");
- }
-#endif
-
- return ExtractBits<std::uint8_t, 6>(string_[position_++]);
- };
-
- if ((1u << 7) & cu0) {
- if ((1u << 6) & cu0) { // 2~4-length code point
- if ((1u << 5) & cu0) { // 3~4-length code point
- if ((1u << 4) & cu0) { // 4-length code point
-#ifdef CRU_DEBUG
- if (cu0 & (1u << 3)) {
- throw TextEncodeException(
- "Unexpected bad-format begin byte (not 0b10xxxxxx) of 4-byte "
- "code point.");
- }
-#endif
-
- const CodePoint s0 = ExtractBits<std::uint8_t, 3>(cu0) << (6 * 3);
- const CodePoint s1 = read_next_folowing_code() << (6 * 2);
- const CodePoint s2 = read_next_folowing_code() << 6;
- const CodePoint s3 = read_next_folowing_code();
- return s0 + s1 + s2 + s3;
- } else { // 3-length code point
- const CodePoint s0 = ExtractBits<std::uint8_t, 4>(cu0) << (6 * 2);
- const CodePoint s1 = read_next_folowing_code() << 6;
- const CodePoint s2 = read_next_folowing_code();
- return s0 + s1 + s2;
- }
- } else { // 2-length code point
- const CodePoint s0 = ExtractBits<std::uint8_t, 5>(cu0) << 6;
- const CodePoint s1 = read_next_folowing_code();
- return s0 + s1;
- }
- } else {
- throw TextEncodeException(
- "Unexpected bad-format (0b10xxxxxx) begin byte of a code point.");
- }
- } else {
- return static_cast<CodePoint>(cu0);
- }
-}
-
CodePoint Utf16Iterator::Next() {
- if (position_ == static_cast<int>(string_.length())) return k_code_point_end;
+ if (position_ == static_cast<Index>(string_.length()))
+ return k_code_point_end;
const auto cu0 = static_cast<std::uint16_t>(string_[position_++]);
if (cu0 < 0xd800u || cu0 >= 0xe000u) { // 1-length code point
return static_cast<CodePoint>(cu0);
} else if (cu0 <= 0xdbffu) { // 2-length code point
- if (position_ == static_cast<int>(string_.length())) {
+ if (position_ == static_cast<Index>(string_.length())) {
throw TextEncodeException(
"Unexpected end when reading second code unit of surrogate pair.");
}
@@ -145,12 +87,12 @@ CodePoint Utf16Iterator::Next() {
}
}
-int IndexUtf8ToUtf16(const std::string_view& utf8_string, int utf8_index,
- const std::wstring_view& utf16_string) {
- if (utf8_index >= static_cast<int>(utf8_string.length()))
- return static_cast<int>(utf16_string.length());
+Index IndexUtf8ToUtf16(const std::string_view& utf8_string, Index utf8_index,
+ const std::wstring_view& utf16_string) {
+ if (utf8_index >= static_cast<Index>(utf8_string.length()))
+ return utf16_string.length();
- int cp_index = 0;
+ Index cp_index = 0;
Utf8Iterator iter{utf8_string};
while (iter.CurrentPosition() <= utf8_index) {
iter.Next();
@@ -158,19 +100,19 @@ int IndexUtf8ToUtf16(const std::string_view& utf8_string, int utf8_index,
}
Utf16Iterator result_iter{utf16_string};
- for (int i = 0; i < cp_index - 1; i++) {
+ for (Index i = 0; i < cp_index - 1; i++) {
if (result_iter.Next() == k_code_point_end) break;
}
return result_iter.CurrentPosition();
}
-int IndexUtf16ToUtf8(const std::wstring_view& utf16_string, int utf16_index,
- const std::string_view& utf8_string) {
- if (utf16_index >= static_cast<int>(utf16_string.length()))
- return static_cast<int>(utf8_string.length());
+Index IndexUtf16ToUtf8(const std::wstring_view& utf16_string, Index utf16_index,
+ const std::string_view& utf8_string) {
+ if (utf16_index >= static_cast<Index>(utf16_string.length()))
+ return utf8_string.length();
- int cp_index = 0;
+ Index cp_index = 0;
Utf16Iterator iter{utf16_string};
while (iter.CurrentPosition() <= utf16_index) {
iter.Next();
@@ -178,11 +120,10 @@ int IndexUtf16ToUtf8(const std::wstring_view& utf16_string, int utf16_index,
}
Utf8Iterator result_iter{utf8_string};
- for (int i = 0; i < cp_index - 1; i++) {
+ for (Index i = 0; i < cp_index - 1; i++) {
if (result_iter.Next() == k_code_point_end) break;
}
return result_iter.CurrentPosition();
}
-
} // namespace cru::platform::win