From 6aa2201797a9ed64ce0178215ae941d0c5f09579 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 30 Oct 2020 00:07:57 +0800 Subject: ... --- src/win/graphics/direct/TextLayout.cpp | 124 +++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/win/graphics/direct/TextLayout.cpp (limited to 'src/win/graphics/direct/TextLayout.cpp') diff --git a/src/win/graphics/direct/TextLayout.cpp b/src/win/graphics/direct/TextLayout.cpp new file mode 100644 index 00000000..0c6e797f --- /dev/null +++ b/src/win/graphics/direct/TextLayout.cpp @@ -0,0 +1,124 @@ +#include "cru/win/graphics/direct/TextLayout.hpp" + +#include "cru/common/Logger.hpp" +#include "cru/platform/Check.hpp" +#include "cru/win/graphics/direct/Exception.hpp" +#include "cru/win/graphics/direct/Factory.hpp" +#include "cru/win/graphics/direct/Font.hpp" + +#include + +namespace cru::platform::graphics::win::direct { +DWriteTextLayout::DWriteTextLayout(DirectGraphFactory* factory, + std::shared_ptr font, + std::u16string text) + : DirectGraphResource(factory), text_(std::move(text)) { + Expects(font); + font_ = CheckPlatform(font, GetPlatformId()); + + ThrowIfFailed(factory->GetDWriteFactory()->CreateTextLayout( + reinterpret_cast(text_.c_str()), + static_cast(text_.size()), font_->GetComInterface(), max_width_, + max_height_, &text_layout_)); +} + +DWriteTextLayout::~DWriteTextLayout() = default; + +std::u16string DWriteTextLayout::GetText() { return text_; } + +std::u16string_view DWriteTextLayout::GetTextView() { return text_; } + +void DWriteTextLayout::SetText(std::u16string new_text) { + text_.swap(new_text); + ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout( + reinterpret_cast(text_.c_str()), + static_cast(text_.size()), font_->GetComInterface(), max_width_, + max_height_, &text_layout_)); +} + +std::shared_ptr DWriteTextLayout::GetFont() { + return std::dynamic_pointer_cast(font_); +} + +void DWriteTextLayout::SetFont(std::shared_ptr font) { + font_ = CheckPlatform(font, GetPlatformId()); + ThrowIfFailed(GetDirectFactory()->GetDWriteFactory()->CreateTextLayout( + reinterpret_cast(text_.c_str()), + static_cast(text_.size()), font_->GetComInterface(), max_width_, + max_height_, &text_layout_)); +} + +void DWriteTextLayout::SetMaxWidth(float max_width) { + max_width_ = max_width; + ThrowIfFailed(text_layout_->SetMaxWidth(max_width_)); +} + +void DWriteTextLayout::SetMaxHeight(float max_height) { + max_height_ = max_height; + ThrowIfFailed(text_layout_->SetMaxHeight(max_height_)); +} + +Rect DWriteTextLayout::GetTextBounds() { + DWRITE_TEXT_METRICS metrics; + ThrowIfFailed(text_layout_->GetMetrics(&metrics)); + return Rect{metrics.left, metrics.top, metrics.width, metrics.height}; +} + +std::vector DWriteTextLayout::TextRangeRect( + const TextRange& text_range_arg) { + if (text_range_arg.count == 0) { + return {}; + } + const auto text_range = text_range_arg.Normalize(); + + DWRITE_TEXT_METRICS text_metrics; + ThrowIfFailed(text_layout_->GetMetrics(&text_metrics)); + const auto metrics_count = + text_metrics.lineCount * text_metrics.maxBidiReorderingDepth; + + std::vector hit_test_metrics(metrics_count); + UINT32 actual_count; + ThrowIfFailed(text_layout_->HitTestTextRange( + static_cast(text_range.position), + static_cast(text_range.count), 0, 0, hit_test_metrics.data(), + metrics_count, &actual_count)); + + hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count, + hit_test_metrics.cend()); + + std::vector result; + result.reserve(actual_count); + + for (const auto& metrics : hit_test_metrics) { + result.push_back( + Rect{metrics.left, metrics.top, metrics.width, metrics.height}); + } + + return result; +} + +Point DWriteTextLayout::TextSinglePoint(Index position, bool trailing) { + DWRITE_HIT_TEST_METRICS metrics; + FLOAT left; + FLOAT top; + ThrowIfFailed(text_layout_->HitTestTextPosition(static_cast(position), + static_cast(trailing), + &left, &top, &metrics)); + return Point{left, top}; +} + +TextHitTestResult DWriteTextLayout::HitTest(const Point& point) { + BOOL trailing; + BOOL inside; + DWRITE_HIT_TEST_METRICS metrics; + + ThrowIfFailed(text_layout_->HitTestPoint(point.x, point.y, &trailing, &inside, + &metrics)); + + TextHitTestResult result; + result.position = metrics.textPosition; + result.trailing = trailing != 0; + result.insideText = inside != 0; + return result; +} +} // namespace cru::platform::graphics::win::direct -- cgit v1.2.3 From 1e1170a89330881c5fad60988bc27c824dfcf454 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 31 Dec 2020 18:27:57 +0800 Subject: ... --- include/cru/platform/graphics/TextLayout.hpp | 4 ++-- include/cru/ui/render/TextRenderObject.hpp | 11 ++++++++++- include/cru/win/graphics/direct/TextLayout.hpp | 2 +- src/ui/controls/TextBox.cpp | 1 + src/ui/render/TextRenderObject.cpp | 13 +++++++++++-- src/win/graphics/direct/TextLayout.cpp | 7 +++++-- 6 files changed, 30 insertions(+), 8 deletions(-) (limited to 'src/win/graphics/direct/TextLayout.cpp') diff --git a/include/cru/platform/graphics/TextLayout.hpp b/include/cru/platform/graphics/TextLayout.hpp index efd017d6..b363fb77 100644 --- a/include/cru/platform/graphics/TextLayout.hpp +++ b/include/cru/platform/graphics/TextLayout.hpp @@ -16,9 +16,9 @@ struct ITextLayout : virtual IGraphResource { virtual void SetMaxWidth(float max_width) = 0; virtual void SetMaxHeight(float max_height) = 0; - virtual Rect GetTextBounds() = 0; + virtual Rect GetTextBounds(bool includingTrailingSpace = false) = 0; virtual std::vector TextRangeRect(const TextRange& text_range) = 0; virtual Point TextSinglePoint(Index position, bool trailing) = 0; virtual TextHitTestResult HitTest(const Point& point) = 0; }; -} // namespace cru::platform::graph +} // namespace cru::platform::graphics diff --git a/include/cru/ui/render/TextRenderObject.hpp b/include/cru/ui/render/TextRenderObject.hpp index fa569c8c..bdec18d1 100644 --- a/include/cru/ui/render/TextRenderObject.hpp +++ b/include/cru/ui/render/TextRenderObject.hpp @@ -38,7 +38,9 @@ class TextRenderObject : public RenderObject { std::u16string_view GetTextView() const; void SetText(std::u16string new_text); - std::shared_ptr GetBrush() const { return brush_; } + std::shared_ptr GetBrush() const { + return brush_; + } void SetBrush(std::shared_ptr new_brush); std::shared_ptr GetFont() const; @@ -80,6 +82,11 @@ class TextRenderObject : public RenderObject { float GetCaretWidth() const { return caret_width_; } void SetCaretWidth(float width); + bool IsMeasureIncludingTrailingSpace() const { + return is_measure_including_trailing_space_; + } + void SetMeasureIncludingTrailingSpace(bool including); + RenderObject* HitTest(const Point& point) override; protected: @@ -104,5 +111,7 @@ class TextRenderObject : public RenderObject { gsl::index caret_position_ = 0; std::shared_ptr caret_brush_; float caret_width_ = default_caret_width; + + bool is_measure_including_trailing_space_ = false; }; } // namespace cru::ui::render diff --git a/include/cru/win/graphics/direct/TextLayout.hpp b/include/cru/win/graphics/direct/TextLayout.hpp index 3320431f..aa040278 100644 --- a/include/cru/win/graphics/direct/TextLayout.hpp +++ b/include/cru/win/graphics/direct/TextLayout.hpp @@ -38,7 +38,7 @@ class DWriteTextLayout : public DirectGraphResource, void SetMaxWidth(float max_width) override; void SetMaxHeight(float max_height) override; - Rect GetTextBounds() override; + Rect GetTextBounds(bool includingTrailingSpace = false) override; // Return empty vector if text_range.count is 0. Text range could be in // reverse direction, it should be normalized first in implementation. std::vector TextRangeRect(const TextRange& text_range) override; diff --git a/src/ui/controls/TextBox.cpp b/src/ui/controls/TextBox.cpp index e1acaee0..bfc98c06 100644 --- a/src/ui/controls/TextBox.cpp +++ b/src/ui/controls/TextBox.cpp @@ -28,6 +28,7 @@ TextBox::TextBox() scroll_render_object_->SetAttachedControl(this); text_render_object_->SetAttachedControl(this); text_render_object_->SetMinSize(Size{100, 24}); + text_render_object_->SetMeasureIncludingTrailingSpace(true); service_ = std::make_unique(this); service_->SetEnabled(true); diff --git a/src/ui/render/TextRenderObject.cpp b/src/ui/render/TextRenderObject.cpp index 9faab622..06092d52 100644 --- a/src/ui/render/TextRenderObject.cpp +++ b/src/ui/render/TextRenderObject.cpp @@ -57,7 +57,8 @@ std::shared_ptr TextRenderObject::GetFont() const { return text_layout_->GetFont(); } -void TextRenderObject::SetFont(std::shared_ptr font) { +void TextRenderObject::SetFont( + std::shared_ptr font) { Expects(font); text_layout_->SetFont(std::move(font)); } @@ -154,6 +155,12 @@ Rect TextRenderObject::GetCaretRect() { return rect; } +void TextRenderObject::SetMeasureIncludingTrailingSpace(bool including) { + if (is_measure_including_trailing_space_ == including) return; + is_measure_including_trailing_space_ = including; + InvalidateLayout(); +} + RenderObject* TextRenderObject::HitTest(const Point& point) { const auto padding_rect = GetPaddingRect(); return padding_rect.IsPointInside(point) ? this : nullptr; @@ -185,7 +192,9 @@ Size TextRenderObject::OnMeasureContent(const MeasureRequirement& requirement, text_layout_->SetMaxWidth(measure_width); text_layout_->SetMaxHeight(std::numeric_limits::max()); - const auto text_size = text_layout_->GetTextBounds().GetSize(); + const auto text_size = + text_layout_->GetTextBounds(is_measure_including_trailing_space_) + .GetSize(); auto result = text_size; if (requirement.max.width.IsSpecified() && diff --git a/src/win/graphics/direct/TextLayout.cpp b/src/win/graphics/direct/TextLayout.cpp index 0c6e797f..0b3c68ca 100644 --- a/src/win/graphics/direct/TextLayout.cpp +++ b/src/win/graphics/direct/TextLayout.cpp @@ -58,10 +58,13 @@ void DWriteTextLayout::SetMaxHeight(float max_height) { ThrowIfFailed(text_layout_->SetMaxHeight(max_height_)); } -Rect DWriteTextLayout::GetTextBounds() { +Rect DWriteTextLayout::GetTextBounds(bool includingTrailingSpace) { DWRITE_TEXT_METRICS metrics; ThrowIfFailed(text_layout_->GetMetrics(&metrics)); - return Rect{metrics.left, metrics.top, metrics.width, metrics.height}; + return Rect{metrics.left, metrics.top, + includingTrailingSpace ? metrics.widthIncludingTrailingWhitespace + : metrics.width, + metrics.height}; } std::vector DWriteTextLayout::TextRangeRect( -- cgit v1.2.3