diff --git a/src/kiwano/2d/TextActor.cpp b/src/kiwano/2d/TextActor.cpp index 87c492b7..79890253 100644 --- a/src/kiwano/2d/TextActor.cpp +++ b/src/kiwano/2d/TextActor.cpp @@ -25,7 +25,13 @@ namespace kiwano { -TextActor::TextActor() {} + // 预留出描边的空间 +const Point cached_texture_offset = Point{ 5, 5 }; + +TextActor::TextActor() + : is_cache_dirty_(false) +{ +} TextActor::TextActor(const String& text) : TextActor(text, TextStyle()) @@ -33,6 +39,7 @@ TextActor::TextActor(const String& text) } TextActor::TextActor(const String& text, const TextStyle& style) + : TextActor() { SetStyle(style); SetText(text); @@ -44,9 +51,19 @@ void TextActor::OnRender(RenderContext& ctx) { if (layout_) { - ctx.SetCurrentBrush(fill_brush_); - ctx.SetCurrentStrokeStyle(outline_stroke_); - ctx.DrawTextLayout(*layout_, Point{}, outline_brush_); + if (texture_cached_) + { + Rect dest_rect = GetBounds(); + dest_rect.left_top -= cached_texture_offset; + dest_rect.right_bottom -= cached_texture_offset; + ctx.DrawTexture(*texture_cached_, nullptr, &dest_rect); + } + else + { + ctx.SetCurrentBrush(fill_brush_); + ctx.SetCurrentStrokeStyle(outline_stroke_); + ctx.DrawTextLayout(*layout_, Point{}, outline_brush_); + } } } @@ -67,6 +84,7 @@ void TextActor::SetText(const String& text) { layout_->Reset(text, style_); content_ = text; + is_cache_dirty_ = true; } catch (SystemError& e) { @@ -76,7 +94,8 @@ void TextActor::SetText(const String& text) void TextActor::SetStyle(const TextStyle& style) { - style_ = style; + is_cache_dirty_ = true; + style_ = style; if (layout_) layout_->Reset(content_, style); } @@ -85,7 +104,8 @@ void TextActor::SetFont(FontPtr font) { if (style_.font != font) { - style_.font = font; + is_cache_dirty_ = true; + style_.font = font; if (layout_) layout_->SetFont(font); } @@ -95,6 +115,7 @@ void TextActor::SetUnderline(bool enable) { if (style_.show_underline != enable) { + is_cache_dirty_ = true; style_.show_underline = enable; if (layout_) layout_->SetUnderline(enable); @@ -105,6 +126,7 @@ void TextActor::SetStrikethrough(bool enable) { if (style_.show_strikethrough != enable) { + is_cache_dirty_ = true; style_.show_strikethrough = enable; if (layout_) layout_->SetStrikethrough(enable); @@ -115,6 +137,7 @@ void TextActor::SetWrapWidth(float wrap_width) { if (style_.wrap_width != wrap_width) { + is_cache_dirty_ = true; style_.wrap_width = wrap_width; if (layout_) layout_->SetWrapWidth(wrap_width); @@ -125,6 +148,7 @@ void TextActor::SetLineSpacing(float line_spacing) { if (style_.line_spacing != line_spacing) { + is_cache_dirty_ = true; style_.line_spacing = line_spacing; if (layout_) layout_->SetLineSpacing(line_spacing); @@ -135,6 +159,7 @@ void TextActor::SetAlignment(TextAlign align) { if (style_.alignment != align) { + is_cache_dirty_ = true; style_.alignment = align; if (layout_) layout_->SetAlignment(align); @@ -143,23 +168,27 @@ void TextActor::SetAlignment(TextAlign align) void TextActor::SetFillBrush(BrushPtr brush) { - fill_brush_ = brush; + fill_brush_ = brush; + is_cache_dirty_ = true; } void TextActor::SetOutlineBrush(BrushPtr brush) { - outline_brush_ = brush; + outline_brush_ = brush; + is_cache_dirty_ = true; } void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke) { outline_stroke_ = stroke; + is_cache_dirty_ = true; } void TextActor::SetFillColor(const Color& color) { if (fill_brush_) { + is_cache_dirty_ = true; fill_brush_->SetColor(color); } else @@ -172,6 +201,7 @@ void TextActor::SetOutlineColor(const Color& outline_color) { if (outline_brush_) { + is_cache_dirty_ = true; outline_brush_->SetColor(outline_color); } else @@ -184,11 +214,26 @@ void TextActor::SetTextLayout(TextLayoutPtr layout) { if (layout_ != layout) { - layout_ = layout; + is_cache_dirty_ = true; + layout_ = layout; ForceUpdateLayout(); } } +void TextActor::SetPreRenderEnabled(bool enable) +{ + if (enable) + { + texture_cached_ = MakePtr(); + } + else + { + texture_cached_ = nullptr; + } + render_ctx_ = nullptr; + is_cache_dirty_ = true; +} + void TextActor::Update(Duration dt) { this->UpdateDirtyLayout(); @@ -206,6 +251,10 @@ void TextActor::UpdateDirtyLayout() { ForceUpdateLayout(); } + else if (is_cache_dirty_) + { + UpdateCachedTexture(); + } } void TextActor::ForceUpdateLayout() @@ -214,6 +263,7 @@ void TextActor::ForceUpdateLayout() { layout_->UpdateIfDirty(); SetSize(layout_->GetSize()); + UpdateCachedTexture(); } else { @@ -221,4 +271,30 @@ void TextActor::ForceUpdateLayout() } } +void TextActor::UpdateCachedTexture() +{ + if (!texture_cached_) + { + return; + } + + const auto expectedSize = layout_->GetSize() + cached_texture_offset * 2; + if (!render_ctx_) + { + render_ctx_ = RenderContext::Create(*texture_cached_, expectedSize); + } + else if (render_ctx_->GetSize() != expectedSize) + { + render_ctx_->Resize(expectedSize); + } + + render_ctx_->BeginDraw(); + render_ctx_->Clear(); + render_ctx_->SetCurrentBrush(fill_brush_); + render_ctx_->SetCurrentStrokeStyle(outline_stroke_); + render_ctx_->DrawTextLayout(*layout_, cached_texture_offset, outline_brush_); + render_ctx_->EndDraw(); + is_cache_dirty_ = false; +} + } // namespace kiwano diff --git a/src/kiwano/2d/TextActor.h b/src/kiwano/2d/TextActor.h index c9a5d761..74b01123 100644 --- a/src/kiwano/2d/TextActor.h +++ b/src/kiwano/2d/TextActor.h @@ -142,6 +142,10 @@ public: /// @brief 设置文本布局 void SetTextLayout(TextLayoutPtr layout); + /// \~chinese + /// @brief 设置预渲染模式,在描边等情况下会有更好的性能 + void SetPreRenderEnabled(bool enable); + /// \~chinese /// @brief 更新脏文字布局 /// @details 仅当文字布局脏时更新 @@ -159,13 +163,18 @@ protected: bool CheckVisibility(RenderContext& ctx) const override; + void UpdateCachedTexture(); + private: - String content_; - TextStyle style_; - TextLayoutPtr layout_; - BrushPtr fill_brush_; - BrushPtr outline_brush_; - StrokeStylePtr outline_stroke_; + bool is_cache_dirty_; + String content_; + TextStyle style_; + TextLayoutPtr layout_; + BrushPtr fill_brush_; + BrushPtr outline_brush_; + StrokeStylePtr outline_stroke_; + TexturePtr texture_cached_; + RenderContextPtr render_ctx_; }; /** @} */