Update Font & TextLayout & TextActor

This commit is contained in:
Nomango 2019-12-26 19:25:43 +08:00
parent f057b3b737
commit 8629d65797
30 changed files with 765 additions and 831 deletions

View File

@ -28,7 +28,6 @@
<ClInclude Include="..\..\src\kiwano\2d\Stage.h" />
<ClInclude Include="..\..\src\kiwano\2d\Sprite.h" />
<ClInclude Include="..\..\src\kiwano\2d\TextActor.h" />
<ClInclude Include="..\..\src\kiwano\2d\TextStyle.hpp" />
<ClInclude Include="..\..\src\kiwano\2d\Transform.h" />
<ClInclude Include="..\..\src\kiwano\2d\Transition.h" />
<ClInclude Include="..\..\src\kiwano\core\AsyncTask.h" />
@ -61,10 +60,10 @@
<ClInclude Include="..\..\src\kiwano\renderer\Brush.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Color.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Font.h" />
<ClInclude Include="..\..\src\kiwano\renderer\FontCollection.h" />
<ClInclude Include="..\..\src\kiwano\renderer\Geometry.h" />
<ClInclude Include="..\..\src\kiwano\renderer\GifImage.h" />
<ClInclude Include="..\..\src\kiwano\renderer\StrokeStyle.h" />
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp" />
<ClInclude Include="..\..\src\kiwano\renderer\Texture.h" />
<ClInclude Include="..\..\src\kiwano\renderer\TextureCache.h" />
<ClInclude Include="..\..\src\kiwano\renderer\LayerArea.h" />
@ -126,7 +125,6 @@
<ClCompile Include="..\..\src\kiwano\renderer\Brush.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Color.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Font.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\FontCollection.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Geometry.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\GifImage.cpp" />
<ClCompile Include="..\..\src\kiwano\renderer\Texture.cpp" />

View File

@ -48,9 +48,6 @@
<ClInclude Include="..\..\src\kiwano\2d\Sprite.h">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\TextStyle.hpp">
<Filter>2d</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Transition.h">
<Filter>2d</Filter>
</ClInclude>
@ -201,9 +198,6 @@
<ClInclude Include="..\..\src\kiwano\renderer\RenderTarget.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\FontCollection.h">
<Filter>renderer</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\2d\Transform.h">
<Filter>2d</Filter>
</ClInclude>
@ -270,6 +264,9 @@
<ClInclude Include="..\..\src\kiwano\core\RefCounter.h">
<Filter>core</Filter>
</ClInclude>
<ClInclude Include="..\..\src\kiwano\renderer\TextStyle.hpp">
<Filter>renderer</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\src\kiwano\ui\Button.cpp">
@ -407,9 +404,6 @@
<ClCompile Include="..\..\src\kiwano\renderer\RenderTarget.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\renderer\FontCollection.cpp">
<Filter>renderer</Filter>
</ClCompile>
<ClCompile Include="..\..\src\kiwano\2d\Transform.cpp">
<Filter>2d</Filter>
</ClCompile>

View File

@ -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);
}

View File

@ -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_;

View File

@ -20,6 +20,7 @@
#include <kiwano/2d/DebugActor.h>
#include <kiwano/renderer/Renderer.h>
#include <kiwano/core/Logger.h>
#include <psapi.h>
#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);

View File

@ -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();
}
}

View File

@ -161,6 +161,7 @@ namespace kiwano
GifImagePtr gif_;
GifImage::Frame frame_;
TexturePtr saved_frame_;
TexturePtr frame_to_render_;
TextureRenderTarget frame_rt_;
};

View File

@ -108,7 +108,7 @@ namespace kiwano
{
PrepareRender(rt);
rt->DrawTexture(frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
rt->DrawTexture(*frame_->GetTexture(), &frame_->GetCropRect(), &GetBounds());
}
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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())

View File

@ -35,6 +35,7 @@ namespace kiwano
: type_(type)
, callback_(callback)
, running_(true)
, removeable_(false)
{
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -79,11 +79,8 @@
#include <kiwano/2d/Transform.h>
#include <kiwano/2d/TextStyle.hpp>
#include <kiwano/2d/Frame.h>
#include <kiwano/2d/FrameSequence.h>
#include <kiwano/2d/action/Action.h>
#include <kiwano/2d/action/ActionGroup.h>
#include <kiwano/2d/action/ActionTween.h>
@ -92,9 +89,7 @@
#include <kiwano/2d/action/Animation.h>
#include <kiwano/2d/action/ActionHelper.h>
#include <kiwano/2d/action/ActionManager.h>
#include <kiwano/2d/Transition.h>
#include <kiwano/2d/Actor.h>
#include <kiwano/2d/Stage.h>
#include <kiwano/2d/Layer.h>

View File

@ -19,25 +19,48 @@
// THE SOFTWARE.
#include <kiwano/renderer/Font.h>
#include <kiwano/renderer/Renderer.h>
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;
}
}

