From 794df63a10951b561b5f7ba466e75735d67c34dd Mon Sep 17 00:00:00 2001 From: Nomango Date: Mon, 17 Feb 2020 12:06:29 +0800 Subject: [PATCH] Fix incorrect TextLayout width --- src/kiwano-physics/Fixture.cpp | 2 +- src/kiwano-physics/World.cpp | 15 +- src/kiwano/2d/Actor.cpp | 4 +- src/kiwano/2d/Actor.h | 51 ++--- src/kiwano/2d/DebugActor.cpp | 2 +- src/kiwano/2d/TextActor.cpp | 67 ++++--- src/kiwano/2d/TextActor.h | 26 ++- src/kiwano/render/DirectX/RendererImpl.cpp | 4 +- src/kiwano/render/TextLayout.cpp | 209 ++++++++++++--------- src/kiwano/render/TextLayout.h | 27 ++- 10 files changed, 238 insertions(+), 169 deletions(-) diff --git a/src/kiwano-physics/Fixture.cpp b/src/kiwano-physics/Fixture.cpp index fd2d5588..51e20a2b 100644 --- a/src/kiwano-physics/Fixture.cpp +++ b/src/kiwano-physics/Fixture.cpp @@ -80,7 +80,7 @@ FixturePtr Fixture::CreateRect(Body* body, Param const& param, Size const& size, b2Vec2 b2offset = world->Stage2World(offset); b2PolygonShape shape; - shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, rotation); + shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation)); return CreateFixture(body, &shape, param); } diff --git a/src/kiwano-physics/World.cpp b/src/kiwano-physics/World.cpp index 0b0f4cbc..0f7d8a2a 100644 --- a/src/kiwano-physics/World.cpp +++ b/src/kiwano-physics/World.cpp @@ -242,10 +242,23 @@ ContactList World::GetContactList() void World::Update(Duration dt) { - world_.Step(dt.Seconds(), vel_iter_, pos_iter_); b2Body* b2body = world_.GetBodyList(); while (b2body) + { + Body* body = static_cast(b2body->GetUserData()); + if (body && body->GetType() != Body::Type::Static) + { + body->UpdateFromActor(); + } + + b2body = b2body->GetNext(); + } + + world_.Step(dt.Seconds(), vel_iter_, pos_iter_); + + b2body = world_.GetBodyList(); + while (b2body) { Body* body = static_cast(b2body->GetUserData()); if (body && body->GetType() != Body::Type::Static) diff --git a/src/kiwano/2d/Actor.cpp b/src/kiwano/2d/Actor.cpp index 9a8b257e..963efbb4 100644 --- a/src/kiwano/2d/Actor.cpp +++ b/src/kiwano/2d/Actor.cpp @@ -260,13 +260,13 @@ void Actor::HandleEvent(Event* evt) } } -Matrix3x2 const& Actor::GetTransformMatrix() const +const Matrix3x2& Actor::GetTransformMatrix() const { UpdateTransform(); return transform_matrix_; } -Matrix3x2 const& Actor::GetTransformInverseMatrix() const +const Matrix3x2& Actor::GetTransformInverseMatrix() const { UpdateTransform(); if (dirty_transform_inverse_) diff --git a/src/kiwano/2d/Actor.h b/src/kiwano/2d/Actor.h index bbcb2df2..9e838f19 100644 --- a/src/kiwano/2d/Actor.h +++ b/src/kiwano/2d/Actor.h @@ -114,7 +114,7 @@ public: /// \~chinese /// @brief 获取坐标 - Point const& GetPosition() const; + virtual Point GetPosition() const; /// \~chinese /// @brief 获取 x 坐标 @@ -124,6 +124,10 @@ public: /// @brief 获取 y 坐标 float GetPositionY() const; + /// \~chinese + /// @brief 获取大小 + virtual Size GetSize() const; + /// \~chinese /// @brief 获取宽度 float GetWidth() const; @@ -132,10 +136,6 @@ public: /// @brief 获取高度 float GetHeight() const; - /// \~chinese - /// @brief 获取大小 - Size const& GetSize() const; - /// \~chinese /// @brief 获取缩放后的宽度 float GetScaledWidth() const; @@ -150,7 +150,7 @@ public: /// \~chinese /// @brief 获取锚点 - Point const& GetAnchor() const; + virtual Point GetAnchor() const; /// \~chinese /// @brief 获取 x 方向锚点 @@ -162,7 +162,7 @@ public: /// \~chinese /// @brief 获取透明度 - float GetOpacity() const; + virtual float GetOpacity() const; /// \~chinese /// @brief 获取显示透明度 @@ -170,11 +170,11 @@ public: /// \~chinese /// @brief 获取旋转角度 - float GetRotation() const; + virtual float GetRotation() const; /// \~chinese /// @brief 获取缩放比例 - Point const& GetScale() const; + virtual Point GetScale() const; /// \~chinese /// @brief 获取横向缩放比例 @@ -186,7 +186,7 @@ public: /// \~chinese /// @brief 获取错切角度 - Point const& GetSkew() const; + virtual Point GetSkew() const; /// \~chinese /// @brief 获取横向错切角度 @@ -218,11 +218,11 @@ public: /// \~chinese /// @brief 获取二维变换矩阵 - Matrix3x2 const& GetTransformMatrix() const; + const Matrix3x2& GetTransformMatrix() const; /// \~chinese /// @brief 获取二维变换的逆矩阵 - Matrix3x2 const& GetTransformInverseMatrix() const; + const Matrix3x2& GetTransformInverseMatrix() const; /// \~chinese /// @brief 设置角色是否可见 @@ -284,14 +284,6 @@ public: /// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1] void SetAnchor(float anchorx, float anchory); - /// \~chinese - /// @brief 修改宽度 - virtual void SetWidth(float width); - - /// \~chinese - /// @brief 修改高度 - virtual void SetHeight(float height); - /// \~chinese /// @brief 修改大小 virtual void SetSize(Size const& size); @@ -300,6 +292,14 @@ public: /// @brief 修改大小 void SetSize(float width, float height); + /// \~chinese + /// @brief 修改宽度 + void SetWidth(float width); + + /// \~chinese + /// @brief 修改高度 + void SetHeight(float height); + /// \~chinese /// @brief 设置透明度,默认为 1.0, 范围 [0, 1] virtual void SetOpacity(float opacity); @@ -514,7 +514,7 @@ inline int Actor::GetZOrder() const return z_order_; } -inline Point const& Actor::GetPosition() const +inline Point Actor::GetPosition() const { return transform_.position; } @@ -529,7 +529,7 @@ inline float Actor::GetPositionY() const return GetPosition().y; } -inline Point const& Actor::GetScale() const +inline Point Actor::GetScale() const { return transform_.scale; } @@ -544,7 +544,7 @@ inline float Actor::GetScaleY() const return GetScale().y; } -inline Point const& Actor::GetSkew() const +inline Point Actor::GetSkew() const { return transform_.skew; } @@ -574,7 +574,7 @@ inline float Actor::GetHeight() const return GetSize().y; } -inline Size const& Actor::GetSize() const +inline Size Actor::GetSize() const { return size_; } @@ -594,7 +594,7 @@ inline Size Actor::GetScaledSize() const return Size{ GetScaledWidth(), GetScaledHeight() }; } -inline Point const& Actor::GetAnchor() const +inline Point Actor::GetAnchor() const { return anchor_; } @@ -693,4 +693,5 @@ inline void Actor::SetSkew(float skewx, float skewy) { SetSkew(Vec2{ skewx, skewy }); } + } // namespace kiwano diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index 0f8626b2..d33881c5 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -124,7 +124,7 @@ void DebugActor::OnUpdate(Duration dt) debug_text_.Reset(ss.str(), debug_text_style_); - Size layout_size = debug_text_.GetLayoutSize(); + Size layout_size = debug_text_.GetSize(); if (layout_size.x > GetWidth() - 20) { SetWidth(20 + layout_size.x); diff --git a/src/kiwano/2d/TextActor.cpp b/src/kiwano/2d/TextActor.cpp index da05ffa2..a46715f8 100644 --- a/src/kiwano/2d/TextActor.cpp +++ b/src/kiwano/2d/TextActor.cpp @@ -61,34 +61,10 @@ void TextActor::OnRender(RenderContext& ctx) } } -void TextActor::OnUpdate(Duration dt) +Size TextActor::GetSize() const { - UpdateLayout(); -} - -void TextActor::UpdateLayout() -{ - if (!layout_) - return; - - if (layout_->GetDirtyFlag() == TextLayout::DirtyFlag::Updated) - { - layout_->SetDirtyFlag(TextLayout::DirtyFlag::Clean); - - if (text_.empty()) - { - SetSize(Size()); - } - else - { - SetSize(layout_->GetLayoutSize()); - } - } -} - -bool TextActor::CheckVisibility(RenderContext& ctx) const -{ - return layout_ && layout_->IsValid() && Actor::CheckVisibility(ctx); + const_cast(this)->UpdateDirtyLayout(); + return Actor::GetSize(); } void TextActor::SetFillColor(Color const& color) @@ -124,7 +100,7 @@ void TextActor::SetTextLayout(TextLayoutPtr layout) if (layout_ != layout) { layout_ = layout; - UpdateLayout(); + ForceUpdateLayout(); } } @@ -294,4 +270,39 @@ void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke) } } +void TextActor::Update(Duration dt) +{ + this->UpdateDirtyLayout(); + Actor::Update(dt); +} + +bool TextActor::CheckVisibility(RenderContext& ctx) const +{ + return layout_ && layout_->IsValid() && Actor::CheckVisibility(ctx); +} + +void TextActor::UpdateDirtyLayout() +{ + KGE_ASSERT(layout_); + if (layout_->UpdateWhenDirty()) + { + ForceUpdateLayout(); + } +} + +void TextActor::ForceUpdateLayout() +{ + KGE_ASSERT(layout_); + + layout_->UpdateWhenDirty(); + if (text_.empty()) + { + SetSize(Size()); + } + else + { + SetSize(layout_->GetSize()); + } +} + } // namespace kiwano diff --git a/src/kiwano/2d/TextActor.h b/src/kiwano/2d/TextActor.h index 581b2028..0027371e 100644 --- a/src/kiwano/2d/TextActor.h +++ b/src/kiwano/2d/TextActor.h @@ -67,8 +67,8 @@ public: TextLayoutPtr GetLayout() const; /// \~chinese - /// @brief 获取文本布局大小 - Size GetLayoutSize() const; + /// @brief 获取大小 + Size GetSize() const override; /// \~chinese /// @brief 获取填充画刷 @@ -159,15 +159,20 @@ public: void SetTextLayout(TextLayoutPtr layout); /// \~chinese - /// @brief 更新文字布局 + /// @brief 更新脏文字布局 + /// @details 仅当文字布局脏时更新 + void UpdateDirtyLayout(); + + /// \~chinese + /// @brief 强制更新文字布局 /// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态 - void UpdateLayout(); + void ForceUpdateLayout(); void OnRender(RenderContext& ctx) override; - void OnUpdate(Duration dt) override; - protected: + void Update(Duration dt) override; + bool CheckVisibility(RenderContext& ctx) const override; private: @@ -198,15 +203,6 @@ inline TextLayoutPtr TextActor::GetLayout() const return layout_; } -inline Size TextActor::GetLayoutSize() const -{ - if (layout_) - { - return layout_->GetLayoutSize(); - } - return Size(); -} - inline BrushPtr TextActor::GetFillBrush() const { return style_.fill_brush; diff --git a/src/kiwano/render/DirectX/RendererImpl.cpp b/src/kiwano/render/DirectX/RendererImpl.cpp index a45746ee..6ba754af 100644 --- a/src/kiwano/render/DirectX/RendererImpl.cpp +++ b/src/kiwano/render/DirectX/RendererImpl.cpp @@ -610,7 +610,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c if (content.empty()) { layout.Clear(); - layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated); + layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty); return; } @@ -635,7 +635,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c if (SUCCEEDED(hr)) { NativePtr::Set(layout, output); - layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated); + layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty); } } } diff --git a/src/kiwano/render/TextLayout.cpp b/src/kiwano/render/TextLayout.cpp index 8f66e2e3..62b05a3d 100644 --- a/src/kiwano/render/TextLayout.cpp +++ b/src/kiwano/render/TextLayout.cpp @@ -45,14 +45,15 @@ TextLayoutPtr TextLayout::Create(const String& content, const TextStyle& style) TextLayout::TextLayout() : dirty_flag_(DirtyFlag::Clean) + , line_count_(0) { } -void TextLayout::Reset(const String& text, const TextStyle& style) +void TextLayout::Reset(const String& content, const TextStyle& style) { - if (!text.empty()) + if (!content.empty()) { - Renderer::GetInstance().CreateTextLayout(*this, text, style); + Renderer::GetInstance().CreateTextLayout(*this, content, style); SetAlignment(style.alignment); SetWrapWidth(style.wrap_width); @@ -63,80 +64,58 @@ void TextLayout::Reset(const String& text, const TextStyle& style) SetDefaultOutlineStrokeStyle(style.outline_stroke); if (style.show_underline) - SetUnderline(style.show_underline, { 0, text.length() }); + SetUnderline(style.show_underline, { 0, content.length() }); if (style.show_strikethrough) - SetStrikethrough(style.show_strikethrough, { 0, text.length() }); + SetStrikethrough(style.show_strikethrough, { 0, content.length() }); } else { Clear(); } + + content_ = content; + SetDirtyFlag(DirtyFlag::Dirty); +} + +Size TextLayout::GetSize() const +{ + const_cast(this)->UpdateWhenDirty(); + return size_; } uint32_t TextLayout::GetLineCount() const { -#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX - auto native = NativePtr::Get(this); - KGE_ASSERT(native); - - if (native) - { - DWRITE_TEXT_METRICS metrics; - if (SUCCEEDED(native->GetMetrics(&metrics))) - { - return metrics.lineCount; - } - } -#else - // not supported -#endif - return 0; -} - -Size TextLayout::GetLayoutSize() const -{ -#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX - auto native = NativePtr::Get(this); - KGE_ASSERT(native); - - if (native) - { - DWRITE_TEXT_METRICS metrics; - if (SUCCEEDED(native->GetMetrics(&metrics))) - { - return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height) - : Size(metrics.width, metrics.height); - } - } -#else - // not supported -#endif - return Size(); + const_cast(this)->UpdateWhenDirty(); + return line_count_; } void TextLayout::SetFont(FontPtr font, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); if (native) { - ComPtr collection = NativePtr::Get(font); + auto collection = NativePtr::Get(font); HRESULT hr = native->SetFontCollection(collection.Get(), { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontCollection failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetFontFamily(String const& family, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -147,16 +126,18 @@ void TextLayout::SetFontFamily(String const& family, TextRange range) HRESULT hr = native->SetFontFamilyName(font_family.c_str(), { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontFamilyName failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetFontSize(float size, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -165,16 +146,18 @@ void TextLayout::SetFontSize(float size, TextRange range) { HRESULT hr = native->SetFontSize(size, { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontSize failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetFontWeight(uint32_t weight, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -185,16 +168,18 @@ void TextLayout::SetFontWeight(uint32_t weight, TextRange range) HRESULT hr = native->SetFontWeight(font_weight, { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontWeight failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetItalic(bool italic, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -205,16 +190,18 @@ void TextLayout::SetItalic(bool italic, TextRange range) HRESULT hr = native->SetFontStyle(font_style, { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontStyle failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetUnderline(bool enable, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -223,16 +210,18 @@ void TextLayout::SetUnderline(bool enable, TextRange range) { HRESULT hr = native->SetUnderline(enable, { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetUnderline failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else - return; // not supported + // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetStrikethrough(bool enable, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -241,16 +230,18 @@ void TextLayout::SetStrikethrough(bool enable, TextRange range) { HRESULT hr = native->SetStrikethrough(enable, { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetStrikethrough failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else - return; // not supported + // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetFillBrush(BrushPtr brush, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX auto native = NativePtr::Get(this); KGE_ASSERT(native); @@ -260,16 +251,18 @@ void TextLayout::SetFillBrush(BrushPtr brush, TextRange range) HRESULT hr = native->SetDrawingEffect(NativePtr::Get(brush).Get(), { range.start, range.length }); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetDrawingEffect failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else - return; // not supported + // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX // TODO KGE_NOT_USED(range); @@ -281,6 +274,8 @@ void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range) void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range) { + KGE_ASSERT(content_.size() >= (range.start + range.length)); + #if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX // TODO KGE_NOT_USED(range); @@ -317,12 +312,12 @@ void TextLayout::SetAlignment(TextAlign align) HRESULT hr = native->SetTextAlignment(alignment); KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetTextAlignment failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetWrapWidth(float wrap_width) @@ -333,34 +328,26 @@ void TextLayout::SetWrapWidth(float wrap_width) if (native) { - DWRITE_WORD_WRAPPING wrapping = (wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP; - - HRESULT hr = native->SetWordWrapping(wrapping); - if (SUCCEEDED(hr)) + HRESULT hr = S_OK; + if (wrap_width > 0) { - if (wrap_width > 0) + hr = native->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP); + if (SUCCEEDED(hr)) { hr = native->SetMaxWidth(wrap_width); } - else - { - // Fix the layout width when the text does not wrap - DWRITE_TEXT_METRICS metrics; - hr = native->GetMetrics(&metrics); - - if (SUCCEEDED(hr)) - { - hr = native->SetMaxWidth(metrics.width); - } - } + } + else + { + hr = native->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); } KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetWordWrapping failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else - return; // not supported + // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); } void TextLayout::SetLineSpacing(float line_spacing) @@ -383,12 +370,62 @@ void TextLayout::SetLineSpacing(float line_spacing) hr = native->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, spacing, spacing * 0.8f); } KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetLineSpacing failed"); - - dirty_flag_ = DirtyFlag::Updated; } #else - return; // not supported + // not supported #endif + + SetDirtyFlag(DirtyFlag::Dirty); +} + +bool TextLayout::UpdateWhenDirty() +{ +#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX + if (dirty_flag_ == DirtyFlag::Dirty) + { + SetDirtyFlag(DirtyFlag::Clean); + + auto native = NativePtr::Get(this); + KGE_ASSERT(native); + + HRESULT hr = S_OK; + + DWRITE_TEXT_METRICS metrics; + hr = native->GetMetrics(&metrics); + if (SUCCEEDED(hr)) + { + if (native->GetWordWrapping() == DWRITE_WORD_WRAPPING_NO_WRAP) + { + // Fix the layout width when the text does not wrap + hr = native->SetMaxWidth(metrics.widthIncludingTrailingWhitespace); + if (SUCCEEDED(hr)) + { + hr = native->GetMetrics(&metrics); + } + } + } + + if (SUCCEEDED(hr)) + { + line_count_ = metrics.lineCount; + + if (metrics.layoutWidth > 0) + { + size_ = Size(metrics.layoutWidth, metrics.height); + } + else + { + size_ = Size(metrics.widthIncludingTrailingWhitespace, metrics.height); + } + } + + KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::GetMetrics failed"); + return true; + } +#else + // not supported +#endif + return false; } } // namespace kiwano diff --git a/src/kiwano/render/TextLayout.h b/src/kiwano/render/TextLayout.h index 14abc5d8..21a77ec6 100644 --- a/src/kiwano/render/TextLayout.h +++ b/src/kiwano/render/TextLayout.h @@ -67,12 +67,12 @@ public: void Reset(const String& content, const TextStyle& style); /// \~chinese - /// @brief 获取文本行数 - uint32_t GetLineCount() const; + /// @brief 获取文本布局大小 + Size GetSize() const; /// \~chinese - /// @brief 获取文本布局大小 - Size GetLayoutSize() const; + /// @brief 获取文本行数 + uint32_t GetLineCount() const; /// \~chinese /// @brief 获取默认填充画刷 @@ -183,23 +183,34 @@ public: void SetDefaultOutlineStrokeStyle(StrokeStylePtr stroke); /// \~chinese - /// @brief 脏数据标志 + /// @brief 脏布局标志 enum class DirtyFlag : uint8_t { - Clean = 0, ///< 干净布局 - Dirty = 1 << 0, ///< 脏布局 - Updated = 1 << 1, ///< 已更新 + Clean = 0, ///< 干净布局 + Dirty = 1 << 0 ///< 脏布局 }; + /// \~chinese + /// @brief 获取脏布局标志 DirtyFlag GetDirtyFlag() const; + /// \~chinese + /// @brief 设置脏布局标志 void SetDirtyFlag(DirtyFlag flag); + /// \~chinese + /// @brief 更新脏布局 + /// @return 是否需要更新 + bool UpdateWhenDirty(); + private: DirtyFlag dirty_flag_; + uint32_t line_count_; + Size size_; BrushPtr default_fill_brush_; BrushPtr default_outline_brush_; StrokeStylePtr default_outline_stroke_; + String content_; }; /** @} */