Fix incorrect TextLayout width

This commit is contained in:
Nomango 2020-02-17 12:06:29 +08:00
parent 60899a6a9b
commit 794df63a10
10 changed files with 238 additions and 169 deletions

View File

@ -80,7 +80,7 @@ FixturePtr Fixture::CreateRect(Body* body, Param const& param, Size const& size,
b2Vec2 b2offset = world->Stage2World(offset);
b2PolygonShape shape;
shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, rotation);
shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation));
return CreateFixture(body, &shape, param);
}

View File

@ -242,10 +242,23 @@ ContactList World::GetContactList()
void World::Update(Duration dt)
{
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
b2Body* b2body = world_.GetBodyList();
while (b2body)
{
Body* body = static_cast<Body*>(b2body->GetUserData());
if (body && body->GetType() != Body::Type::Static)
{
body->UpdateFromActor();
}
b2body = b2body->GetNext();
}
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
b2body = world_.GetBodyList();
while (b2body)
{
Body* body = static_cast<Body*>(b2body->GetUserData());
if (body && body->GetType() != Body::Type::Static)

View File

@ -260,13 +260,13 @@ void Actor::HandleEvent(Event* evt)
}
}
Matrix3x2 const& Actor::GetTransformMatrix() const
const Matrix3x2& Actor::GetTransformMatrix() const
{
UpdateTransform();
return transform_matrix_;
}
Matrix3x2 const& Actor::GetTransformInverseMatrix() const
const Matrix3x2& Actor::GetTransformInverseMatrix() const
{
UpdateTransform();
if (dirty_transform_inverse_)

View File

@ -114,7 +114,7 @@ public:
/// \~chinese
/// @brief 获取坐标
Point const& GetPosition() const;
virtual Point GetPosition() const;
/// \~chinese
/// @brief 获取 x 坐标
@ -124,6 +124,10 @@ public:
/// @brief 获取 y 坐标
float GetPositionY() const;
/// \~chinese
/// @brief 获取大小
virtual Size GetSize() const;
/// \~chinese
/// @brief 获取宽度
float GetWidth() const;
@ -132,10 +136,6 @@ public:
/// @brief 获取高度
float GetHeight() const;
/// \~chinese
/// @brief 获取大小
Size const& GetSize() const;
/// \~chinese
/// @brief 获取缩放后的宽度
float GetScaledWidth() const;
@ -150,7 +150,7 @@ public:
/// \~chinese
/// @brief 获取锚点
Point const& GetAnchor() const;
virtual Point GetAnchor() const;
/// \~chinese
/// @brief 获取 x 方向锚点
@ -162,7 +162,7 @@ public:
/// \~chinese
/// @brief 获取透明度
float GetOpacity() const;
virtual float GetOpacity() const;
/// \~chinese
/// @brief 获取显示透明度
@ -170,11 +170,11 @@ public:
/// \~chinese
/// @brief 获取旋转角度
float GetRotation() const;
virtual float GetRotation() const;
/// \~chinese
/// @brief 获取缩放比例
Point const& GetScale() const;
virtual Point GetScale() const;
/// \~chinese
/// @brief 获取横向缩放比例
@ -186,7 +186,7 @@ public:
/// \~chinese
/// @brief 获取错切角度
Point const& GetSkew() const;
virtual Point GetSkew() const;
/// \~chinese
/// @brief 获取横向错切角度
@ -218,11 +218,11 @@ public:
/// \~chinese
/// @brief 获取二维变换矩阵
Matrix3x2 const& GetTransformMatrix() const;
const Matrix3x2& GetTransformMatrix() const;
/// \~chinese
/// @brief 获取二维变换的逆矩阵
Matrix3x2 const& GetTransformInverseMatrix() const;
const Matrix3x2& GetTransformInverseMatrix() const;
/// \~chinese
/// @brief 设置角色是否可见
@ -284,14 +284,6 @@ public:
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
void SetAnchor(float anchorx, float anchory);
/// \~chinese
/// @brief 修改宽度
virtual void SetWidth(float width);
/// \~chinese
/// @brief 修改高度
virtual void SetHeight(float height);
/// \~chinese
/// @brief 修改大小
virtual void SetSize(Size const& size);
@ -300,6 +292,14 @@ public:
/// @brief 修改大小
void SetSize(float width, float height);
/// \~chinese
/// @brief 修改宽度
void SetWidth(float width);
/// \~chinese
/// @brief 修改高度
void SetHeight(float height);
/// \~chinese
/// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
virtual void SetOpacity(float opacity);
@ -514,7 +514,7 @@ inline int Actor::GetZOrder() const
return z_order_;
}
inline Point const& Actor::GetPosition() const
inline Point Actor::GetPosition() const
{
return transform_.position;
}
@ -529,7 +529,7 @@ inline float Actor::GetPositionY() const
return GetPosition().y;
}
inline Point const& Actor::GetScale() const
inline Point Actor::GetScale() const
{
return transform_.scale;
}
@ -544,7 +544,7 @@ inline float Actor::GetScaleY() const
return GetScale().y;
}
inline Point const& Actor::GetSkew() const
inline Point Actor::GetSkew() const
{
return transform_.skew;
}
@ -574,7 +574,7 @@ inline float Actor::GetHeight() const
return GetSize().y;
}
inline Size const& Actor::GetSize() const
inline Size Actor::GetSize() const
{
return size_;
}
@ -594,7 +594,7 @@ inline Size Actor::GetScaledSize() const
return Size{ GetScaledWidth(), GetScaledHeight() };
}
inline Point const& Actor::GetAnchor() const
inline Point Actor::GetAnchor() const
{
return anchor_;
}
@ -693,4 +693,5 @@ inline void Actor::SetSkew(float skewx, float skewy)
{
SetSkew(Vec2{ skewx, skewy });
}
} // namespace kiwano

