diff options
author | crupest <crupest@outlook.com> | 2021-09-09 17:55:40 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2021-09-09 17:55:40 +0800 |
commit | 74aee8a6308445604b513ab37812ddc99365aa98 (patch) | |
tree | 4a0886df82af6baa248e62b97fa585e09be9470d /src | |
parent | 700751108257a00ab1a6134fe0ca570acb3269a8 (diff) | |
download | cru-74aee8a6308445604b513ab37812ddc99365aa98.tar.gz cru-74aee8a6308445604b513ab37812ddc99365aa98.tar.bz2 cru-74aee8a6308445604b513ab37812ddc99365aa98.zip |
...
Diffstat (limited to 'src')
-rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/common/String.cpp | 32 | ||||
-rw-r--r-- | src/common/StringUtil.cpp | 2 | ||||
-rw-r--r-- | src/osx/graphics/quartz/Convert.cpp | 8 | ||||
-rw-r--r-- | src/osx/graphics/quartz/TextLayout.cpp | 66 |
5 files changed, 103 insertions, 6 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 71648589..1056a763 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -12,6 +12,7 @@ target_sources(cru_base PUBLIC ${CRU_BASE_INCLUDE_DIR}/Format.hpp ${CRU_BASE_INCLUDE_DIR}/Logger.hpp ${CRU_BASE_INCLUDE_DIR}/PreConfig.hpp + ${CRU_BASE_INCLUDE_DIR}/Range.hpp ${CRU_BASE_INCLUDE_DIR}/SelfResolvable.hpp ${CRU_BASE_INCLUDE_DIR}/String.hpp ${CRU_BASE_INCLUDE_DIR}/StringUtil.hpp diff --git a/src/common/String.cpp b/src/common/String.cpp index 83dd8aa8..078462c4 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -148,6 +148,38 @@ std::string String::ToUtf8() const { return cru::ToUtf8(std::u16string_view(Char16CStr(), size())); } +Index String::IndexFromCodeUnitToCodePoint(Index code_unit_index) const { + auto iter = CodePointIterator(); + Index result = 0; + while (iter.GetPosition() <= code_unit_index && !iter.IsPastEnd()) { + ++iter; + ++result; + } + return result - 1; +} + +Index String::IndexFromCodePointToCodeUnit(Index code_point_index) const { + auto iter = CodePointIterator(); + Index cpi = 0; + while (cpi < code_point_index && !iter.IsPastEnd()) { + ++iter; + ++cpi; + } + return iter.GetPosition(); +} + +Range String::RangeFromCodeUnitToCodePoint(Range code_unit_range) const { + return Range::FromTwoSides( + IndexFromCodeUnitToCodePoint(code_unit_range.GetStart()), + IndexFromCodeUnitToCodePoint(code_unit_range.GetEnd())); +} + +Range String::RangeFromCodePointToCodeUnit(Range code_point_range) const { + return Range::FromTwoSides( + IndexFromCodePointToCodeUnit(code_point_range.GetStart()), + IndexFromCodePointToCodeUnit(code_point_range.GetEnd())); +} + namespace { inline int Compare(std::uint16_t left, std::uint16_t right) { if (left < right) return -1; diff --git a/src/common/StringUtil.cpp b/src/common/StringUtil.cpp index 36f4df4e..b1f1ed4b 100644 --- a/src/common/StringUtil.cpp +++ b/src/common/StringUtil.cpp @@ -1,6 +1,6 @@ #include "cru/common/StringUtil.hpp" #include "cru/common/Base.hpp" -#include "gsl/gsl_util" +#include "cru/common/Exception.hpp" namespace cru { namespace { diff --git a/src/osx/graphics/quartz/Convert.cpp b/src/osx/graphics/quartz/Convert.cpp index 087de56b..9dcb29db 100644 --- a/src/osx/graphics/quartz/Convert.cpp +++ b/src/osx/graphics/quartz/Convert.cpp @@ -41,4 +41,12 @@ Rect Convert(const CGRect& rect) { static_cast<float>(rect.size.width), static_cast<float>(rect.size.height)}; } + +CFRange Convert(const Range& range) { + return CFRangeMake(range.position, range.count); +} + +Range Convert(const CFRange& range) { + return Range(range.location, range.length); +} } // namespace cru::platform::graphics::osx::quartz diff --git a/src/osx/graphics/quartz/TextLayout.cpp b/src/osx/graphics/quartz/TextLayout.cpp index 08495634..73bfb1ce 100644 --- a/src/osx/graphics/quartz/TextLayout.cpp +++ b/src/osx/graphics/quartz/TextLayout.cpp @@ -3,6 +3,9 @@ #include "cru/osx/graphics/quartz/Resource.hpp" #include "cru/platform/Check.hpp" +#include <algorithm> +#include <limits> + namespace cru::platform::graphics::osx::quartz { OsxCTTextLayout::OsxCTTextLayout(IGraphFactory* graphics_factory, std::shared_ptr<OsxCTFont> font, @@ -48,15 +51,59 @@ void OsxCTTextLayout::SetMaxHeight(float max_height) { } Rect OsxCTTextLayout::GetTextBounds(bool includingTrailingSpace) { - auto lines = CTFrameGetLines(ct_frame_); + float left = std::numeric_limits<float>::max(); + float top = std::numeric_limits<float>::max(); + float right = 0; + float bottom = 0; + + for (int i = 0; i < line_count_; i++) { + auto line = static_cast<CTLineRef>(lines_[i]); + const auto& line_origin = line_origins_[i]; - const auto line_count = CFArrayGetCount(lines); + CGRect line_rect = CTLineGetImageBounds(line, nullptr); + if (includingTrailingSpace) { + float trailingWidth = CTLineGetTrailingWhitespaceWidth(line); + line_rect.size.width += trailingWidth; + } - for (int i = 0; i < line_count; i++) { - auto line = CFArrayGetValueAtIndex(lines, i); + line_rect.origin.x += line_origin.x; + line_rect.origin.y += line_origin.y; - // TODO: To be continued! + left = std::min<float>(line_rect.origin.x, left); + top = std::min<float>(line_rect.origin.y, top); + right = std::max<float>(line_rect.origin.x + line_rect.size.width, right); + bottom = + std::max<float>(line_rect.origin.y + line_rect.size.height, bottom); } + + return Rect::FromVertices(left, top, right, bottom); +} + +std::vector<Rect> OsxCTTextLayout::TextRangeRect(const TextRange& text_range) { + const auto r = text_.RangeFromCodeUnitToCodePoint(text_range).Normalize(); + + std::vector<Rect> results; + + for (int i = 0; i < line_count_; i++) { + auto line = lines_[i]; + const auto& line_origin = line_origins_[i]; + + Range range = Convert(CTLineGetStringRange(line)); + range = range.CoerceInto(r.GetStart(), r.GetEnd()); + + if (range.count) { + auto line_rect = CTLineGetImageBounds(line, nullptr); + line_rect.origin.x += line_origin.x; + line_rect.origin.y += line_origin.y; + float start_offset = CTLineGetOffsetForStringIndex(line, range.GetStart(), nullptr); + float end_offset = CTLineGetOffsetForStringIndex(line, range.GetEnd(), nullptr); + line_rect.origin.x += start_offset; + line_rect.size.width = end_offset - start_offset; + results.push_back(Convert(line_rect)); + } + } + + return results; } void OsxCTTextLayout::RecreateFrame() { @@ -77,5 +124,14 @@ void OsxCTTextLayout::RecreateFrame() { CFRelease(attributed_string); CGPathRelease(path); + + const auto lines = CTFrameGetLines(ct_frame_); + line_count_ = CFArrayGetCount(lines); + lines_.resize(line_count_); + line_origins_.resize(line_count_); + CTFrameGetLineOrigins(ct_frame_, CFRangeMake(0, 0), line_origins_.data()); + for (int i = 0; i < line_count_; i++) { + lines_[i] = static_cast<CTLineRef>(CFArrayGetValueAtIndex(lines, i)); + } } } // namespace cru::platform::graphics::osx::quartz |