View File

@ -19,51 +19,50 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/renderer/FontCollection.h>
#include <kiwano/core/ObjectBase.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano/core/Resource.h>
#include <dwrite.h>
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<IDWriteFontCollection> GetCollection() const;
void SetCollection(ComPtr<IDWriteFontCollection> collection);
private:
ComPtr<IDWriteFontCollection> collection_;
};
inline ComPtr<IDWriteFontCollection> Font::GetCollection() const
{
return collection_;
}
inline void Font::SetCollection(ComPtr<IDWriteFontCollection> collection)
{
collection_ = collection;
}
}

View File

@ -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 <kiwano/renderer/FontCollection.h>
#include <kiwano/renderer/Renderer.h>
namespace kiwano
{
FontCollection::FontCollection()
{
}
FontCollection::FontCollection(String const& file)
{
Load(file);
}
FontCollection::FontCollection(Vector<String> const& files)
{
Load(files);
}
FontCollection::FontCollection(Resource const& res)
{
Load(res);
}
FontCollection::FontCollection(Vector<Resource> const& res_arr)
{
Load(res_arr);
}
bool FontCollection::Load(String const& file)
{
Renderer::instance().CreateFontCollection(*this, { file });
return IsValid();
}
bool FontCollection::Load(Vector<String> 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<Resource> const& res_arr)
{
Renderer::instance().CreateFontCollection(*this, res_arr);
return IsValid();
}
bool FontCollection::IsValid() const
{
return collection_ != nullptr;
}
}

View File

@ -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 <kiwano/core/Resource.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <dwrite.h>
namespace kiwano
{
// 字体集
class FontCollection
{
public:
FontCollection();
FontCollection(String const& file);
FontCollection(Vector<String> const& files);
FontCollection(Resource const& res);
FontCollection(Vector<Resource> const& res_arr);
// 从本地文件加载字体
bool Load(String const& file);
// 从多个本地文件加载字体
bool Load(Vector<String> const& files);
// 从资源加载字体
bool Load(Resource const& res);
// 从多个资源加载字体
bool Load(Vector<Resource> const& res_arr);
bool IsValid() const;
public:
inline ComPtr<IDWriteFontCollection> GetFontCollection() const { return collection_; }
inline void SetFontCollection(ComPtr<IDWriteFontCollection> collection) { collection_ = collection; }
private:
ComPtr<IDWriteFontCollection> collection_;
};
}

View File

@ -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);

View File

@ -20,6 +20,7 @@
#pragma once
#include <kiwano/core/time.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano/renderer/Brush.h>
#include <kiwano/renderer/Texture.h>
#include <kiwano/renderer/Geometry.h>
@ -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
);

View File

@ -577,7 +577,7 @@ namespace kiwano
}
}
void Renderer::CreateFontCollection(FontCollection& collection, Vector<String> const& file_paths)
void Renderer::CreateFontCollection(Font& font, Vector<String> 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<Resource> const& res_arr)
void Renderer::CreateFontCollection(Font& font, Vector<Resource> 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<IDWriteTextFormat> 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()
);
}

View File

