diff options
author | Yuqian Yang <crupest@crupest.life> | 2025-10-17 21:50:24 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-10-17 21:50:24 +0800 |
commit | 728d592f4075ae78b67dab6911ada05875a470a3 (patch) | |
tree | 57a7232ea0a984b0344bc63a593c1dee65072d2f | |
parent | 045462a6aed2796976a2f5cf0042f9a0ac1493f7 (diff) | |
download | cru-728d592f4075ae78b67dab6911ada05875a470a3.tar.gz cru-728d592f4075ae78b67dab6911ada05875a470a3.tar.bz2 cru-728d592f4075ae78b67dab6911ada05875a470a3.zip |
Fix macOS build.
36 files changed, 242 insertions, 121 deletions
diff --git a/include/cru/base/Osx.h b/include/cru/base/Osx.h index fbdffc54..e42a4fe5 100644 --- a/include/cru/base/Osx.h +++ b/include/cru/base/Osx.h @@ -7,9 +7,10 @@ #endif #include "Range.h" -#include "String.h" #include <CoreFoundation/CoreFoundation.h> +#include <string> +#include <string_view> namespace cru { template <typename CFClassRef> @@ -29,8 +30,8 @@ class CFWrapper { } }; -CFWrapper<CFStringRef> ToCFString(StringView string); -String FromCFStringRef(CFStringRef string); +CFWrapper<CFStringRef> ToCFString(std::string_view string); +std::string FromCFStringRef(CFStringRef string); CFRange ToCFRange(const Range& range); Range FromCFRange(const CFRange& range); diff --git a/include/cru/base/StringUtil.h b/include/cru/base/StringUtil.h index 54e7b6e6..8c7841d7 100644 --- a/include/cru/base/StringUtil.h +++ b/include/cru/base/StringUtil.h @@ -375,4 +375,9 @@ class CodePointIterator { using Utf8CodePointIterator = CodePointIterator<char, &Utf8NextCodePoint>; using Utf16CodePointIterator = CodePointIterator<Utf16CodeUnit, &Utf16NextCodePoint>; + +Index Utf8IndexCodeUnitToCodePoint(const Utf8CodeUnit* ptr, Index size, Index position); +Index Utf8IndexCodePointToCodeUnit(const Utf8CodeUnit* ptr, Index size, Index position); +Index Utf16IndexCodeUnitToCodePoint(const Utf16CodeUnit* ptr, Index size, Index position); +Index Utf16IndexCodePointToCodeUnit(const Utf16CodeUnit* ptr, Index size, Index position); } // namespace cru::string diff --git a/include/cru/platform/Color.h b/include/cru/platform/Color.h index 53252cc4..f7c82dec 100644 --- a/include/cru/platform/Color.h +++ b/include/cru/platform/Color.h @@ -2,8 +2,10 @@ #include "Base.h" #include <cru/base/Base.h> +#include <cru/base/StringUtil.h> #include <cstdint> +#include <format> #include <optional> #include <string_view> @@ -248,6 +250,10 @@ struct std::hash<cru::platform::Color> { } }; +template <> +struct std::formatter<cru::platform::Color, char> + : cru::string::ImplementFormatterByToString<cru::platform::Color> {}; + namespace cru::platform { std::optional<Color> GetPredefinedColorByName(std::string_view name); diff --git a/include/cru/platform/graphics/quartz/Brush.h b/include/cru/platform/graphics/quartz/Brush.h index 9b29ef59..73aa2f6d 100644 --- a/include/cru/platform/graphics/quartz/Brush.h +++ b/include/cru/platform/graphics/quartz/Brush.h @@ -36,7 +36,7 @@ class QuartzSolidColorBrush : public QuartzBrush, void Select(CGContextRef context) override; - String GetDebugString() override; + std::string GetDebugString() override; private: Color color_; diff --git a/include/cru/platform/graphics/quartz/Convert.h b/include/cru/platform/graphics/quartz/Convert.h index c5a1a6cc..fd6159a6 100644 --- a/include/cru/platform/graphics/quartz/Convert.h +++ b/include/cru/platform/graphics/quartz/Convert.h @@ -1,6 +1,4 @@ #pragma once -#include "cru/base/Range.h" -#include "cru/base/String.h" #include "cru/base/io/Stream.h" #include "cru/platform/Matrix.h" diff --git a/include/cru/platform/graphics/quartz/Factory.h b/include/cru/platform/graphics/quartz/Factory.h index 042e35ca..61d8dbdb 100644 --- a/include/cru/platform/graphics/quartz/Factory.h +++ b/include/cru/platform/graphics/quartz/Factory.h @@ -21,11 +21,11 @@ class QuartzGraphicsFactory : public OsxQuartzResource, std::unique_ptr<IGeometryBuilder> CreateGeometryBuilder() override; - std::unique_ptr<IFont> CreateFont(String font_family, + std::unique_ptr<IFont> CreateFont(std::string font_family, float font_size) override; std::unique_ptr<ITextLayout> CreateTextLayout(std::shared_ptr<IFont> font, - String text) override; + std::string text) override; IImageFactory* GetImageFactory() override; diff --git a/include/cru/platform/graphics/quartz/Font.h b/include/cru/platform/graphics/quartz/Font.h index 975607b9..d110b59b 100644 --- a/include/cru/platform/graphics/quartz/Font.h +++ b/include/cru/platform/graphics/quartz/Font.h @@ -8,7 +8,7 @@ namespace cru::platform::graphics::quartz { class OsxCTFont : public OsxQuartzResource, public virtual IFont { public: - OsxCTFont(IGraphicsFactory* graphics_factory, const String& name, float size); + OsxCTFont(IGraphicsFactory* graphics_factory, const std::string& name, float size); CRU_DELETE_COPY(OsxCTFont) CRU_DELETE_MOVE(OsxCTFont) @@ -17,11 +17,11 @@ class OsxCTFont : public OsxQuartzResource, public virtual IFont { CTFontRef GetCTFont() const { return ct_font_; } - String GetFontName() override; + std::string GetFontName() override; float GetFontSize() override; private: - String name_; + std::string name_; CTFontRef ct_font_; }; } // namespace cru::platform::graphics::quartz diff --git a/include/cru/platform/graphics/quartz/Resource.h b/include/cru/platform/graphics/quartz/Resource.h index d28e4055..23fe6fa9 100644 --- a/include/cru/platform/graphics/quartz/Resource.h +++ b/include/cru/platform/graphics/quartz/Resource.h @@ -1,7 +1,7 @@ #pragma once -#include "cru/platform/osx/Resource.h" #include "cru/platform/graphics/Base.h" #include "cru/platform/graphics/Resource.h" +#include "cru/platform/osx/Resource.h" namespace cru::platform::graphics::quartz { class OsxQuartzResource : public platform::osx::OsxResource, @@ -15,7 +15,7 @@ class OsxQuartzResource : public platform::osx::OsxResource, ~OsxQuartzResource() override = default; public: - String GetPlatformId() const override { return u"OSX Quartz"; } + std::string GetPlatformId() const override { return "OSX Quartz"; } IGraphicsFactory* GetGraphicsFactory() override { return graphics_factory_; } diff --git a/include/cru/platform/graphics/quartz/TextLayout.h b/include/cru/platform/graphics/quartz/TextLayout.h index bbb417f6..e53ee464 100644 --- a/include/cru/platform/graphics/quartz/TextLayout.h +++ b/include/cru/platform/graphics/quartz/TextLayout.h @@ -11,7 +11,7 @@ namespace cru::platform::graphics::quartz { class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout { public: OsxCTTextLayout(IGraphicsFactory* graphics_factory, - std::shared_ptr<OsxCTFont> font, const String& str); + std::shared_ptr<OsxCTFont> font, const std::string& str); CRU_DELETE_COPY(OsxCTTextLayout) CRU_DELETE_MOVE(OsxCTTextLayout) @@ -19,8 +19,8 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout { ~OsxCTTextLayout() override; public: - String GetText() override { return text_; } - void SetText(String new_text) override; + std::string GetText() override { return text_; } + void SetText(std::string new_text) override; std::shared_ptr<IFont> GetFont() override { return font_; } void SetFont(std::shared_ptr<IFont> font) override; @@ -46,10 +46,10 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout { Matrix GetTransform() { return transform_; } - String GetDebugString() override; + std::string GetDebugString() override; private: - void DoSetText(String text); + void DoSetText(std::string text); void ReleaseResource(); void RecreateFrame(); @@ -68,8 +68,8 @@ class OsxCTTextLayout : public OsxQuartzResource, public virtual ITextLayout { std::shared_ptr<OsxCTFont> font_; - String text_; - String actual_text_; + std::string text_; + std::string actual_text_; CFMutableAttributedStringRef cf_attributed_text_; CTFramesetterRef ct_framesetter_ = nullptr; diff --git a/include/cru/platform/gui/osx/Clipboard.h b/include/cru/platform/gui/osx/Clipboard.h index b4dcce4c..6672f84d 100644 --- a/include/cru/platform/gui/osx/Clipboard.h +++ b/include/cru/platform/gui/osx/Clipboard.h @@ -22,8 +22,8 @@ class OsxClipboard : public OsxGuiResource, public virtual IClipboard { ~OsxClipboard() override; public: - String GetText() override; - void SetText(String text) override; + std::string GetText() override; + void SetText(std::string text) override; private: std::unique_ptr<details::OsxClipboardPrivate> p_; diff --git a/include/cru/platform/gui/osx/InputMethod.h b/include/cru/platform/gui/osx/InputMethod.h index cbfdae6c..067d86ea 100644 --- a/include/cru/platform/gui/osx/InputMethod.h +++ b/include/cru/platform/gui/osx/InputMethod.h @@ -46,7 +46,7 @@ class OsxInputMethodContext : public OsxGuiResource, IEvent<std::nullptr_t>* CompositionEvent() override; - IEvent<StringView>* TextEvent() override; + IEvent<std::string>* TextEvent() override; bool IsEnabled(); diff --git a/include/cru/platform/gui/osx/Menu.h b/include/cru/platform/gui/osx/Menu.h index c5cc756a..05f21e1c 100644 --- a/include/cru/platform/gui/osx/Menu.h +++ b/include/cru/platform/gui/osx/Menu.h @@ -25,8 +25,8 @@ class OsxMenuItem : public OsxGuiResource, public virtual IMenuItem { ~OsxMenuItem() override; public: - String GetTitle() override; - void SetTitle(String title) override; + std::string GetTitle() override; + void SetTitle(std::string title) override; bool IsEnabled() override; void SetEnabled(bool enabled) override; IMenu* GetParentMenu() override; diff --git a/include/cru/platform/gui/osx/Resource.h b/include/cru/platform/gui/osx/Resource.h index 1eec7d09..1253544c 100644 --- a/include/cru/platform/gui/osx/Resource.h +++ b/include/cru/platform/gui/osx/Resource.h @@ -1,7 +1,7 @@ #pragma once #include "cru/platform/osx/Resource.h" -#include "cru/platform/gui/Base.h" +#include <cru/platform/gui/UiApplication.h> namespace cru::platform::gui::osx { class OsxGuiResource : public platform::osx::OsxResource { @@ -14,7 +14,7 @@ class OsxGuiResource : public platform::osx::OsxResource { ~OsxGuiResource() override = default; public: - String GetPlatformId() const override { return u"OSX GUI"; } + std::string GetPlatformId() const override { return "OSX GUI"; } IUiApplication* GetUiApplication() const { return ui_application_; } diff --git a/include/cru/platform/gui/osx/UiApplication.h b/include/cru/platform/gui/osx/UiApplication.h index 2d2c119c..f0e311dc 100644 --- a/include/cru/platform/gui/osx/UiApplication.h +++ b/include/cru/platform/gui/osx/UiApplication.h @@ -51,9 +51,9 @@ class OsxUiApplication : public OsxGuiResource, public virtual IUiApplication { IMenu* GetApplicationMenu() override; - std::optional<String> ShowSaveDialog(SaveDialogOptions options) override; + std::optional<std::string> ShowSaveDialog(SaveDialogOptions options) override; - std::optional<std::vector<String>> ShowOpenDialog( + std::optional<std::vector<std::string>> ShowOpenDialog( OpenDialogOptions options) override; private: diff --git a/include/cru/platform/gui/osx/Window.h b/include/cru/platform/gui/osx/Window.h index 6cefbe8e..d00136b0 100644 --- a/include/cru/platform/gui/osx/Window.h +++ b/include/cru/platform/gui/osx/Window.h @@ -36,8 +36,8 @@ class OsxWindow : public OsxGuiResource, public INativeWindow { WindowStyleFlag GetStyleFlag() override; void SetStyleFlag(WindowStyleFlag flag) override; - String GetTitle() override; - void SetTitle(String title) override; + std::string GetTitle() override; + void SetTitle(std::string title) override; WindowVisibilityType GetVisibility() override; void SetVisibility(WindowVisibilityType visibility) override; diff --git a/include/cru/platform/osx/Resource.h b/include/cru/platform/osx/Resource.h index d30ee31b..4a3b6b7d 100644 --- a/include/cru/platform/osx/Resource.h +++ b/include/cru/platform/osx/Resource.h @@ -4,10 +4,6 @@ namespace cru::platform::osx { class OsxResource : public Object, public virtual IPlatformResource { public: - CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(OsxResource) - CRU_DELETE_COPY(OsxResource) - CRU_DELETE_MOVE(OsxResource) - - String GetPlatformId() const override { return u"OSX"; } + std::string GetPlatformId() const override { return "OSX"; } }; } // namespace cru::platform::osx diff --git a/src/base/Osx.cpp b/src/base/Osx.cpp index 46b923fe..d979f542 100644 --- a/src/base/Osx.cpp +++ b/src/base/Osx.cpp @@ -1,19 +1,22 @@ #include "cru/base/Osx.h" +#include "cru/base/StringUtil.h" namespace cru { -CFWrapper<CFStringRef> ToCFString(StringView string) { +CFWrapper<CFStringRef> ToCFString(std::string_view string) { return CFWrapper<CFStringRef>(CFStringCreateWithBytes( nullptr, reinterpret_cast<const UInt8*>(string.data()), - string.size() * sizeof(std::uint16_t), kCFStringEncodingUTF16, false)); + string.size() * sizeof(char), kCFStringEncodingUTF8, false)); } -String FromCFStringRef(CFStringRef string) { +std::string FromCFStringRef(CFStringRef string) { auto length = CFStringGetLength(string); - String result; + std::string result; for (int i = 0; i < length; i++) { - result.AppendCodePoint(CFStringGetCharacterAtIndex(string, i)); + cru::string::Utf8EncodeCodePointAppend( + CFStringGetCharacterAtIndex(string, i), + [&result](char c) { result += c; }); } return result; diff --git a/src/base/StringUtil.cpp b/src/base/StringUtil.cpp index 581ebcab..4cd662d1 100644 --- a/src/base/StringUtil.cpp +++ b/src/base/StringUtil.cpp @@ -357,4 +357,51 @@ Index Utf16NextWord(const Utf16CodeUnit* ptr, Index size, Index position, ptr, size, position, is_space); } +template <typename CharType, + NextCodePointFunctionType<CharType> NextCodePointFunction> +static Index IndexCodeUnitToCodePoint(const CharType* ptr, Index size, + Index position) { + CodePointIterator<CharType, NextCodePointFunction> iter(ptr, size); + Index result = 0; + while (!iter.IsPastEnd() && iter.GetPosition() < position) { + ++iter; + ++result; + } + return result; +} + +template <typename CharType, + NextCodePointFunctionType<CharType> NextCodePointFunction> +static Index IndexCodePointToCodeUnit(const CharType* ptr, Index size, + Index position) { + CodePointIterator<CharType, NextCodePointFunction> iter(ptr, size); + for (Index i = 0; i < position; i++) { + ++iter; + } + return iter.GetPosition(); +} + +Index Utf8IndexCodeUnitToCodePoint(const Utf8CodeUnit* ptr, Index size, + Index position) { + return IndexCodeUnitToCodePoint<Utf8CodeUnit, Utf8NextCodePoint>(ptr, size, + position); +} + +Index Utf8IndexCodePointToCodeUnit(const Utf8CodeUnit* ptr, Index size, + Index position) { + return IndexCodePointToCodeUnit<Utf8CodeUnit, Utf8NextCodePoint>(ptr, size, + position); +} + +Index Utf16IndexCodeUnitToCodePoint(const Utf16CodeUnit* ptr, Index size, + Index position) { + return IndexCodeUnitToCodePoint<Utf16CodeUnit, Utf16NextCodePoint>(ptr, size, + position); +} +Index Utf16IndexCodePointToCodeUnit(const Utf16CodeUnit* ptr, Index size, + Index position) { + return IndexCodePointToCodeUnit<Utf16CodeUnit, Utf16NextCodePoint>(ptr, size, + position); +} + } // namespace cru::string diff --git a/src/base/io/Stream.cpp b/src/base/io/Stream.cpp index 1aafc839..e07f2899 100644 --- a/src/base/io/Stream.cpp +++ b/src/base/io/Stream.cpp @@ -1,7 +1,9 @@ #include "cru/base/io/Stream.h" #include "cru/base/Exception.h" +#include <algorithm> #include <format> +#include <iterator> #include <utility> namespace cru::io { @@ -193,6 +195,10 @@ Buffer Stream::ReadToEnd(Index grow_size) { std::string Stream::ReadToEndAsUtf8String() { auto buffer = ReadToEnd(); - return std::string(buffer.GetUsedBeginPtr(), buffer.GetUsedEndPtr()); + std::string result; + std::transform(buffer.GetUsedBeginPtr(), buffer.GetUsedEndPtr(), + std::back_inserter(result), + [](std::byte c) { return static_cast<char>(c); }); + return result; } } // namespace cru::io diff --git a/src/platform/graphics/quartz/Brush.cpp b/src/platform/graphics/quartz/Brush.cpp index ea740eb3..c5784e51 100644 --- a/src/platform/graphics/quartz/Brush.cpp +++ b/src/platform/graphics/quartz/Brush.cpp @@ -1,6 +1,5 @@ #include "cru/platform/graphics/quartz/Brush.h" -#include "cru/base/String.h" -#include "cru/base/Format.h" +#include <format> namespace cru::platform::graphics::quartz { QuartzSolidColorBrush::QuartzSolidColorBrush(IGraphicsFactory* graphics_factory, @@ -30,7 +29,7 @@ void QuartzSolidColorBrush::Select(CGContextRef context) { CGContextSetFillColorWithColor(context, cg_color_); } -String QuartzSolidColorBrush::GetDebugString() { - return Format(u"QuartzSolidColorBrush(Color: {})", color_); +std::string QuartzSolidColorBrush::GetDebugString() { + return std::format("QuartzSolidColorBrush(Color: {})", color_); } } // namespace cru::platform::graphics::quartz diff --git a/src/platform/graphics/quartz/Convert.cpp b/src/platform/graphics/quartz/Convert.cpp index 06720982..06699b0c 100644 --- a/src/platform/graphics/quartz/Convert.cpp +++ b/src/platform/graphics/quartz/Convert.cpp @@ -1,5 +1,4 @@ #include "cru/platform/graphics/quartz/Convert.h" -#include <cstdint> namespace cru::platform::graphics::quartz { diff --git a/src/platform/graphics/quartz/Factory.cpp b/src/platform/graphics/quartz/Factory.cpp index 862c0966..69e9c607 100644 --- a/src/platform/graphics/quartz/Factory.cpp +++ b/src/platform/graphics/quartz/Factory.cpp @@ -1,12 +1,12 @@ #include "cru/platform/graphics/quartz/Factory.h" +#include "cru/platform/Check.h" +#include "cru/platform/graphics/ImageFactory.h" #include "cru/platform/graphics/quartz/Brush.h" #include "cru/platform/graphics/quartz/Font.h" #include "cru/platform/graphics/quartz/Geometry.h" #include "cru/platform/graphics/quartz/ImageFactory.h" #include "cru/platform/graphics/quartz/TextLayout.h" -#include "cru/platform/Check.h" -#include "cru/platform/graphics/ImageFactory.h" #include <memory> @@ -26,13 +26,13 @@ QuartzGraphicsFactory::CreateGeometryBuilder() { return std::make_unique<QuartzGeometryBuilder>(this); } -std::unique_ptr<IFont> QuartzGraphicsFactory::CreateFont(String font_family, - float font_size) { +std::unique_ptr<IFont> QuartzGraphicsFactory::CreateFont( + std::string font_family, float font_size) { return std::make_unique<OsxCTFont>(this, font_family, font_size); } std::unique_ptr<ITextLayout> QuartzGraphicsFactory::CreateTextLayout( - std::shared_ptr<IFont> font, String text) { + std::shared_ptr<IFont> font, std::string text) { auto f = CheckPlatform<OsxCTFont>(font, GetPlatformId()); return std::make_unique<OsxCTTextLayout>(this, f, text); } diff --git a/src/platform/graphics/quartz/Font.cpp b/src/platform/graphics/quartz/Font.cpp index 0c03e5e0..12a8aa7f 100644 --- a/src/platform/graphics/quartz/Font.cpp +++ b/src/platform/graphics/quartz/Font.cpp @@ -4,8 +4,8 @@ #include "cru/platform/graphics/quartz/Resource.h" namespace cru::platform::graphics::quartz { -OsxCTFont::OsxCTFont(IGraphicsFactory* graphics_factory, const String& name, - float size) +OsxCTFont::OsxCTFont(IGraphicsFactory* graphics_factory, + const std::string& name, float size) : OsxQuartzResource(graphics_factory), name_(name) { auto n = ToCFString(name); @@ -20,6 +20,6 @@ OsxCTFont::OsxCTFont(IGraphicsFactory* graphics_factory, const String& name, OsxCTFont::~OsxCTFont() { CFRelease(ct_font_); } -String OsxCTFont::GetFontName() { return name_; } +std::string OsxCTFont::GetFontName() { return name_; } float OsxCTFont::GetFontSize() { return CTFontGetSize(ct_font_); } } // namespace cru::platform::graphics::quartz diff --git a/src/platform/graphics/quartz/Image.cpp b/src/platform/graphics/quartz/Image.cpp index d4ccd416..a6c7c65b 100644 --- a/src/platform/graphics/quartz/Image.cpp +++ b/src/platform/graphics/quartz/Image.cpp @@ -36,7 +36,7 @@ std::unique_ptr<IPainter> QuartzImage::CreatePainter() { if (!buffer_) throw Exception( "Failed to create painter for image because failed to get its " - u"buffer."); + "buffer."); auto width = CGImageGetWidth(image_); auto height = CGImageGetHeight(image_); diff --git a/src/platform/graphics/quartz/ImageFactory.cpp b/src/platform/graphics/quartz/ImageFactory.cpp index 2090828c..69fa502d 100644 --- a/src/platform/graphics/quartz/ImageFactory.cpp +++ b/src/platform/graphics/quartz/ImageFactory.cpp @@ -30,14 +30,14 @@ std::unique_ptr<IImage> QuartzImageFactory::DecodeFromStream( new QuartzImage(GetGraphicsFactory(), this, cg_image, true)); } -static String GetImageFormatUniformTypeIdentifier(ImageFormat format) { +static std::string GetImageFormatUniformTypeIdentifier(ImageFormat format) { switch (format) { case ImageFormat::Png: - return u"public.png"; + return "public.png"; case ImageFormat::Jpeg: - return u"public.jpeg"; + return "public.jpeg"; case ImageFormat::Gif: - return u"com.compuserve.gif"; + return "com.compuserve.gif"; default: throw Exception("Unknown image format."); } diff --git a/src/platform/graphics/quartz/TextLayout.cpp b/src/platform/graphics/quartz/TextLayout.cpp index 8c573c7a..87f85b77 100644 --- a/src/platform/graphics/quartz/TextLayout.cpp +++ b/src/platform/graphics/quartz/TextLayout.cpp @@ -1,18 +1,19 @@ #include "cru/platform/graphics/quartz/TextLayout.h" #include "cru/base/Base.h" #include "cru/base/Osx.h" -#include "cru/base/Format.h" -#include "cru/platform/graphics/quartz/Convert.h" -#include "cru/platform/graphics/quartz/Resource.h" +#include "cru/base/StringUtil.h" #include "cru/platform/Check.h" #include "cru/platform/graphics/Base.h" +#include "cru/platform/graphics/quartz/Convert.h" +#include "cru/platform/graphics/quartz/Resource.h" +#include <format> #include <limits> namespace cru::platform::graphics::quartz { OsxCTTextLayout::OsxCTTextLayout(IGraphicsFactory* graphics_factory, std::shared_ptr<OsxCTFont> font, - const String& str) + const std::string& str) : OsxQuartzResource(graphics_factory), max_width_(std::numeric_limits<float>::max()), max_height_(std::numeric_limits<float>::max()), @@ -35,7 +36,7 @@ void OsxCTTextLayout::SetFont(std::shared_ptr<IFont> font) { RecreateFrame(); } -void OsxCTTextLayout::DoSetText(String text) { +void OsxCTTextLayout::DoSetText(std::string text) { text_ = std::move(text); if (text_.empty()) { @@ -67,14 +68,15 @@ void OsxCTTextLayout::DoSetText(String text) { head_empty_line_count_ = 1; actual_text_ = {}; } else { - actual_text_ = String(text_.cbegin() + head_empty_line_count_, - text_.cend() - tail_empty_line_count_); + actual_text_ = std::string(text_.cbegin() + head_empty_line_count_, + text_.cend() - tail_empty_line_count_); } } auto s = ToCFString(actual_text_); cf_attributed_text_ = CFAttributedStringCreateMutable(nullptr, 0); - CFAttributedStringReplaceString(cf_attributed_text_, CFRangeMake(0, 0), s.ref); + CFAttributedStringReplaceString(cf_attributed_text_, CFRangeMake(0, 0), + s.ref); Ensures(cf_attributed_text_); CFAttributedStringSetAttribute( cf_attributed_text_, @@ -82,7 +84,7 @@ void OsxCTTextLayout::DoSetText(String text) { kCTFontAttributeName, font_->GetCTFont()); } -void OsxCTTextLayout::SetText(String new_text) { +void OsxCTTextLayout::SetText(std::string new_text) { if (new_text == text_) return; CFRelease(cf_attributed_text_); @@ -199,10 +201,11 @@ TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) { if (point.y >= th) { for (int i = 1; i <= tail_empty_line_count_; ++i) { if (point.y < th + i * font_->GetFontSize()) { - return {text_.size() - (tail_empty_line_count_ - i), false, false}; + return {static_cast<Index>(text_.size() - (tail_empty_line_count_ - i)), + false, false}; } } - return {text_.size(), false, false}; + return {static_cast<Index>(text_.size()), false, false}; } auto p = point; @@ -236,24 +239,28 @@ TextHitTestResult OsxCTTextLayout::HitTest(const Point& point) { bool inside_text; if (pp.x < bounds.origin.x) { - po = actual_text_.IndexFromCodePointToCodeUnit(range.location); + po = cru::string::Utf8IndexCodePointToCodeUnit( + actual_text_.data(), actual_text_.size(), range.location); inside_text = false; } else if (pp.x > bounds.origin.x + bounds.size.width) { - po = actual_text_.IndexFromCodePointToCodeUnit(range.location + - range.length); + po = cru::string::Utf8IndexCodePointToCodeUnit( + actual_text_.data(), actual_text_.size(), + range.location + range.length); inside_text = false; } else { int position = CTLineGetStringIndexForPosition( line, CGPointMake(pp.x - line_origins_[i].x, pp.y - line_origins_[i].y)); - po = actual_text_.IndexFromCodePointToCodeUnit(position); + po = cru::string::Utf8IndexCodePointToCodeUnit( + actual_text_.data(), actual_text_.size(), position); inside_text = true; } if (po != 0 && - po == actual_text_.IndexFromCodePointToCodeUnit(range.location + - range.length) && + po == cru::string::Utf8IndexCodePointToCodeUnit( + actual_text_.data(), actual_text_.size(), + range.location + range.length) && actual_text_[po - 1] == u'\n') { --po; } @@ -357,15 +364,16 @@ CTFrameRef OsxCTTextLayout::CreateFrameWithColor(const Color& color) { return frame; } -String OsxCTTextLayout::GetDebugString() { - return Format(u"OsxCTTextLayout(text: {}, size: ({}, {}))", text_, max_width_, - max_height_); +std::string OsxCTTextLayout::GetDebugString() { + return std::format("OsxCTTextLayout(text: {}, size: ({}, {}))", text_, + max_width_, max_height_); } CGRect OsxCTTextLayout::DoGetTextBounds(bool includingTrailingSpace) { if (actual_text_.empty()) return CGRect{}; - auto rects = DoTextRangeRect(TextRange{0, actual_text_.size()}); + auto rects = + DoTextRangeRect(TextRange{0, static_cast<Index>(actual_text_.size())}); float left = std::numeric_limits<float>::max(); float bottom = std::numeric_limits<float>::max(); @@ -398,7 +406,12 @@ CGRect OsxCTTextLayout::DoGetTextBoundsIncludingEmptyLines( std::vector<CGRect> OsxCTTextLayout::DoTextRangeRect( const TextRange& text_range) { const auto r = - actual_text_.RangeFromCodeUnitToCodePoint(text_range).Normalize(); + Range::FromTwoSides( + cru::string::Utf8IndexCodeUnitToCodePoint( + actual_text_.data(), actual_text_.size(), text_range.position), + cru::string::Utf8IndexCodeUnitToCodePoint( + actual_text_.data(), actual_text_.size(), text_range.GetEnd())) + .Normalize(); std::vector<CGRect> results; @@ -430,7 +443,8 @@ CGRect OsxCTTextLayout::DoTextSinglePoint(Index position, bool trailing) { if (actual_text_.empty()) return CGRectMake(0, 0, 0, font_->GetFontSize()); - position = actual_text_.IndexFromCodeUnitToCodePoint(position); + position = cru::string::Utf8IndexCodeUnitToCodePoint( + actual_text_.data(), actual_text_.size(), position); for (int i = 0; i < line_count_; i++) { auto line = lines_[i]; diff --git a/src/platform/gui/osx/Clipboard.mm b/src/platform/gui/osx/Clipboard.mm index d87ab7e3..a09bca1c 100644 --- a/src/platform/gui/osx/Clipboard.mm +++ b/src/platform/gui/osx/Clipboard.mm @@ -13,30 +13,30 @@ OsxClipboard::OsxClipboard(cru::platform::gui::IUiApplication* ui_application, OsxClipboard::~OsxClipboard() {} -String OsxClipboard::GetText() { return p_->GetText(); } +std::string OsxClipboard::GetText() { return p_->GetText(); } -void OsxClipboard::SetText(String text) { p_->SetText(text); } +void OsxClipboard::SetText(std::string text) { p_->SetText(text); } namespace details { OsxClipboardPrivate::OsxClipboardPrivate(NSPasteboard* pasteboard) : pasteboard_(pasteboard) {} OsxClipboardPrivate::~OsxClipboardPrivate() {} -String OsxClipboardPrivate::GetText() { +std::string OsxClipboardPrivate::GetText() { auto result = [pasteboard_ readObjectsForClasses:@[ NSString.class ] options:nil]; if (result == nil) { CRU_LOG_TAG_WARN("Failed to get text from clipboard"); - return u""; + return ""; } else { if (result.count == 0) { - return u""; + return ""; } else { return FromCFStringRef((CFStringRef)result[0]); } } } -void OsxClipboardPrivate::SetText(String text) { +void OsxClipboardPrivate::SetText(std::string text) { auto cf_string = ToCFString(text); [pasteboard_ clearContents]; [pasteboard_ writeObjects:@[ (NSString*)cf_string.ref ]]; diff --git a/src/platform/gui/osx/ClipboardPrivate.h b/src/platform/gui/osx/ClipboardPrivate.h index 41554297..5019ba17 100644 --- a/src/platform/gui/osx/ClipboardPrivate.h +++ b/src/platform/gui/osx/ClipboardPrivate.h @@ -17,8 +17,8 @@ class OsxClipboardPrivate : public Object { ~OsxClipboardPrivate(); public: - String GetText(); - void SetText(String text); + std::string GetText(); + void SetText(std::string text); private: NSPasteboard* pasteboard_; diff --git a/src/platform/gui/osx/InputMethod.mm b/src/platform/gui/osx/InputMethod.mm index c3532ab6..c17dab3d 100644 --- a/src/platform/gui/osx/InputMethod.mm +++ b/src/platform/gui/osx/InputMethod.mm @@ -24,7 +24,7 @@ void OsxInputMethodContextPrivate::RaiseCompositionEndEvent() { } void OsxInputMethodContextPrivate::RaiseCompositionEvent() { composition_event_.Raise(nullptr); } -void OsxInputMethodContextPrivate::RaiseTextEvent(StringView text) { text_event_.Raise(text); } +void OsxInputMethodContextPrivate::RaiseTextEvent(std::string text) { text_event_.Raise(text); } void OsxInputMethodContextPrivate::PerformSel(SEL sel) { // [window_->p_->GetNSWindow() performSelector:sel]; @@ -77,7 +77,7 @@ IEvent<std::nullptr_t>* OsxInputMethodContext::CompositionEvent() { return &p_->composition_event_; } -IEvent<StringView>* OsxInputMethodContext::TextEvent() { return &p_->text_event_; } +IEvent<std::string>* OsxInputMethodContext::TextEvent() { return &p_->text_event_; } bool OsxInputMethodContext::IsEnabled() { return p_->is_enabled_; } } diff --git a/src/platform/gui/osx/InputMethodPrivate.h b/src/platform/gui/osx/InputMethodPrivate.h index ac2d1bf4..39f3be02 100644 --- a/src/platform/gui/osx/InputMethodPrivate.h +++ b/src/platform/gui/osx/InputMethodPrivate.h @@ -24,7 +24,7 @@ class OsxInputMethodContextPrivate { void RaiseCompositionStartEvent(); void RaiseCompositionEndEvent(); void RaiseCompositionEvent(); - void RaiseTextEvent(StringView text); + void RaiseTextEvent(std::string text); Point GetCandidateWindowPosition() const { return candidate_window_point_; } void SetCandidateWindowPosition(const Point& p) { @@ -56,7 +56,7 @@ class OsxInputMethodContextPrivate { Event<std::nullptr_t> composition_start_event_; Event<std::nullptr_t> composition_event_; Event<std::nullptr_t> composition_end_event_; - Event<StringView> text_event_; + Event<std::string> text_event_; bool is_enabled_ = false; }; diff --git a/src/platform/gui/osx/Keyboard.mm b/src/platform/gui/osx/Keyboard.mm index da4c85f0..ea1d2d4e 100644 --- a/src/platform/gui/osx/Keyboard.mm +++ b/src/platform/gui/osx/Keyboard.mm @@ -267,16 +267,16 @@ NSString* ConvertKeyCodeToKeyEquivalent(KeyCode key_code) { NSEventModifierFlags ConvertKeyModifier(KeyModifier k) { NSEventModifierFlags flags = 0; - if (k & KeyModifiers::shift) { + if (k & KeyModifiers::Shift) { flags |= NSEventModifierFlagShift; } - if (k & KeyModifiers::ctrl) { + if (k & KeyModifiers::Ctrl) { flags |= NSEventModifierFlagControl; } - if (k & KeyModifiers::alt) { + if (k & KeyModifiers::Alt) { flags |= NSEventModifierFlagOption; } - if (k & KeyModifiers::command) { + if (k & KeyModifiers::Command) { flags |= NSEventModifierFlagCommand; } return flags; diff --git a/src/platform/gui/osx/Menu.mm b/src/platform/gui/osx/Menu.mm index 45beddee..0eea19ec 100644 --- a/src/platform/gui/osx/Menu.mm +++ b/src/platform/gui/osx/Menu.mm @@ -60,9 +60,9 @@ OsxMenuItem::OsxMenuItem(IUiApplication* ui_application) : OsxGuiResource(ui_app OsxMenuItem::~OsxMenuItem() { delete p_; } -String OsxMenuItem::GetTitle() { return FromCFStringRef((CFStringRef)[p_->menu_item_ title]); } +std::string OsxMenuItem::GetTitle() { return FromCFStringRef((CFStringRef)[p_->menu_item_ title]); } -void OsxMenuItem::SetTitle(String title) { +void OsxMenuItem::SetTitle(std::string title) { auto cf_title = ToCFString(title); [p_->menu_item_ setTitle:(NSString*)(cf_title.ref)]; } diff --git a/src/platform/gui/osx/UiApplication.mm b/src/platform/gui/osx/UiApplication.mm index 7e744928..fca21075 100644 --- a/src/platform/gui/osx/UiApplication.mm +++ b/src/platform/gui/osx/UiApplication.mm @@ -177,7 +177,7 @@ graphics::IGraphicsFactory* OsxUiApplication::GetGraphicsFactory() { return p_->quartz_graphics_factory_.get(); } -std::optional<String> OsxUiApplication::ShowSaveDialog(SaveDialogOptions options) { +std::optional<std::string> OsxUiApplication::ShowSaveDialog(SaveDialogOptions options) { NSSavePanel* panel = [NSSavePanel savePanel]; [panel setTitle:(NSString*)ToCFString(options.title).ref]; [panel setPrompt:(NSString*)ToCFString(options.prompt).ref]; @@ -201,7 +201,7 @@ std::optional<String> OsxUiApplication::ShowSaveDialog(SaveDialogOptions options } } -std::optional<std::vector<String>> OsxUiApplication::ShowOpenDialog(OpenDialogOptions options) { +std::optional<std::vector<std::string>> OsxUiApplication::ShowOpenDialog(OpenDialogOptions options) { NSOpenPanel* panel = [NSOpenPanel openPanel]; [panel setTitle:(NSString*)ToCFString(options.title).ref]; [panel setPrompt:(NSString*)ToCFString(options.prompt).ref]; @@ -223,7 +223,7 @@ std::optional<std::vector<String>> OsxUiApplication::ShowOpenDialog(OpenDialogOp auto model_result = [panel runModal]; if (model_result == NSModalResponseOK) { - std::vector<String> result; + std::vector<std::string> result; for (NSURL* url in [panel URLs]) { result.push_back(FromCFStringRef((CFStringRef)[url path])); } diff --git a/src/platform/gui/osx/Window.mm b/src/platform/gui/osx/Window.mm index 6559cf70..65d31ab8 100644 --- a/src/platform/gui/osx/Window.mm +++ b/src/platform/gui/osx/Window.mm @@ -10,6 +10,7 @@ #include "cru/platform/graphics/NullPainter.h" #include "cru/platform/graphics/quartz/Convert.h" #include "cru/platform/graphics/quartz/Painter.h" +#include "cru/platform/gui/Input.h" #include "cru/platform/gui/TimerHelper.h" #include "cru/platform/gui/osx/Cursor.h" #include "cru/platform/gui/osx/InputMethod.h" @@ -29,7 +30,6 @@ constexpr int key_down_debug = 0; } using ::cru::FromCFStringRef; -using ::cru::ToCFString; using cru::platform::graphics::quartz::Convert; namespace cru::platform::gui::osx { namespace { @@ -250,9 +250,9 @@ void OsxWindow::SetStyleFlag(WindowStyleFlag flag) { } } -String OsxWindow::GetTitle() { return p_->title_; } +std::string OsxWindow::GetTitle() { return p_->title_; } -void OsxWindow::SetTitle(String title) { +void OsxWindow::SetTitle(std::string title) { p_->title_ = title; if (p_->window_) { @@ -401,13 +401,13 @@ namespace { cru::platform::gui::KeyModifier GetKeyModifier(NSEvent* event) { cru::platform::gui::KeyModifier key_modifier; if (event.modifierFlags & NSEventModifierFlagControl) - key_modifier |= cru::platform::gui::KeyModifiers::ctrl; + key_modifier |= cru::platform::gui::KeyModifiers::Ctrl; if (event.modifierFlags & NSEventModifierFlagOption) - key_modifier |= cru::platform::gui::KeyModifiers::alt; + key_modifier |= cru::platform::gui::KeyModifiers::Alt; if (event.modifierFlags & NSEventModifierFlagShift) - key_modifier |= cru::platform::gui::KeyModifiers::shift; + key_modifier |= cru::platform::gui::KeyModifiers::Shift; if (event.modifierFlags & NSEventModifierFlagCommand) - key_modifier |= cru::platform::gui::KeyModifiers::command; + key_modifier |= cru::platform::gui::KeyModifiers::Command; return key_modifier; } } // namespace @@ -504,28 +504,28 @@ cru::platform::gui::KeyModifier GetKeyModifier(NSEvent* event) { auto key_modifier = GetKeyModifier(event); cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - _p->OnMouseDown(cru::platform::gui::mouse_buttons::left, p, key_modifier); + _p->OnMouseDown(cru::platform::gui::MouseButtons::Left, p, key_modifier); } - (void)mouseUp:(NSEvent*)event { auto key_modifier = GetKeyModifier(event); cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - _p->OnMouseUp(cru::platform::gui::mouse_buttons::left, p, key_modifier); + _p->OnMouseUp(cru::platform::gui::MouseButtons::Left, p, key_modifier); } - (void)rightMouseDown:(NSEvent*)event { auto key_modifier = GetKeyModifier(event); cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - _p->OnMouseDown(cru::platform::gui::mouse_buttons::right, p, key_modifier); + _p->OnMouseDown(cru::platform::gui::MouseButtons::Right, p, key_modifier); } - (void)rightMouseUp:(NSEvent*)event { auto key_modifier = GetKeyModifier(event); cru::platform::Point p(event.locationInWindow.x, event.locationInWindow.y); - _p->OnMouseUp(cru::platform::gui::mouse_buttons::right, p, key_modifier); + _p->OnMouseUp(cru::platform::gui::MouseButtons::Right, p, key_modifier); } - (void)scrollWheel:(NSEvent*)event { @@ -611,17 +611,17 @@ const std::unordered_set<KeyCode> input_context_handle_codes_when_has_text{ if (input_context->IsEnabled()) { if (input_context_handle_codes.count(c) && - !(key_modifier & ~cru::platform::gui::KeyModifiers::shift)) { + !(key_modifier & ~cru::platform::gui::KeyModifiers::Shift)) { handled = [[self inputContext] handleEvent:event]; } else if (input_context_handle_codes_when_has_text.count(c) && !key_modifier) { if (!input_context->GetCompositionText().text.empty()) { handled = [[self inputContext] handleEvent:event]; } else { if (c == KeyCode::Return) { - _input_context_p->RaiseTextEvent(u"\n"); + _input_context_p->RaiseTextEvent("\n"); handled = true; } else if (c == KeyCode::Space) { - _input_context_p->RaiseTextEvent(u" "); + _input_context_p->RaiseTextEvent(" "); handled = true; } } @@ -688,9 +688,11 @@ const std::unordered_set<KeyCode> input_context_handle_codes_when_has_text{ cru::platform::gui::CompositionText composition_text; composition_text.text = FromCFStringRef((CFStringRef)[_input_context_text string]); - composition_text.selection.position = ss.IndexFromCodePointToCodeUnit(selectedRange.location); + composition_text.selection.position = + cru::string::Utf8IndexCodePointToCodeUnit(ss.data(), ss.size(), selectedRange.location); composition_text.selection.count = - ss.IndexFromCodePointToCodeUnit(selectedRange.location + selectedRange.length) - + cru::string::Utf8IndexCodePointToCodeUnit(ss.data(), ss.size(), + selectedRange.location + selectedRange.length) - composition_text.selection.position; _input_context_p->SetCompositionText(composition_text); _input_context_p->RaiseCompositionEvent(); diff --git a/src/platform/gui/osx/WindowPrivate.h b/src/platform/gui/osx/WindowPrivate.h index 478ce4e5..9e1b2a6c 100644 --- a/src/platform/gui/osx/WindowPrivate.h +++ b/src/platform/gui/osx/WindowPrivate.h @@ -83,7 +83,7 @@ class OsxWindowPrivate { INativeWindow* parent_ = nullptr; WindowStyleFlag style_flag_ = WindowStyleFlag{}; - String title_; + std::string title_; Rect content_rect_; diff --git a/test/base/StringUtilTest.cpp b/test/base/StringUtilTest.cpp index 32fd0d88..fda30627 100644 --- a/test/base/StringUtilTest.cpp +++ b/test/base/StringUtilTest.cpp @@ -1,6 +1,7 @@ #include "cru/base/StringUtil.h" #include <catch2/catch_test_macros.hpp> +#include <string_view> using cru::Index; using namespace cru::string; @@ -127,6 +128,50 @@ TEST_CASE("StringUtil Utf16CodePointIterator", "[string]") { REQUIRE(code_points == expected_code_points); } +TEST_CASE("StringUtil Utf8IndexCodeUnitToCodePoint", "[string]") { + std::string_view text = "aπ你🤣!"; + Index current = text.size(); + REQUIRE(Utf8IndexCodeUnitToCodePoint(text.data(), text.size(), 0) == 0); + REQUIRE(Utf8IndexCodeUnitToCodePoint(text.data(), text.size(), 1) == 1); + REQUIRE(Utf8IndexCodeUnitToCodePoint(text.data(), text.size(), 3) == 2); + REQUIRE(Utf8IndexCodeUnitToCodePoint(text.data(), text.size(), 6) == 3); + REQUIRE(Utf8IndexCodeUnitToCodePoint(text.data(), text.size(), 10) == 4); + REQUIRE(Utf8IndexCodeUnitToCodePoint(text.data(), text.size(), 11) == 5); +} + +TEST_CASE("StringUtil Utf8IndexCodePointToCodeUnit", "[string]") { + std::string_view text = "aπ你🤣!"; + Index current = text.size(); + REQUIRE(Utf8IndexCodePointToCodeUnit(text.data(), text.size(), 0) == 0); + REQUIRE(Utf8IndexCodePointToCodeUnit(text.data(), text.size(), 1) == 1); + REQUIRE(Utf8IndexCodePointToCodeUnit(text.data(), text.size(), 2) == 3); + REQUIRE(Utf8IndexCodePointToCodeUnit(text.data(), text.size(), 3) == 6); + REQUIRE(Utf8IndexCodePointToCodeUnit(text.data(), text.size(), 4) == 10); + REQUIRE(Utf8IndexCodePointToCodeUnit(text.data(), text.size(), 5) == 11); +} + +TEST_CASE("StringUtil Utf16IndexCodeUnitToCodePoint", "[string]") { + std::u16string_view text = u"aπ你🤣!"; + Index current = text.size(); + REQUIRE(Utf16IndexCodeUnitToCodePoint(text.data(), text.size(), 0) == 0); + REQUIRE(Utf16IndexCodeUnitToCodePoint(text.data(), text.size(), 1) == 1); + REQUIRE(Utf16IndexCodeUnitToCodePoint(text.data(), text.size(), 2) == 2); + REQUIRE(Utf16IndexCodeUnitToCodePoint(text.data(), text.size(), 3) == 3); + REQUIRE(Utf16IndexCodeUnitToCodePoint(text.data(), text.size(), 5) == 4); + REQUIRE(Utf16IndexCodeUnitToCodePoint(text.data(), text.size(), 6) == 5); +} + +TEST_CASE("StringUtil Utf16IndexCodePointToCodeUnit", "[string]") { + std::u16string_view text = u"aπ你🤣!"; + Index current = text.size(); + REQUIRE(Utf16IndexCodePointToCodeUnit(text.data(), text.size(), 0) == 0); + REQUIRE(Utf16IndexCodePointToCodeUnit(text.data(), text.size(), 1) == 1); + REQUIRE(Utf16IndexCodePointToCodeUnit(text.data(), text.size(), 2) == 2); + REQUIRE(Utf16IndexCodePointToCodeUnit(text.data(), text.size(), 3) == 3); + REQUIRE(Utf16IndexCodePointToCodeUnit(text.data(), text.size(), 4) == 5); + REQUIRE(Utf16IndexCodePointToCodeUnit(text.data(), text.size(), 5) == 6); +} + TEST_CASE("ParseToNumber Work", "[string]") { auto r1 = ParseToNumber<int>("123"); REQUIRE(r1.valid); |