diff --git a/projects/kiwano/kiwano.vcxproj b/projects/kiwano/kiwano.vcxproj index a04930cd..2fbffc54 100644 --- a/projects/kiwano/kiwano.vcxproj +++ b/projects/kiwano/kiwano.vcxproj @@ -28,7 +28,6 @@ - @@ -61,10 +60,10 @@ - + @@ -126,7 +125,6 @@ - diff --git a/projects/kiwano/kiwano.vcxproj.filters b/projects/kiwano/kiwano.vcxproj.filters index 95f0f48c..e008fce2 100644 --- a/projects/kiwano/kiwano.vcxproj.filters +++ b/projects/kiwano/kiwano.vcxproj.filters @@ -48,9 +48,6 @@ 2d - - 2d - 2d @@ -201,9 +198,6 @@ renderer - - renderer - 2d @@ -270,6 +264,9 @@ core + + renderer + @@ -407,9 +404,6 @@ renderer - - renderer - 2d diff --git a/src/kiwano/2d/Canvas.cpp b/src/kiwano/2d/Canvas.cpp index 2cdeddcf..fa30f137 100644 --- a/src/kiwano/2d/Canvas.cpp +++ b/src/kiwano/2d/Canvas.cpp @@ -58,7 +58,7 @@ namespace kiwano PrepareRender(rt); Rect bitmap_rect(0.f, 0.f, texture_cached_->GetWidth(), texture_cached_->GetHeight()); - rt->DrawTexture(texture_cached_, bitmap_rect, bitmap_rect); + rt->DrawTexture(*texture_cached_, bitmap_rect, bitmap_rect); } } @@ -82,11 +82,6 @@ namespace kiwano stroke_style_ = stroke_style; } - void Canvas::SetTextFont(Font const& font) - { - text_font_ = font; - } - void Canvas::SetTextStyle(TextStyle const & text_style) { text_style_ = text_style; @@ -249,7 +244,7 @@ namespace kiwano { if (texture) { - rt_.DrawTexture(texture, src_rect, dest_rect); + rt_.DrawTexture(*texture, src_rect, dest_rect); cache_expired_ = true; } } @@ -259,7 +254,9 @@ namespace kiwano if (text.empty()) return; - TextLayout layout(text, text_font_, text_style_); + TextLayout layout; + layout.SetStyle(text_style_); + layout.SetText(text); DrawTextLayout(layout, point); } diff --git a/src/kiwano/2d/Canvas.h b/src/kiwano/2d/Canvas.h index c9d1f39b..447a5013 100644 --- a/src/kiwano/2d/Canvas.h +++ b/src/kiwano/2d/Canvas.h @@ -198,11 +198,6 @@ namespace kiwano /// @param stroke_style 轮廓样式 void SetStrokeStyle(StrokeStyle stroke_style); - /// \~chinese - /// @brief 设置文字字体 - /// @param font 文字字体 - void SetTextFont(Font const& font); - /// \~chinese /// @brief 设置文字画刷样式 /// @param text_style 文字画刷样式 @@ -270,7 +265,6 @@ namespace kiwano float stroke_width_; Color fill_color_; Color stroke_color_; - Font text_font_; TextStyle text_style_; StrokeStyle stroke_style_; GeometrySink geo_sink_; diff --git a/src/kiwano/2d/DebugActor.cpp b/src/kiwano/2d/DebugActor.cpp index f740c0d5..893dbc1c 100644 --- a/src/kiwano/2d/DebugActor.cpp +++ b/src/kiwano/2d/DebugActor.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #pragma comment(lib, "psapi.lib") @@ -57,13 +58,10 @@ namespace kiwano debug_text_->SetPosition(Point{ 10, 10 }); this->AddChild(debug_text_); - Font font; - font.family = L"Arial"; - font.size = 16.f; - font.weight = FontWeight::Normal; - debug_text_->SetFont(font); - TextStyle style; + style.font_family = L"Arial"; + style.font_size = 16.f; + style.font_weight = FontWeight::Normal; style.line_spacing = 20.f; debug_text_->SetStyle(style); diff --git a/src/kiwano/2d/GifSprite.cpp b/src/kiwano/2d/GifSprite.cpp index a500db01..69657b73 100644 --- a/src/kiwano/2d/GifSprite.cpp +++ b/src/kiwano/2d/GifSprite.cpp @@ -89,11 +89,11 @@ namespace kiwano void GifSprite::OnRender(RenderTarget* rt) { - if (frame_.raw && frame_.raw->IsValid() && CheckVisibilty(rt)) + if (frame_to_render_ && CheckVisibilty(rt)) { PrepareRender(rt); - rt->DrawTexture(frame_.raw, &frame_.rect, nullptr); + rt->DrawTexture(*frame_to_render_, &frame_.rect, nullptr); } } @@ -188,13 +188,16 @@ namespace kiwano loop_count_++; } - frame_rt_.DrawTexture(frame_.raw, nullptr, &frame_.rect); + if (frame_.raw) + { + frame_rt_.DrawTexture(*frame_.raw, nullptr, &frame_.rect); + } + frame_rt_.EndDraw(); - TexturePtr frame_to_render = frame_rt_.GetOutput(); - if (frame_to_render) + frame_to_render_ = frame_rt_.GetOutput(); + if (frame_to_render_) { - frame_.raw = frame_to_render; next_index_ = (++next_index_) % gif_->GetFramesCount(); } } diff --git a/src/kiwano/2d/GifSprite.h b/src/kiwano/2d/GifSprite.h index ce70b01f..611473c9 100644 --- a/src/kiwano/2d/GifSprite.h +++ b/src/kiwano/2d/GifSprite.h @@ -161,6 +161,7 @@ namespace kiwano GifImagePtr gif_; GifImage::Frame frame_; TexturePtr saved_frame_; + TexturePtr frame_to_render_; TextureRenderTarget frame_rt_; }; diff --git a/src/kiwano/2d/Sprite.cpp b/src/kiwano/2d/Sprite.cpp index 319b2a92..d5ff9e8b 100644 --- a/src/kiwano/2d/Sprite.cpp +++ b/src/kiwano/2d/Sprite.cpp @@ -108,7 +108,7 @@ namespace kiwano { PrepareRender(rt); - rt->DrawTexture(frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds()); + rt->DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds()); } } } diff --git a/src/kiwano/2d/TextActor.cpp b/src/kiwano/2d/TextActor.cpp index b1a1ed93..96f49c0e 100644 --- a/src/kiwano/2d/TextActor.cpp +++ b/src/kiwano/2d/TextActor.cpp @@ -26,186 +26,39 @@ namespace kiwano { namespace { - Font text_default_font; TextStyle text_default_style; } - void kiwano::TextActor::SetDefaultFont(Font const & font) - { - text_default_font = font; - } - - void kiwano::TextActor::SetDefaultStyle(TextStyle const & style) + void TextActor::SetDefaultStyle(TextStyle const & style) { text_default_style = style; } TextActor::TextActor() - : font_(text_default_font) - , layout_dirty_(false) - , format_dirty_(false) + : TextActor(String()) { - text_layout_.SetTextStyle(text_default_style); } TextActor::TextActor(String const& text) - : TextActor(text, text_default_font, text_default_style) - { - } - - TextActor::TextActor(String const& text, const Font & font) - : TextActor(text, font, text_default_style) + : TextActor(text, text_default_style) { } TextActor::TextActor(String const& text, const TextStyle & style) - : TextActor(text, text_default_font, style) { - } - - TextActor::TextActor(String const& text, const Font & font, const TextStyle & style) - : font_(font) - , text_(text) - , layout_dirty_(true) - , format_dirty_(true) - { - text_layout_.SetTextStyle(style); + SetText(text); + SetStyle(style); } TextActor::~TextActor() { } - void TextActor::SetText(String const& text) - { - text_ = text; - layout_dirty_ = true; - } - - void TextActor::SetStyle(const TextStyle& style) - { - text_layout_.SetTextStyle(style); - layout_dirty_ = true; - } - - void TextActor::SetFont(const Font & font) - { - font_ = font; - format_dirty_ = true; - } - - void TextActor::SetFontFamily(String const& family) - { - if (font_.family != family) - { - font_.family = family; - format_dirty_ = true; - } - } - - void TextActor::SetFontSize(float size) - { - if (font_.size != size) - { - font_.size = size; - format_dirty_ = true; - } - } - - void TextActor::SetFontWeight(uint32_t weight) - { - if (font_.weight != weight) - { - font_.weight = weight; - format_dirty_ = true; - } - } - - void TextActor::SetItalic(bool italic) - { - if (font_.italic != italic) - { - font_.italic = italic; - format_dirty_ = true; - } - } - - void TextActor::SetWrapWidth(float wrap_width) - { - if (text_layout_.GetTextStyle().wrap_width != wrap_width) - { - text_layout_.GetTextStyle().wrap_width = wrap_width; - layout_dirty_ = true; - } - } - - void TextActor::SetLineSpacing(float line_spacing) - { - if (text_layout_.GetTextStyle().line_spacing != line_spacing) - { - text_layout_.GetTextStyle().line_spacing = line_spacing; - layout_dirty_ = true; - } - } - - void TextActor::SetAlignment(TextAlign align) - { - if (text_layout_.GetTextStyle().alignment != align) - { - text_layout_.GetTextStyle().alignment = align; - layout_dirty_ = true; - } - } - - void TextActor::SetUnderline(bool underline) - { - if (text_layout_.GetTextStyle().underline != underline) - { - text_layout_.GetTextStyle().underline = underline; - layout_dirty_ = true; - } - } - - void TextActor::SetStrikethrough(bool strikethrough) - { - if (text_layout_.GetTextStyle().strikethrough != strikethrough) - { - text_layout_.GetTextStyle().strikethrough = strikethrough; - layout_dirty_ = true; - } - } - - void TextActor::SetColor(Color const& color) - { - text_layout_.GetTextStyle().color = color; - text_layout_.GetTextStyle().color = color; - } - - void TextActor::SetOutline(bool outline) - { - text_layout_.GetTextStyle().outline = outline; - } - - void TextActor::SetOutlineColor(Color const&outline_color) - { - text_layout_.GetTextStyle().outline_color = outline_color; - } - - void TextActor::SetOutlineWidth(float outline_width) - { - text_layout_.GetTextStyle().outline_width = outline_width; - } - - void TextActor::SetOutlineStroke(StrokeStyle outline_stroke) - { - text_layout_.GetTextStyle().outline_stroke = outline_stroke; - } - void TextActor::OnRender(RenderTarget* rt) { UpdateLayout(); - if (text_layout_ && CheckVisibilty(rt)) + if (text_layout_.IsValid() && CheckVisibilty(rt)) { PrepareRender(rt); rt->DrawTextLayout(text_layout_); @@ -214,16 +67,9 @@ namespace kiwano void TextActor::UpdateLayout() { - if (format_dirty_) + if (text_layout_.IsDirty()) { - format_dirty_ = false; - text_layout_.UpdateFont(font_); - } - - if (layout_dirty_) - { - layout_dirty_ = false; - text_layout_.UpdateLayout(text_); + text_layout_.Update(); SetSize(text_layout_.GetLayoutSize()); } } diff --git a/src/kiwano/2d/TextActor.h b/src/kiwano/2d/TextActor.h index 778c6e89..11e701f6 100644 --- a/src/kiwano/2d/TextActor.h +++ b/src/kiwano/2d/TextActor.h @@ -45,46 +45,33 @@ namespace kiwano TextActor(); /// \~chinese - /// @brief 构建空的文本角色 + /// @brief 构建文本角色 /// @param text 文字内容 explicit TextActor(const String& text); /// \~chinese - /// @brief 构建空的文本角色 - /// @param text 文字内容 - /// @param font 字体 - TextActor(const String& text, const Font& font); - - /// \~chinese - /// @brief 构建空的文本角色 + /// @brief 构建文本角色 /// @param text 文字内容 /// @param style 文本样式 TextActor(const String& text, const TextStyle& style); - /// \~chinese - /// @brief 构建空的文本角色 - /// @param text 文字内容 - /// @param font 字体 - /// @param style 文本样式 - TextActor(const String& text, const Font& font, const TextStyle& style); - virtual ~TextActor(); /// \~chinese /// @brief 获取文本 - String const& GetText() const; - - /// \~chinese - /// @brief 获取字体 - Font GetFont() const; + const String& GetText() const; /// \~chinese /// @brief 获取文本样式 - TextStyle GetStyle() const; + const TextStyle& GetStyle() const; /// \~chinese /// @brief 获取文本布局 - TextLayout GetLayout() const; + const TextLayout& GetLayout() const; + + /// \~chinese + /// @brief 获取字体 + FontPtr GetFont() const; /// \~chinese /// @brief 设置文本 @@ -96,7 +83,7 @@ namespace kiwano /// \~chinese /// @brief 设置字体 - void SetFont(const Font& font); + void SetFont(FontPtr font); /// \~chinese /// @brief 设置字体族 @@ -104,9 +91,7 @@ namespace kiwano /// \~chinese /// @brief 设置字号(默认值为 18) - void SetFontSize( - float size - ); + void SetFontSize(float size); /// \~chinese /// @brief 设置字体粗细值(默认值为 FontWeight::Normal) @@ -132,17 +117,9 @@ namespace kiwano /// @brief 设置对齐方式(默认为 TextAlign::Left) void SetAlignment(TextAlign align); - /// \~chinese - /// @brief 设置下划线(默认值为 false) - void SetUnderline(bool underline); - - /// \~chinese - /// @brief 设置删除线(默认值为 false) - void SetStrikethrough(bool strikethrough); - /// \~chinese /// @brief 设置是否显示描边 - void SetOutline(bool outline); + void SetOutline(bool enable); /// \~chinese /// @brief 设置描边颜色 @@ -157,12 +134,16 @@ namespace kiwano void SetOutlineStroke(StrokeStyle outline_stroke); /// \~chinese - /// @brief 更新文本布局 - void UpdateLayout(); + /// @brief 设置是否显示下划线(默认值为 false) + void SetUnderline(bool enable); /// \~chinese - /// @brief 设置默认字体 - static void SetDefaultFont(Font const& font); + /// @brief 设置是否显示删除线(默认值为 false) + void SetStrikethrough(bool enable); + + /// \~chinese + /// @brief 更新文本布局 + void UpdateLayout(); /// \~chinese /// @brief 设置默认文字样式 @@ -171,21 +152,114 @@ namespace kiwano void OnRender(RenderTarget* rt) override; private: - bool format_dirty_; - bool layout_dirty_; TextLayout text_layout_; - String text_; - Font font_; }; /** @} */ - inline String const& TextActor::GetText() const { return text_; } + inline const String& TextActor::GetText() const + { + return text_layout_.GetText(); + } - inline Font TextActor::GetFont() const { return font_; } + inline FontPtr TextActor::GetFont() const + { + return text_layout_.GetStyle().font; + } - inline TextStyle TextActor::GetStyle() const { return text_layout_.GetTextStyle(); } + inline const TextStyle& TextActor::GetStyle() const + { + return text_layout_.GetStyle(); + } - inline TextLayout TextActor::GetLayout() const { return text_layout_; } + inline const TextLayout& TextActor::GetLayout() const + { + return text_layout_; + } + + inline void TextActor::SetText(String const& text) + { + text_layout_.SetText(text); + } + + inline void TextActor::SetStyle(const TextStyle& style) + { + text_layout_.SetStyle(style); + } + + inline void TextActor::SetFont(FontPtr font) + { + text_layout_.SetFont(font); + } + + inline void TextActor::SetFontFamily(String const& family) + { + text_layout_.SetFontFamily(family); + } + + inline void TextActor::SetFontSize(float size) + { + text_layout_.SetFontSize(size); + } + + inline void TextActor::SetFontWeight(uint32_t weight) + { + text_layout_.SetFontWeight(weight); + } + + inline void TextActor::SetItalic(bool italic) + { + text_layout_.SetItalic(italic); + } + + inline void TextActor::SetWrapWidth(float wrap_width) + { + text_layout_.SetWrapWidth(wrap_width); + } + + inline void TextActor::SetLineSpacing(float line_spacing) + { + text_layout_.SetLineSpacing(line_spacing); + } + + inline void TextActor::SetAlignment(TextAlign align) + { + text_layout_.SetAlignment(align); + } + + inline void TextActor::SetUnderline(bool enable) + { + text_layout_.SetUnderline(enable, 0, text_layout_.GetText().length()); + } + + inline void TextActor::SetStrikethrough(bool enable) + { + text_layout_.SetStrikethrough(enable, 0, text_layout_.GetText().length()); + } + + inline void TextActor::SetColor(Color const& color) + { + text_layout_.SetColor(color); + } + + inline void TextActor::SetOutline(bool enable) + { + text_layout_.SetOutline(enable); + } + + inline void TextActor::SetOutlineColor(Color const& outline_color) + { + text_layout_.SetOutlineColor(outline_color); + } + + inline void TextActor::SetOutlineWidth(float outline_width) + { + text_layout_.SetOutlineWidth(outline_width); + } + + inline void TextActor::SetOutlineStroke(StrokeStyle outline_stroke) + { + text_layout_.SetOutlineStroke(outline_stroke); + } } diff --git a/src/kiwano/core/EventDispatcher.cpp b/src/kiwano/core/EventDispatcher.cpp index 54e7dd91..4e647d78 100644 --- a/src/kiwano/core/EventDispatcher.cpp +++ b/src/kiwano/core/EventDispatcher.cpp @@ -33,9 +33,9 @@ namespace kiwano { next = listener->next_item(); - if (listener->IsRunning() && listener->type_ == evt.GetType()) + if (listener->IsRunning()) { - listener->callback_(evt); + listener->Receive(evt); } if (listener->IsRemoveable()) diff --git a/src/kiwano/core/EventListener.cpp b/src/kiwano/core/EventListener.cpp index 872c62ca..c8fd0dc7 100644 --- a/src/kiwano/core/EventListener.cpp +++ b/src/kiwano/core/EventListener.cpp @@ -35,6 +35,7 @@ namespace kiwano : type_(type) , callback_(callback) , running_(true) + , removeable_(false) { } diff --git a/src/kiwano/core/EventListener.h b/src/kiwano/core/EventListener.h index 147c22e4..a0795530 100644 --- a/src/kiwano/core/EventListener.h +++ b/src/kiwano/core/EventListener.h @@ -140,6 +140,10 @@ namespace kiwano SetEventType(KGE_EVENT(_EventTy)); } + /// \~chinese + /// @brief 接收消息 + void Receive(Event& evt); + private: bool running_; bool removeable_; @@ -193,4 +197,12 @@ namespace kiwano type_ = type; } + inline void EventListener::Receive(Event& evt) + { + if (type_ == evt.GetType() && callback_) + { + callback_(evt); + } + } + } diff --git a/src/kiwano/core/win32/helper.h b/src/kiwano/core/win32/helper.h index 940013ae..b7b5e0bf 100644 --- a/src/kiwano/core/win32/helper.h +++ b/src/kiwano/core/win32/helper.h @@ -28,12 +28,12 @@ namespace kiwano { if (FAILED(hr)) { - KGE_ERROR(L"Fatal error with HRESULT of %08X", hr); + KGE_ERROR(L"Failed with HRESULT of %08X", hr); StackWalker{}.ShowCallstack(); static char buffer[1024 + 1]; - sprintf_s(buffer, "Fatal error with HRESULT of %08X", hr); + sprintf_s(buffer, "Failed with HRESULT of %08X", hr); throw std::runtime_error(buffer); } } diff --git a/src/kiwano/kiwano.h b/src/kiwano/kiwano.h index 76a029d7..d99d537e 100644 --- a/src/kiwano/kiwano.h +++ b/src/kiwano/kiwano.h @@ -79,11 +79,8 @@ #include -#include - #include #include - #include #include #include @@ -92,9 +89,7 @@ #include #include #include - #include - #include #include #include diff --git a/src/kiwano/renderer/Font.cpp b/src/kiwano/renderer/Font.cpp index 4a1508dc..46fe442b 100644 --- a/src/kiwano/renderer/Font.cpp +++ b/src/kiwano/renderer/Font.cpp @@ -19,25 +19,48 @@ // THE SOFTWARE. #include +#include namespace kiwano { - Font::Font(String const& family, float size, uint32_t weight, bool italic) - : family(family) - , size(size) - , weight(weight) - , italic(italic) - , collection() + Font::Font() { } - Font::Font(FontCollection collection, String const& family, float size, uint32_t weight, bool italic) - : family(family) - , size(size) - , weight(weight) - , italic(italic) - , collection(collection) + Font::Font(String const& font_file) { + Load(font_file); + } + + Font::Font(Resource const& font_resource) + { + Load(font_resource); + } + + bool Font::Load(String const& font_file) + { + try + { + Renderer::instance().CreateFontCollection(*this, { font_file }); + } + catch (std::runtime_error&) + { + return false; + } + return true; + } + + bool Font::Load(Resource const& font_resource) + { + try + { + Renderer::instance().CreateFontCollection(*this, { font_resource }); + } + catch (std::runtime_error&) + { + return false; + } + return true; } } diff --git a/src/kiwano/renderer/Font.h b/src/kiwano/renderer/Font.h index 16876b28..8e916b92 100644 --- a/src/kiwano/renderer/Font.h +++ b/src/kiwano/renderer/Font.h @@ -19,51 +19,50 @@ // THE SOFTWARE. #pragma once -#include +#include +#include +#include +#include namespace kiwano { - // 字体粗细值 - struct FontWeight - { - enum Value : uint32_t - { - Thin = 100U, - ExtraLight = 200U, - Light = 300U, - Normal = 400U, - Medium = 500U, - Bold = 700U, - ExtraBold = 800U, - Black = 900U, - ExtraBlack = 950U - }; - }; + KGE_DECLARE_SMART_PTR(Font); + + class Renderer; // 字体 class Font + : public ObjectBase { - public: - String family; // 字体族 - float size; // 字号 - uint32_t weight; // 粗细值 - bool italic; // 是否斜体 - FontCollection collection; // 字体集 + friend class Renderer; public: - Font( - String const& family = L"", - float size = 18, - uint32_t weight = FontWeight::Normal, - bool italic = false - ); + Font(); - Font( - FontCollection collection, - String const& family = L"", - float size = 18, - uint32_t weight = FontWeight::Normal, - bool italic = false - ); + Font(String const& font_file); + + Font(Resource const& font_resource); + + bool Load(String const& font_file); + + bool Load(Resource const& font_resource); + + private: + ComPtr GetCollection() const; + + void SetCollection(ComPtr collection); + + private: + ComPtr collection_; }; + + inline ComPtr Font::GetCollection() const + { + return collection_; + } + + inline void Font::SetCollection(ComPtr collection) + { + collection_ = collection; + } } diff --git a/src/kiwano/renderer/FontCollection.cpp b/src/kiwano/renderer/FontCollection.cpp deleted file mode 100644 index df0118cc..00000000 --- a/src/kiwano/renderer/FontCollection.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2016-2018 Kiwano - Nomango -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include -#include - -namespace kiwano -{ - FontCollection::FontCollection() - { - } - - FontCollection::FontCollection(String const& file) - { - Load(file); - } - - FontCollection::FontCollection(Vector const& files) - { - Load(files); - } - - FontCollection::FontCollection(Resource const& res) - { - Load(res); - } - - FontCollection::FontCollection(Vector const& res_arr) - { - Load(res_arr); - } - - bool FontCollection::Load(String const& file) - { - Renderer::instance().CreateFontCollection(*this, { file }); - return IsValid(); - } - - bool FontCollection::Load(Vector const& files) - { - Renderer::instance().CreateFontCollection(*this, files); - return IsValid(); - } - - bool FontCollection::Load(Resource const& res) - { - Renderer::instance().CreateFontCollection(*this, { res }); - return IsValid(); - } - - bool FontCollection::Load(Vector const& res_arr) - { - Renderer::instance().CreateFontCollection(*this, res_arr); - return IsValid(); - } - - bool FontCollection::IsValid() const - { - return collection_ != nullptr; - } - -} diff --git a/src/kiwano/renderer/FontCollection.h b/src/kiwano/renderer/FontCollection.h deleted file mode 100644 index 89d9e856..00000000 --- a/src/kiwano/renderer/FontCollection.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) 2016-2018 Kiwano - Nomango -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#pragma once -#include -#include -#include - -namespace kiwano -{ - // 字体集 - class FontCollection - { - public: - FontCollection(); - - FontCollection(String const& file); - - FontCollection(Vector const& files); - - FontCollection(Resource const& res); - - FontCollection(Vector const& res_arr); - - // 从本地文件加载字体 - bool Load(String const& file); - - // 从多个本地文件加载字体 - bool Load(Vector const& files); - - // 从资源加载字体 - bool Load(Resource const& res); - - // 从多个资源加载字体 - bool Load(Vector const& res_arr); - - bool IsValid() const; - - public: - inline ComPtr GetFontCollection() const { return collection_; } - - inline void SetFontCollection(ComPtr collection) { collection_ = collection; } - - private: - ComPtr collection_; - }; -} diff --git a/src/kiwano/renderer/RenderTarget.cpp b/src/kiwano/renderer/RenderTarget.cpp index fdc88be1..3a08161d 100644 --- a/src/kiwano/renderer/RenderTarget.cpp +++ b/src/kiwano/renderer/RenderTarget.cpp @@ -333,12 +333,12 @@ namespace kiwano ThrowIfFailed(hr); } - void RenderTarget::DrawTexture(TexturePtr texture, Rect const& src_rect, Rect const& dest_rect) + void RenderTarget::DrawTexture(Texture const& texture, Rect const& src_rect, Rect const& dest_rect) { DrawTexture(texture, &src_rect, &dest_rect); } - void RenderTarget::DrawTexture(TexturePtr texture, const Rect* src_rect, const Rect* dest_rect) + void RenderTarget::DrawTexture(Texture const& texture, const Rect* src_rect, const Rect* dest_rect) { HRESULT hr = S_OK; if (!render_target_) @@ -346,19 +346,14 @@ namespace kiwano hr = E_UNEXPECTED; } - if (!texture) + if (SUCCEEDED(hr) && texture.IsValid()) { - hr = E_INVALIDARG; - } - - if (SUCCEEDED(hr) && texture->IsValid()) - { - auto mode = (texture->GetBitmapInterpolationMode() == InterpolationMode::Linear) + auto mode = (texture.GetBitmapInterpolationMode() == InterpolationMode::Linear) ? D2D1_BITMAP_INTERPOLATION_MODE_LINEAR : D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR; render_target_->DrawBitmap( - texture->GetBitmap().get(), + texture.GetBitmap().get(), dest_rect ? &DX::ConvertToRectF(*dest_rect) : nullptr, opacity_, mode, @@ -381,13 +376,14 @@ namespace kiwano if (SUCCEEDED(hr)) { + const TextStyle& style = layout.GetStyle(); text_renderer_->SetTextStyle( opacity_, - DX::ConvertToColorF(layout.GetTextStyle().color), - layout.GetTextStyle().outline, - DX::ConvertToColorF(layout.GetTextStyle().outline_color), - layout.GetTextStyle().outline_width, - GetStrokeStyle(layout.GetTextStyle().outline_stroke).get() + DX::ConvertToColorF(style.color), + style.outline, + DX::ConvertToColorF(style.outline_color), + style.outline_width, + GetStrokeStyle(style.outline_stroke).get() ); hr = layout.GetTextLayout()->Draw(nullptr, text_renderer_.get(), offset.x, offset.y); diff --git a/src/kiwano/renderer/RenderTarget.h b/src/kiwano/renderer/RenderTarget.h index 10b163f2..3d584fb0 100644 --- a/src/kiwano/renderer/RenderTarget.h +++ b/src/kiwano/renderer/RenderTarget.h @@ -20,6 +20,7 @@ #pragma once #include +#include #include #include #include @@ -106,13 +107,13 @@ namespace kiwano ); void DrawTexture( - TexturePtr texture, + Texture const& texture, Rect const& src_rect, Rect const& dest_rect ); void DrawTexture( - TexturePtr texture, + Texture const& texture, const Rect* src_rect = nullptr, const Rect* dest_rect = nullptr ); diff --git a/src/kiwano/renderer/Renderer.cpp b/src/kiwano/renderer/Renderer.cpp index fac28939..f04f2d26 100644 --- a/src/kiwano/renderer/Renderer.cpp +++ b/src/kiwano/renderer/Renderer.cpp @@ -577,7 +577,7 @@ namespace kiwano } } - void Renderer::CreateFontCollection(FontCollection& collection, Vector const& file_paths) + void Renderer::CreateFontCollection(Font& font, Vector const& file_paths) { HRESULT hr = S_OK; if (!d2d_res_) @@ -620,18 +620,15 @@ namespace kiwano if (SUCCEEDED(hr)) { - collection.SetFontCollection(font_collection); + font.SetCollection(font_collection); } } } - if (FAILED(hr)) - { - KGE_WARN(L"Load font failed with HRESULT of %08X!", hr); - } + ThrowIfFailed(hr); } - void Renderer::CreateFontCollection(FontCollection& collection, Vector const& res_arr) + void Renderer::CreateFontCollection(Font& font, Vector const& res_arr) { HRESULT hr = S_OK; if (!d2d_res_) @@ -658,18 +655,15 @@ namespace kiwano if (SUCCEEDED(hr)) { - collection.SetFontCollection(font_collection); + font.SetCollection(font_collection); } } } - if (FAILED(hr)) - { - KGE_WARN(L"Load font failed with HRESULT of %08X!", hr); - } + ThrowIfFailed(hr); } - void Renderer::CreateTextFormat(TextFormat& format, Font const& font) + void Renderer::CreateTextFormat(TextLayout& layout) { HRESULT hr = S_OK; if (!d2d_res_) @@ -680,18 +674,28 @@ namespace kiwano ComPtr output; if (SUCCEEDED(hr)) { - hr = d2d_res_->CreateTextFormat(output, font); + const TextStyle& style = layout.GetStyle(); + + hr = d2d_res_->CreateTextFormat( + output, + style.font_family, + style.font ? style.font->GetCollection() : nullptr, + DWRITE_FONT_WEIGHT(style.font_weight), + style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + style.font_size + ); } if (SUCCEEDED(hr)) { - format.SetTextFormat(output); + layout.SetTextFormat(output); } ThrowIfFailed(hr); } - void Renderer::CreateTextLayout(TextLayout& layout, String const& text, TextFormat const& format) + void Renderer::CreateTextLayout(TextLayout& layout) { HRESULT hr = S_OK; if (!d2d_res_) @@ -704,8 +708,8 @@ namespace kiwano { hr = d2d_res_->CreateTextLayout( output, - text, - format.GetTextFormat() + layout.GetText(), + layout.GetTextFormat() ); } diff --git a/src/kiwano/renderer/Renderer.h b/src/kiwano/renderer/Renderer.h index bab77019..23eb32d0 100644 --- a/src/kiwano/renderer/Renderer.h +++ b/src/kiwano/renderer/Renderer.h @@ -23,6 +23,8 @@ #include #include #include +#include +#include #if defined(KGE_USE_DIRECTX10) # include "win32/D3D10DeviceResources.h" @@ -99,24 +101,21 @@ namespace kiwano ); void CreateFontCollection( - FontCollection& collection, + Font& font, Vector const& file_paths ); void CreateFontCollection( - FontCollection& collection, + Font& font, Vector const& res_arr ); void CreateTextFormat( - TextFormat& format, - Font const& font + TextLayout& layout ); void CreateTextLayout( - TextLayout& layout, - String const& text, - TextFormat const& format + TextLayout& layout ); void CreateLineGeometry( diff --git a/src/kiwano/renderer/TextLayout.cpp b/src/kiwano/renderer/TextLayout.cpp index 69d9b8cf..b48696fa 100644 --- a/src/kiwano/renderer/TextLayout.cpp +++ b/src/kiwano/renderer/TextLayout.cpp @@ -24,132 +24,109 @@ namespace kiwano { - // - // TextFormat - // - - TextFormat::TextFormat() - { - } - - TextFormat::TextFormat(Font const& font) - { - Update(font); - } - - void TextFormat::Update(Font const& font) - { - Renderer::instance().CreateTextFormat(*this, font); - } - - - // - // TextLayout - // - TextLayout::TextLayout() + : dirty_flag_(DirtyFlag::Clean) { } - TextLayout::TextLayout(String const& text, Font const& font, TextStyle const& style) + void TextLayout::Update() { - UpdateFont(font); - SetTextStyle(style); - UpdateLayout(text); - } + if (!IsDirty()) + return; - void TextLayout::UpdateFont(Font const& font) - { - text_format_.Update(font); - } - - void TextLayout::UpdateLayout(String const& text) - { - if (text.empty()) + if (text_.empty()) { - text_format_.SetTextFormat(nullptr); - SetTextLayout(nullptr); + text_format_.reset(); + text_layout_.reset(); return; } - Renderer::instance().CreateTextLayout( - *this, - text, - text_format_ - ); - - HRESULT hr = text_layout_ ? S_OK : E_FAIL; - - if (SUCCEEDED(hr)) + if (!text_format_ || (dirty_flag_ & DirtyFlag::DirtyFormat)) { - if (style_.line_spacing == 0.f) + Renderer::instance().CreateTextFormat(*this); + } + + if (dirty_flag_ & DirtyFlag::DirtyLayout) + { + Renderer::instance().CreateTextLayout(*this); + + if (text_layout_) { - hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); - } - else - { - hr = text_layout_->SetLineSpacing( - DWRITE_LINE_SPACING_METHOD_UNIFORM, - style_.line_spacing, - style_.line_spacing * 0.8f - ); + SetAlignment(style_.alignment); + SetWrapWidth(style_.wrap_width); + SetLineSpacing(style_.line_spacing); } } - if (SUCCEEDED(hr)) - { - hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment)); - } - - if (SUCCEEDED(hr)) - { - hr = text_layout_->SetWordWrapping((style_.wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP); - } - - if (SUCCEEDED(hr)) - { - if (style_.underline) - { - hr = text_layout_->SetUnderline(true, { 0, UINT32(text.length()) }); - } - } - - if (SUCCEEDED(hr)) - { - if (style_.strikethrough) - { - text_layout_->SetStrikethrough(true, { 0, UINT32(text.length()) }); - } - } - - if (SUCCEEDED(hr)) - { - if (style_.wrap_width > 0) - { - hr = text_layout_->SetMaxWidth(style_.wrap_width); - } - else - { - // Fix the layout width when the text does not wrap - DWRITE_TEXT_METRICS metrics; - hr = text_layout_->GetMetrics(&metrics); - - if (SUCCEEDED(hr)) - { - hr = text_layout_->SetMaxWidth(metrics.width); - } - } - } - - ThrowIfFailed(hr); + dirty_flag_ = DirtyFlag::Clean; } - uint32_t TextLayout::GetLineCount() + void TextLayout::SetText(const String& text) { + text_ = text; + dirty_flag_ |= DirtyFlag::DirtyLayout; + } + + void TextLayout::SetStyle(const TextStyle& style) + { + style_ = style; + dirty_flag_ |= DirtyFlag::DirtyLayout; + } + + void TextLayout::SetFont(FontPtr font) + { + if (style_.font != font) + { + style_.font = font; + dirty_flag_ |= DirtyFlag::DirtyFormat; + } + } + + void TextLayout::SetFontFamily(String const& family) + { + if (style_.font_family != family) + { + style_.font_family = family; + dirty_flag_ |= DirtyFlag::DirtyFormat; + } + } + + void TextLayout::SetFontSize(float size) + { + if (style_.font_size != size) + { + style_.font_size = size; + dirty_flag_ |= DirtyFlag::DirtyFormat; + } + } + + void TextLayout::SetFontWeight(uint32_t weight) + { + if (style_.font_weight != weight) + { + style_.font_weight = weight; + dirty_flag_ |= DirtyFlag::DirtyFormat; + } + } + + void TextLayout::SetItalic(bool italic) + { + if (style_.italic != italic) + { + style_.italic = italic; + dirty_flag_ |= DirtyFlag::DirtyFormat; + } + } + + uint32_t TextLayout::GetLineCount() const + { + // Force to update layout + const_cast(this)->Update(); + if (text_layout_) { DWRITE_TEXT_METRICS metrics; - if (SUCCEEDED(text_layout_->GetMetrics(&metrics))) + if (SUCCEEDED(GetTextLayout()->GetMetrics(&metrics))) { return metrics.lineCount; } @@ -159,10 +136,13 @@ namespace kiwano Size TextLayout::GetLayoutSize() const { + // Force to update layout + const_cast(this)->Update(); + if (text_layout_) { DWRITE_TEXT_METRICS metrics; - if (SUCCEEDED(text_layout_->GetMetrics(&metrics))) + if (SUCCEEDED(GetTextLayout()->GetMetrics(&metrics))) { return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height) : Size(metrics.width, metrics.height); } @@ -170,4 +150,98 @@ namespace kiwano return Size(); } + void TextLayout::SetWrapWidth(float wrap_width) + { + style_.wrap_width = wrap_width; + + if (text_layout_) + { + HRESULT hr = S_OK; + bool enable_wrapping = (wrap_width > 0); + + if (SUCCEEDED(hr)) + { + hr = text_layout_->SetWordWrapping(enable_wrapping ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP); + } + + if (SUCCEEDED(hr)) + { + if (enable_wrapping) + { + hr = text_layout_->SetMaxWidth(wrap_width); + } + else + { + // Fix the layout width when the text does not wrap + DWRITE_TEXT_METRICS metrics; + hr = text_layout_->GetMetrics(&metrics); + + if (SUCCEEDED(hr)) + { + hr = text_layout_->SetMaxWidth(metrics.width); + } + } + } + ThrowIfFailed(hr); + } + } + + void TextLayout::SetLineSpacing(float line_spacing) + { + style_.line_spacing = line_spacing; + + if (text_layout_) + { + HRESULT hr = S_OK; + if (line_spacing == 0.f) + { + hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); + } + else + { + hr = text_layout_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, line_spacing, line_spacing * 0.8f); + } + ThrowIfFailed(hr); + } + } + + void TextLayout::SetAlignment(TextAlign align) + { + style_.alignment = align; + + if (text_layout_) + { + HRESULT hr = text_layout_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(align)); + ThrowIfFailed(hr); + } + } + + void TextLayout::SetUnderline(bool enable, uint32_t start, uint32_t length) + { + // Force to update layout + Update(); + + HRESULT hr = text_layout_ ? S_OK : E_FAIL; + + if (SUCCEEDED(hr)) + { + hr = text_layout_->SetUnderline(enable, { start, length }); + } + ThrowIfFailed(hr); + } + + void TextLayout::SetStrikethrough(bool enable, uint32_t start, uint32_t length) + { + // Force to update layout + Update(); + + HRESULT hr = text_layout_ ? S_OK : E_FAIL; + + if (SUCCEEDED(hr)) + { + hr = text_layout_->SetStrikethrough(enable, { start, length }); + } + ThrowIfFailed(hr); + } + } diff --git a/src/kiwano/renderer/TextLayout.h b/src/kiwano/renderer/TextLayout.h index 58049bea..d6424eaa 100644 --- a/src/kiwano/renderer/TextLayout.h +++ b/src/kiwano/renderer/TextLayout.h @@ -20,63 +20,209 @@ #pragma once #include -#include -#include +#include namespace kiwano { - // 文本格式化 - class KGE_API TextFormat - { - public: - TextFormat(); - - TextFormat(Font const& font); - - void Update(Font const& font); - - public: - inline ComPtr GetTextFormat() const { return text_format_; } - - inline void SetTextFormat(ComPtr format) { text_format_ = format; } - - private: - ComPtr text_format_; - }; - - - // 文本布局 + /// \~chinese + /// @brief 文本布局 class KGE_API TextLayout { public: + /// \~chinese + /// @brief 构造空的文本布局 TextLayout(); - TextLayout(String const& text, Font const& font, TextStyle const& style); + /// \~chinese + /// @brief 文本布局是否有效 + bool IsValid() const; - void UpdateFont(Font const& font); + /// \~chinese + /// @brief 文本布局是否陈旧 + bool IsDirty() const; - void UpdateLayout(String const& text); + /// \~chinese + /// @brief 更新文本布局 + /// @note 文本布局是懒更新的,在修改文本布局的属性后需要手动更新 + void Update(); - uint32_t GetLineCount(); + /// \~chinese + /// @brief 获取文本 + const String& GetText() const; + /// \~chinese + /// @brief 获取文本样式 + const TextStyle& GetStyle() const; + + /// \~chinese + /// @brief 获取文本行数 + uint32_t GetLineCount() const; + + /// \~chinese + /// @brief 获取文本布局大小 Size GetLayoutSize() const; - inline TextStyle& GetTextStyle() { return style_; } - inline TextStyle const& GetTextStyle() const { return style_; } - inline void SetTextStyle(TextStyle const& style) { style_ = style; } + /// \~chinese + /// @brief 设置文本 + void SetText(const String& text); + + /// \~chinese + /// @brief 设置文本样式 + void SetStyle(const TextStyle& style); + + /// \~chinese + /// @brief 设置字体 + void SetFont(FontPtr font); + + /// \~chinese + /// @brief 设置字体族 + void SetFontFamily(String const& family); + + /// \~chinese + /// @brief 设置字号(默认值为 18) + void SetFontSize(float size); + + /// \~chinese + /// @brief 设置字体粗细值(默认值为 FontWeight::Normal) + void SetFontWeight(uint32_t weight); + + /// \~chinese + /// @brief 设置文字颜色(默认值为 Color::White) + void SetColor(Color const& color); + + /// \~chinese + /// @brief 设置文字斜体(默认值为 false) + void SetItalic(bool italic); + + /// \~chinese + /// @brief 设置文本自动换行的宽度 + void SetWrapWidth(float wrap_width); + + /// \~chinese + /// @brief 设置行间距(默认为 0) + void SetLineSpacing(float line_spacing); + + /// \~chinese + /// @brief 设置对齐方式 + void SetAlignment(TextAlign align); + + /// \~chinese + /// @brief 设置是否显示描边 + void SetOutline(bool enable); + + /// \~chinese + /// @brief 设置描边颜色 + void SetOutlineColor(Color const& outline_color); + + /// \~chinese + /// @brief 设置描边线宽 + void SetOutlineWidth(float outline_width); + + /// \~chinese + /// @brief 设置描边线相交样式 + void SetOutlineStroke(StrokeStyle outline_stroke); + + /// \~chinese + /// @brief 设置下划线 + /// @param enable 是否显示下划线 + /// @param start 起始位置 + /// @param length 长度 + void SetUnderline(bool enable, uint32_t start, uint32_t length); + + /// \~chinese + /// @brief 设置删除线 + /// @param enable 是否显示删除线 + /// @param start 起始位置 + /// @param length 长度 + void SetStrikethrough(bool enable, uint32_t start, uint32_t length); public: - inline TextFormat GetTextFormat() const { return text_format_; } + ComPtr GetTextFormat() const; - inline ComPtr GetTextLayout() const { return text_layout_; } + void SetTextFormat(ComPtr format); - inline void SetTextLayout(ComPtr layout) { text_layout_ = layout; } + ComPtr GetTextLayout() const; - inline operator bool() const { return static_cast(text_layout_); } + void SetTextLayout(ComPtr layout); private: + enum DirtyFlag : uint8_t + { + Clean = 0, + DirtyFormat = 1, + DirtyLayout = 1 << 1, + }; + uint8_t dirty_flag_; + + ComPtr text_format_; + ComPtr text_layout_; + + String text_; TextStyle style_; - TextFormat text_format_; - mutable ComPtr text_layout_; }; + + inline bool TextLayout::IsValid() const + { + return !!text_layout_; + } + + inline bool TextLayout::IsDirty() const + { + return dirty_flag_ != DirtyFlag::Clean; + } + + inline const String& TextLayout::GetText() const + { + return text_; + } + + inline const TextStyle& TextLayout::GetStyle() const + { + return style_; + } + + inline ComPtr TextLayout::GetTextFormat() const + { + return text_format_; + } + + inline ComPtr TextLayout::GetTextLayout() const + { + return text_layout_; + } + + inline void TextLayout::SetColor(Color const& color) + { + style_.color = color; + } + + inline void TextLayout::SetTextFormat(ComPtr format) + { + text_format_ = format; + } + + inline void TextLayout::SetTextLayout(ComPtr layout) + { + text_layout_ = layout; + } + + inline void TextLayout::SetOutline(bool enable) + { + style_.outline = enable; + } + + inline void TextLayout::SetOutlineColor(Color const& outline_color) + { + style_.outline_color = outline_color; + } + + inline void TextLayout::SetOutlineWidth(float outline_width) + { + style_.outline_width = outline_width; + } + + inline void TextLayout::SetOutlineStroke(StrokeStyle outline_stroke) + { + style_.outline_stroke = outline_stroke; + } } diff --git a/src/kiwano/2d/TextStyle.hpp b/src/kiwano/renderer/TextStyle.hpp similarity index 64% rename from src/kiwano/2d/TextStyle.hpp rename to src/kiwano/renderer/TextStyle.hpp index b8471816..99c9c138 100644 --- a/src/kiwano/2d/TextStyle.hpp +++ b/src/kiwano/renderer/TextStyle.hpp @@ -21,6 +21,7 @@ #pragma once #include #include +#include namespace kiwano { @@ -35,6 +36,26 @@ namespace kiwano Center ///< 居中对齐 }; + /** + * \~chinese + * @brief 字体粗细值 + */ + struct FontWeight + { + enum Value : uint32_t + { + Thin = 100U, + ExtraLight = 200U, + Light = 300U, + Normal = 400U, ///< 正常 + Medium = 500U, + Bold = 700U, + ExtraBold = 800U, + Black = 900U, + ExtraBlack = 950U + }; + }; + /** * \~chinese * @brief 文本样式 @@ -42,12 +63,15 @@ namespace kiwano class KGE_API TextStyle { public: + FontPtr font; ///< 字体 + String font_family; ///< 字体族 + float font_size; ///< 字号 + uint32_t font_weight; ///< 粗细值 + bool italic; ///< 是否斜体 Color color; ///< 颜色 TextAlign alignment; ///< 对齐方式 float wrap_width; ///< 自动换行宽度 float line_spacing; ///< 行间距 - bool underline; ///< 下划线 - bool strikethrough; ///< 删除线 bool outline; ///< 描边 Color outline_color; ///< 描边颜色 float outline_width; ///< 描边线宽 @@ -57,35 +81,44 @@ namespace kiwano /** * \~chinese * @brief 构建文本样式 + * @param font 字体 + * @param font_family 字体族 + * @param font_size 字体大小 + * @param font_weight 字体粗细 + * @param italic 斜体 * @param color 颜色 * @param alignment 对齐方式 * @param wrap_width 自动换行宽度 * @param line_spacing 行间距 - * @param underline 下划线 - * @param strikethrough 删除线 * @param outline 描边 * @param outline_color 描边颜色 * @param outline_width 描边线宽 * @param outline_stroke 描边线相交样式 */ TextStyle( - Color color = Color::White, - TextAlign alignment = TextAlign::Left, - float wrap_width = 0.f, - float line_spacing = 0.f, - bool underline = false, - bool strikethrough = false, - bool outline = false, - Color outline_color = Color(Color::Black, 0.5), - float outline_width = 1.f, - StrokeStyle outline_stroke = StrokeStyle::Round + FontPtr font = nullptr, + const String& font_family = String(), + float font_size = 18, + uint32_t font_weight = FontWeight::Normal, + bool italic = false, + Color color = Color::White, + TextAlign alignment = TextAlign::Left, + float wrap_width = 0.f, + float line_spacing = 0.f, + bool outline = false, + Color outline_color = Color(Color::Black, 0.5), + float outline_width = 1.f, + StrokeStyle outline_stroke = StrokeStyle::Round ) - : color(color) + : font(nullptr) + , font_family(font_family) + , font_size(font_size) + , font_weight(font_weight) + , italic(italic) + , color(color) , alignment(alignment) , wrap_width(wrap_width) , line_spacing(line_spacing) - , underline(underline) - , strikethrough(strikethrough) , outline(outline) , outline_color(outline_color) , outline_width(outline_width) diff --git a/src/kiwano/renderer/win32/D2DDeviceResources.cpp b/src/kiwano/renderer/win32/D2DDeviceResources.cpp index 0c1914d7..47c63a67 100644 --- a/src/kiwano/renderer/win32/D2DDeviceResources.cpp +++ b/src/kiwano/renderer/win32/D2DDeviceResources.cpp @@ -65,7 +65,12 @@ namespace kiwano HRESULT CreateTextFormat( _Out_ ComPtr& text_format, - _In_ Font const& font + _In_ String const& family, + _In_ ComPtr collection, + _In_ DWRITE_FONT_WEIGHT weight, + _In_ DWRITE_FONT_STYLE style, + _In_ DWRITE_FONT_STRETCH stretch, + _In_ FLOAT font_size ) override; HRESULT CreateTextLayout( @@ -435,19 +440,20 @@ namespace kiwano return hr; } - HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr & text_format, _In_ Font const & font) + HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr & text_format, _In_ String const& family, _In_ ComPtr collection, + _In_ DWRITE_FONT_WEIGHT weight, _In_ DWRITE_FONT_STYLE style, _In_ DWRITE_FONT_STRETCH stretch, _In_ FLOAT font_size) { if (!dwrite_factory_) return E_UNEXPECTED; ComPtr output; HRESULT hr = dwrite_factory_->CreateTextFormat( - font.family.c_str(), - font.collection.GetFontCollection().get(), - DWRITE_FONT_WEIGHT(font.weight), - font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, - font.size, + family.c_str(), + collection.get(), + weight, + style, + stretch, + font_size, L"", &output ); diff --git a/src/kiwano/renderer/win32/D2DDeviceResources.h b/src/kiwano/renderer/win32/D2DDeviceResources.h index be14483d..04565b8b 100644 --- a/src/kiwano/renderer/win32/D2DDeviceResources.h +++ b/src/kiwano/renderer/win32/D2DDeviceResources.h @@ -19,10 +19,10 @@ // THE SOFTWARE. #pragma once -#include -#include #include #include +#include +#include #include #include #include @@ -216,7 +216,12 @@ namespace kiwano virtual HRESULT CreateTextFormat( _Out_ ComPtr& text_format, - _In_ Font const& font + _In_ String const& family, + _In_ ComPtr collection, + _In_ DWRITE_FONT_WEIGHT weight, + _In_ DWRITE_FONT_STYLE style, + _In_ DWRITE_FONT_STRETCH stretch, + _In_ FLOAT font_size ) = 0; virtual HRESULT CreateTextLayout( diff --git a/src/kiwano/utils/ResourceCache.cpp b/src/kiwano/utils/ResourceCache.cpp index 415f0dfa..8c6c3b43 100644 --- a/src/kiwano/utils/ResourceCache.cpp +++ b/src/kiwano/utils/ResourceCache.cpp @@ -22,9 +22,6 @@ #include #include #include -#include -#include - namespace kiwano { @@ -187,29 +184,6 @@ namespace kiwano return false; } - bool ResourceCache::AddFrame(String const& id, String const& file_path) - { - FramePtr ptr = new (std::nothrow) Frame; - if (ptr) - { - if (ptr->Load(file_path)) - { - return AddFrame(id, ptr); - } - } - return false; - } - - bool ResourceCache::AddFrame(String const & id, FramePtr frame) - { - if (frame) - { - object_cache_.insert(std::make_pair(id, frame)); - return true; - } - return false; - } - size_t ResourceCache::AddFrameSequence(String const& id, Vector const& files) { if (files.empty()) @@ -233,7 +207,7 @@ namespace kiwano if (!frames.empty()) { FrameSequencePtr fs = new (std::nothrow) FrameSequence(frames); - return AddFrameSequence(id, fs); + return AddObject(id, fs); } return 0; } @@ -273,20 +247,10 @@ namespace kiwano } FrameSequencePtr fs = new (std::nothrow) FrameSequence(frames); - return AddFrameSequence(id, fs); + return AddObject(id, fs); } - size_t ResourceCache::AddFrameSequence(String const & id, FrameSequencePtr frames) - { - if (frames) - { - object_cache_.insert(std::make_pair(id, frames)); - return frames->GetFrames().size(); - } - return 0; - } - - bool ResourceCache::AddObjectBase(String const& id, ObjectBasePtr obj) + bool ResourceCache::AddObject(String const& id, ObjectBasePtr obj) { if (obj) { @@ -296,59 +260,6 @@ namespace kiwano return false; } - bool ResourceCache::AddGifImage(String const& id, GifImagePtr gif) - { - if (gif && gif->IsValid()) - { - object_cache_.insert(std::make_pair(id, gif)); - return true; - } - return false; - } - - bool ResourceCache::AddGifImage(String const& id, String const& file_path) - { - GifImagePtr gif = new (std::nothrow) GifImage; - if (gif && gif->Load(file_path)) - { - return AddGifImage(id, gif); - } - return false; - } - - bool ResourceCache::AddFontCollection(String const& id, FontCollection const& collection) - { - if (collection.IsValid()) - { - font_collection_cache_.insert(std::make_pair(id, collection)); - return true; - } - return false; - } - - FramePtr ResourceCache::GetFrame(String const & id) const - { - return Get(id); - } - - FrameSequencePtr ResourceCache::GetFrameSequence(String const & id) const - { - return Get(id); - } - - GifImagePtr ResourceCache::GetGifImage(String const& id) const - { - return Get(id); - } - - FontCollection ResourceCache::GetFontCollection(String const& id) const - { - auto iter = font_collection_cache_.find(id); - if (iter != font_collection_cache_.end()) - return iter->second; - return FontCollection(); - } - void ResourceCache::Remove(String const & id) { object_cache_.erase(id); @@ -357,7 +268,14 @@ namespace kiwano void ResourceCache::Clear() { object_cache_.clear(); - font_collection_cache_.clear(); + } + + ObjectBasePtr ResourceCache::Get(String const& id) const + { + auto iter = object_cache_.find(id); + if (iter == object_cache_.end()) + return nullptr; + return (*iter).second; } } @@ -378,13 +296,21 @@ namespace kiwano if (type && (*type) == L"gif") { // GIF image - return loader->AddGifImage(*id, gdata->path + (*file)); + GifImagePtr gif = new (std::nothrow) GifImage; + if (gif && gif->Load(gdata->path + (*file))) + { + return loader->AddObject(*id, gif); + } } if (file && !(*file).empty()) { // Simple image - return loader->AddFrame(*id, gdata->path + (*file)); + FramePtr frame = new (std::nothrow) Frame; + if (frame && frame->Load(gdata->path + (*file))) + { + return loader->AddObject(*id, frame); + } } return false; } @@ -407,7 +333,7 @@ namespace kiwano } } FrameSequencePtr frame_seq = new FrameSequence(frames); - return !!loader->AddFrameSequence(*id, frame_seq); + return !!loader->AddObject(*id, frame_seq); } return false; } @@ -429,30 +355,27 @@ namespace kiwano else { // Simple image - return loader->AddFrame(*id, gdata->path + (*file)); + FramePtr frame = new (std::nothrow) Frame; + if (frame && frame->Load(gdata->path + (*file))) + { + return loader->AddObject(*id, frame); + } } } } return false; } - bool LoadFontsFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const Vector* files) + bool LoadFontsFromData(ResourceCache* loader, GlobalData* gdata, const String* id, const String* file) { if (!gdata || !id) return false; - // Font Collection - if (files) + if (file) { - Vector files_copy(*files); - for (auto& file : files_copy) + FontPtr font = new (std::nothrow) Font; + if (font && font->Load(gdata->path + (*file))) { - file = gdata->path + file; - } - - FontCollection collection; - if (collection.Load(files_copy)) - { - return loader->AddFontCollection(*id, collection); + return loader->AddObject(*id, font); } } return false; @@ -512,20 +435,13 @@ namespace kiwano { for (const auto& font : json_data[L"fonts"]) { - String id; + const String *id = nullptr, *file = nullptr; - if (font.count(L"id")) id = font[L"id"].as_string(); - if (font.count(L"files")) - { - Vector files; - files.reserve(font[L"files"].size()); - for (const auto& file : font[L"files"]) - { - files.push_back(file.as_string()); - } - if (!LoadFontsFromData(loader, &global_data, &id, &files)) - return false; - } + if (font.count(L"id")) id = &font[L"id"].as_string(); + if (font.count(L"file")) file = &font[L"file"].as_string(); + + if (!LoadFontsFromData(loader, &global_data, id, file)) + return false; } } return true; @@ -587,18 +503,11 @@ namespace kiwano { for (auto font = fonts->FirstChildElement(); font; font = font->NextSiblingElement()) { - String id; + String id, file; if (auto attr = font->Attribute(L"id")) id.assign(attr); + if (auto attr = font->Attribute(L"file")) file.assign(attr); - Vector files_arr; - for (auto file = font->FirstChildElement(); file; file = file->NextSiblingElement()) - { - if (auto path = file->Attribute(L"path")) - { - files_arr.push_back(path); - } - } - if (!LoadFontsFromData(loader, &global_data, &id, &files_arr)) + if (!LoadFontsFromData(loader, &global_data, &id, &file)) return false; } } diff --git a/src/kiwano/utils/ResourceCache.h b/src/kiwano/utils/ResourceCache.h index 40e3f60a..db4be9c9 100644 --- a/src/kiwano/utils/ResourceCache.h +++ b/src/kiwano/utils/ResourceCache.h @@ -23,6 +23,7 @@ #include #include #include +#include #include <3rd-party/tinyxml2/tinyxml2.h> namespace kiwano @@ -46,11 +47,8 @@ namespace kiwano // 从 XML 文档对象加载资源信息 bool LoadFromXml(const tinyxml2::XMLDocument* doc); - // 添加帧图像 - bool AddFrame(String const& id, String const& file_path); - - // 添加帧图像 - bool AddFrame(String const& id, FramePtr frame); + // 添加对象 + bool AddObject(String const& id, ObjectBasePtr obj); // 添加序列帧 size_t AddFrameSequence(String const& id, Vector const& files); @@ -59,46 +57,18 @@ namespace kiwano // 按行列数裁剪图片 size_t AddFrameSequence(String const& id, String const& file_path, int cols, int rows = 1, float padding_x = 0, float padding_y = 0); - // 添加序列帧 - size_t AddFrameSequence(String const& id, FrameSequencePtr frames); - - // 添加对象 - bool AddObjectBase(String const& id, ObjectBasePtr obj); - - // 添加 GIF 图像 - bool AddGifImage(String const& id, GifImagePtr gif); - - // 添加 GIF 图像 - bool AddGifImage(String const& id, String const& file_path); - - // 添加字体集 - bool AddFontCollection(String const& id, FontCollection const& collection); - - // 获取帧图像 - FramePtr GetFrame(String const& id) const; - - // 获取序列帧 - FrameSequencePtr GetFrameSequence(String const& id) const; - - // 获取 GIF 图像 - GifImagePtr GetGifImage(String const& id) const; - - // 获取字体集 - FontCollection GetFontCollection(String const& id) const; - // 删除指定资源 void Remove(String const& id); // 清空所有资源 void Clear(); + ObjectBasePtr Get(String const& id) const; + template - _Ty* Get(String const& id) const + SmartPtr<_Ty> Get(String const& id) const { - auto iter = object_cache_.find(id); - if (iter == object_cache_.end()) - return nullptr; - return const_cast<_Ty*>(dynamic_cast((*iter).second.get())); + return dynamic_cast<_Ty*>(Get(id).get()); } private: @@ -107,7 +77,6 @@ namespace kiwano virtual ~ResourceCache(); private: - UnorderedMap object_cache_; - UnorderedMap font_collection_cache_; + UnorderedMap object_cache_; }; }