@ -23,6 +23,8 @@
#include <kiwano/renderer/win32/FontCollectionLoader.h>
#include <kiwano/renderer/RenderTarget.h>
#include <kiwano/renderer/GifImage.h>
#include <kiwano/renderer/Font.h>
#include <kiwano/renderer/TextStyle.hpp>
#if defined(KGE_USE_DIRECTX10)
# include "win32/D3D10DeviceResources.h"
@ -99,24 +101,21 @@ namespace kiwano
);
void CreateFontCollection(
FontCollection& collection,
Font& font,
Vector<String> const& file_paths
);
void CreateFontCollection(
FontCollection& collection,
Font& font,
Vector<Resource> 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(

View File

@ -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<TextLayout*>(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<TextLayout*>(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);
}
}

View File

@ -20,63 +20,209 @@
#pragma once
#include <kiwano/math/math.h>
#include <kiwano/renderer/Font.h>
#include <kiwano/2d/TextStyle.hpp>
#include <kiwano/renderer/TextStyle.hpp>
namespace kiwano
{
// Îı¾¸ñʽ»¯
class KGE_API TextFormat
{
public:
TextFormat();
TextFormat(Font const& font);
void Update(Font const& font);
public:
inline ComPtr<IDWriteTextFormat> GetTextFormat() const { return text_format_; }
inline void SetTextFormat(ComPtr<IDWriteTextFormat> format) { text_format_ = format; }
private:
ComPtr<IDWriteTextFormat> 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<IDWriteTextFormat> GetTextFormat() const;
inline ComPtr<IDWriteTextLayout> GetTextLayout() const { return text_layout_; }
void SetTextFormat(ComPtr<IDWriteTextFormat> format);
inline void SetTextLayout(ComPtr<IDWriteTextLayout> layout) { text_layout_ = layout; }
ComPtr<IDWriteTextLayout> GetTextLayout() const;
inline operator bool() const { return static_cast<bool>(text_layout_); }
void SetTextLayout(ComPtr<IDWriteTextLayout> layout);
private:
enum DirtyFlag : uint8_t
{
Clean = 0,
DirtyFormat = 1,
DirtyLayout = 1 << 1,
};
uint8_t dirty_flag_;
ComPtr<IDWriteTextFormat> text_format_;
ComPtr<IDWriteTextLayout> text_layout_;
String text_;
TextStyle style_;
TextFormat text_format_;
mutable ComPtr<IDWriteTextLayout> 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<IDWriteTextFormat> TextLayout::GetTextFormat() const
{
return text_format_;
}
inline ComPtr<IDWriteTextLayout> TextLayout::GetTextLayout() const
{
return text_layout_;
}
inline void TextLayout::SetColor(Color const& color)
{
style_.color = color;
}
inline void TextLayout::SetTextFormat(ComPtr<IDWriteTextFormat> format)
{
text_format_ = format;
}
inline void TextLayout::SetTextLayout(ComPtr<IDWriteTextLayout> 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;
}
}

View File

@ -21,6 +21,7 @@
#pragma once
#include <kiwano/renderer/Color.h>
#include <kiwano/renderer/StrokeStyle.h>
#include <kiwano/renderer/Font.h>
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)

View File

@ -65,7 +65,12 @@ namespace kiwano
HRESULT CreateTextFormat(
_Out_ ComPtr<IDWriteTextFormat>& text_format,
_In_ Font const& font
_In_ String const& family,
_In_ ComPtr<IDWriteFontCollection> 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<IDWriteTextFormat> & text_format, _In_ Font const & font)
HRESULT D2DDeviceResources::CreateTextFormat(_Out_ ComPtr<IDWriteTextFormat> & text_format, _In_ String const& family, _In_ ComPtr<IDWriteFontCollection> 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<IDWriteTextFormat> 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
);

View File

@ -19,10 +19,10 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/renderer/Font.h>
#include <kiwano/renderer/Color.h>
#include <kiwano/math/math.h>
#include <kiwano/core/Resource.h>
#include <kiwano/core/win32/ComPtr.hpp>
#include <kiwano/renderer/Color.h>
#include <dwrite.h>
#include <d2d1.h>
#include <d2d1_1.h>
@ -216,7 +216,12 @@ namespace kiwano
virtual HRESULT CreateTextFormat(
_Out_ ComPtr<IDWriteTextFormat>& text_format,
_In_ Font const& font
_In_ String const& family,
_In_ ComPtr<IDWriteFontCollection> collection,
_In_ DWRITE_FONT_WEIGHT weight,
_In_ DWRITE_FONT_STYLE style,
_In_ DWRITE_FONT_STRETCH stretch,
_In_ FLOAT font_size
) = 0;
virtual HRESULT CreateTextLayout(

View File

@ -22,9 +22,6 @@
#include <kiwano/utils/ResourceCache.h>
#include <kiwano/core/Logger.h>
#include <kiwano/platform/FileSystem.h>
#include <kiwano/renderer/GifImage.h>
#include <kiwano/renderer/FontCollection.h>
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<String> 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<Frame>(id);
}
FrameSequencePtr ResourceCache::GetFrameSequence(String const & id) const
{
return Get<FrameSequence>(id);
}
GifImagePtr ResourceCache::GetGifImage(String const& id) const
{
return Get<GifImage>(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<String>* 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<String> 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<String> 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<String> 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;
}
}

View File

@ -23,6 +23,7 @@
#include <kiwano/2d/Frame.h>
#include <kiwano/2d/FrameSequence.h>
#include <kiwano/renderer/GifImage.h>
#include <kiwano/renderer/Font.h>
#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<String> 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<typename _Ty>
_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<const _Ty*>((*iter).second.get()));
return dynamic_cast<_Ty*>(Get(id).get());
}
private:
@ -107,7 +77,6 @@ namespace kiwano
virtual ~ResourceCache();
private:
UnorderedMap<String, ObjectBasePtr> object_cache_;
UnorderedMap<String, FontCollection> font_collection_cache_;
UnorderedMap<String, ObjectBasePtr> object_cache_;
};
}