View File

@ -124,7 +124,7 @@ void DebugActor::OnUpdate(Duration dt)
debug_text_.Reset(ss.str(), debug_text_style_);
Size layout_size = debug_text_.GetLayoutSize();
Size layout_size = debug_text_.GetSize();
if (layout_size.x > GetWidth() - 20)
{
SetWidth(20 + layout_size.x);

View File

@ -61,34 +61,10 @@ void TextActor::OnRender(RenderContext& ctx)
}
}
void TextActor::OnUpdate(Duration dt)
Size TextActor::GetSize() const
{
UpdateLayout();
}
void TextActor::UpdateLayout()
{
if (!layout_)
return;
if (layout_->GetDirtyFlag() == TextLayout::DirtyFlag::Updated)
{
layout_->SetDirtyFlag(TextLayout::DirtyFlag::Clean);
if (text_.empty())
{
SetSize(Size());
}
else
{
SetSize(layout_->GetLayoutSize());
}
}
}
bool TextActor::CheckVisibility(RenderContext& ctx) const
{
return layout_ && layout_->IsValid() && Actor::CheckVisibility(ctx);
const_cast<TextActor*>(this)->UpdateDirtyLayout();
return Actor::GetSize();
}
void TextActor::SetFillColor(Color const& color)
@ -124,7 +100,7 @@ void TextActor::SetTextLayout(TextLayoutPtr layout)
if (layout_ != layout)
{
layout_ = layout;
UpdateLayout();
ForceUpdateLayout();
}
}
@ -294,4 +270,39 @@ void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke)
}
}
void TextActor::Update(Duration dt)
{
this->UpdateDirtyLayout();
Actor::Update(dt);
}
bool TextActor::CheckVisibility(RenderContext& ctx) const
{
return layout_ && layout_->IsValid() && Actor::CheckVisibility(ctx);
}
void TextActor::UpdateDirtyLayout()
{
KGE_ASSERT(layout_);
if (layout_->UpdateWhenDirty())
{
ForceUpdateLayout();
}
}
void TextActor::ForceUpdateLayout()
{
KGE_ASSERT(layout_);
layout_->UpdateWhenDirty();
if (text_.empty())
{
SetSize(Size());
}
else
{
SetSize(layout_->GetSize());
}
}
} // namespace kiwano

View File

@ -67,8 +67,8 @@ public:
TextLayoutPtr GetLayout() const;
/// \~chinese
/// @brief 获取文本布局大小
Size GetLayoutSize() const;
/// @brief 获取大小
Size GetSize() const override;
/// \~chinese
/// @brief 获取填充画刷
@ -159,15 +159,20 @@ public:
void SetTextLayout(TextLayoutPtr layout);
/// \~chinese
/// @brief 更新文字布局
/// @brief 更新脏文字布局
/// @details 仅当文字布局脏时更新
void UpdateDirtyLayout();
/// \~chinese
/// @brief 强制更新文字布局
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
void UpdateLayout();
void ForceUpdateLayout();
void OnRender(RenderContext& ctx) override;
void OnUpdate(Duration dt) override;
protected:
void Update(Duration dt) override;
bool CheckVisibility(RenderContext& ctx) const override;
private:
@ -198,15 +203,6 @@ inline TextLayoutPtr TextActor::GetLayout() const
return layout_;
}
inline Size TextActor::GetLayoutSize() const
{
if (layout_)
{
return layout_->GetLayoutSize();
}
return Size();
}
inline BrushPtr TextActor::GetFillBrush() const
{
return style_.fill_brush;

View File

@ -610,7 +610,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
if (content.empty())
{
layout.Clear();
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty);
return;
}
@ -635,7 +635,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
if (SUCCEEDED(hr))
{
NativePtr::Set(layout, output);
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty);
}
}
}

View File

@ -45,14 +45,15 @@ TextLayoutPtr TextLayout::Create(const String& content, const TextStyle& style)
TextLayout::TextLayout()
: dirty_flag_(DirtyFlag::Clean)
, line_count_(0)
{
}
void TextLayout::Reset(const String& text, const TextStyle& style)
void TextLayout::Reset(const String& content, const TextStyle& style)
{
if (!text.empty())
if (!content.empty())
{
Renderer::GetInstance().CreateTextLayout(*this, text, style);
Renderer::GetInstance().CreateTextLayout(*this, content, style);
SetAlignment(style.alignment);
SetWrapWidth(style.wrap_width);
@ -63,80 +64,58 @@ void TextLayout::Reset(const String& text, const TextStyle& style)
SetDefaultOutlineStrokeStyle(style.outline_stroke);
if (style.show_underline)
SetUnderline(style.show_underline, { 0, text.length() });
SetUnderline(style.show_underline, { 0, content.length() });
if (style.show_strikethrough)
SetStrikethrough(style.show_strikethrough, { 0, text.length() });
SetStrikethrough(style.show_strikethrough, { 0, content.length() });
}
else
{
Clear();
}
content_ = content;
SetDirtyFlag(DirtyFlag::Dirty);
}
Size TextLayout::GetSize() const
{
const_cast<TextLayout*>(this)->UpdateWhenDirty();
return size_;
}
uint32_t TextLayout::GetLineCount() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
DWRITE_TEXT_METRICS metrics;
if (SUCCEEDED(native->GetMetrics(&metrics)))
{
return metrics.lineCount;
}
}
#else
// not supported
#endif
return 0;
}
Size TextLayout::GetLayoutSize() const
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
DWRITE_TEXT_METRICS metrics;
if (SUCCEEDED(native->GetMetrics(&metrics)))
{
return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height)
: Size(metrics.width, metrics.height);
}
}
#else
// not supported
#endif
return Size();
const_cast<TextLayout*>(this)->UpdateWhenDirty();
return line_count_;
}
void TextLayout::SetFont(FontPtr font, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
if (native)
{
ComPtr<IDWriteFontCollection> collection = NativePtr::Get<IDWriteFontCollection>(font);
auto collection = NativePtr::Get<IDWriteFontCollection>(font);
HRESULT hr = native->SetFontCollection(collection.Get(), { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontCollection failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetFontFamily(String const& family, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -147,16 +126,18 @@ void TextLayout::SetFontFamily(String const& family, TextRange range)
HRESULT hr = native->SetFontFamilyName(font_family.c_str(), { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontFamilyName failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetFontSize(float size, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -165,16 +146,18 @@ void TextLayout::SetFontSize(float size, TextRange range)
{
HRESULT hr = native->SetFontSize(size, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontSize failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -185,16 +168,18 @@ void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
HRESULT hr = native->SetFontWeight(font_weight, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontWeight failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetItalic(bool italic, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -205,16 +190,18 @@ void TextLayout::SetItalic(bool italic, TextRange range)
HRESULT hr = native->SetFontStyle(font_style, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontStyle failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetUnderline(bool enable, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -223,16 +210,18 @@ void TextLayout::SetUnderline(bool enable, TextRange range)
{
HRESULT hr = native->SetUnderline(enable, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetUnderline failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
return; // not supported
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetStrikethrough(bool enable, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -241,16 +230,18 @@ void TextLayout::SetStrikethrough(bool enable, TextRange range)
{
HRESULT hr = native->SetStrikethrough(enable, { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetStrikethrough failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
return; // not supported
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetFillBrush(BrushPtr brush, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
@ -260,16 +251,18 @@ void TextLayout::SetFillBrush(BrushPtr brush, TextRange range)
HRESULT hr =
native->SetDrawingEffect(NativePtr::Get<ID2D1Brush>(brush).Get(), { range.start, range.length });
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetDrawingEffect failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
return; // not supported
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
// TODO
KGE_NOT_USED(range);
@ -281,6 +274,8 @@ void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range)
void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range)
{
KGE_ASSERT(content_.size() >= (range.start + range.length));
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
// TODO
KGE_NOT_USED(range);
@ -317,12 +312,12 @@ void TextLayout::SetAlignment(TextAlign align)
HRESULT hr = native->SetTextAlignment(alignment);
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetTextAlignment failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetWrapWidth(float wrap_width)
@ -333,34 +328,26 @@ void TextLayout::SetWrapWidth(float wrap_width)
if (native)
{
DWRITE_WORD_WRAPPING wrapping = (wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP;
HRESULT hr = native->SetWordWrapping(wrapping);
if (SUCCEEDED(hr))
{
HRESULT hr = S_OK;
if (wrap_width > 0)
{
hr = native->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
if (SUCCEEDED(hr))
{
hr = native->SetMaxWidth(wrap_width);
}
}
else
{
// Fix the layout width when the text does not wrap
DWRITE_TEXT_METRICS metrics;
hr = native->GetMetrics(&metrics);
if (SUCCEEDED(hr))
{
hr = native->SetMaxWidth(metrics.width);
}
}
hr = native->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetWordWrapping failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
return; // not supported
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
void TextLayout::SetLineSpacing(float line_spacing)
@ -383,12 +370,62 @@ void TextLayout::SetLineSpacing(float line_spacing)
hr = native->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, spacing, spacing * 0.8f);
}
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetLineSpacing failed");
dirty_flag_ = DirtyFlag::Updated;
}
#else
return; // not supported
// not supported
#endif
SetDirtyFlag(DirtyFlag::Dirty);
}
bool TextLayout::UpdateWhenDirty()
{
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
if (dirty_flag_ == DirtyFlag::Dirty)
{
SetDirtyFlag(DirtyFlag::Clean);
auto native = NativePtr::Get<IDWriteTextLayout>(this);
KGE_ASSERT(native);
HRESULT hr = S_OK;
DWRITE_TEXT_METRICS metrics;
hr = native->GetMetrics(&metrics);
if (SUCCEEDED(hr))
{
if (native->GetWordWrapping() == DWRITE_WORD_WRAPPING_NO_WRAP)
{
// Fix the layout width when the text does not wrap
hr = native->SetMaxWidth(metrics.widthIncludingTrailingWhitespace);
if (SUCCEEDED(hr))
{
hr = native->GetMetrics(&metrics);
}
}
}
if (SUCCEEDED(hr))
{
line_count_ = metrics.lineCount;
if (metrics.layoutWidth > 0)
{
size_ = Size(metrics.layoutWidth, metrics.height);
}
else
{
size_ = Size(metrics.widthIncludingTrailingWhitespace, metrics.height);
}
}
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::GetMetrics failed");
return true;
}
#else
// not supported
#endif
return false;
}
} // namespace kiwano

View File

@ -67,12 +67,12 @@ public:
void Reset(const String& content, const TextStyle& style);
/// \~chinese
/// @brief 获取文本行数
uint32_t GetLineCount() const;
/// @brief 获取文本布局大小
Size GetSize() const;
/// \~chinese
/// @brief 获取文本布局大小
Size GetLayoutSize() const;
/// @brief 获取文本行数
uint32_t GetLineCount() const;
/// \~chinese
/// @brief 获取默认填充画刷
@ -183,23 +183,34 @@ public:
void SetDefaultOutlineStrokeStyle(StrokeStylePtr stroke);
/// \~chinese
/// @brief 脏数据标志
/// @brief 脏布局标志
enum class DirtyFlag : uint8_t
{
Clean = 0, ///< 干净布局
Dirty = 1 << 0, ///< 脏布局
Updated = 1 << 1, ///< 已更新
Dirty = 1 << 0 ///< 脏布局
};
/// \~chinese
/// @brief 获取脏布局标志
DirtyFlag GetDirtyFlag() const;
/// \~chinese
/// @brief 设置脏布局标志
void SetDirtyFlag(DirtyFlag flag);
/// \~chinese
/// @brief 更新脏布局
/// @return 是否需要更新
bool UpdateWhenDirty();
private:
DirtyFlag dirty_flag_;
uint32_t line_count_;
Size size_;
BrushPtr default_fill_brush_;
BrushPtr default_outline_brush_;
StrokeStylePtr default_outline_stroke_;
String content_;
};
/** @} */