Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
322 changes: 102 additions & 220 deletions WeaselUI/DirectWriteResources.cpp

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions WeaselUI/Layout.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ class Layout {
const wchar_t* format) const = 0;
virtual bool IsInlinePreedit() const = 0;
virtual bool ShouldDisplayStatusIcon() const = 0;
virtual void GetTextSizeDW(const std::wstring text,
virtual void GetTextSizeDW(const std::wstring& text,
size_t nCount,
ComPtr<IDWriteTextFormat1> pTextFormat,
ComPtr<IDWriteTextFormat1>& pTextFormat,
PDWR pDWR,
LPSIZE lpSize) const = 0;

Expand Down
114 changes: 54 additions & 60 deletions WeaselUI/StandardLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ std::wstring StandardLayout::GetLabelText(const std::vector<Text>& labels,
}

void weasel::StandardLayout::GetTextSizeDW(
const std::wstring text,
const std::wstring& text,
size_t nCount,
ComPtr<IDWriteTextFormat1> pTextFormat,
ComPtr<IDWriteTextFormat1>& pTextFormat,
PDWR pDWR,
LPSIZE lpSize) const {
D2D1_SIZE_F sz;
Expand All @@ -26,65 +26,59 @@ void weasel::StandardLayout::GetTextSizeDW(
return;
}
// 创建文本布局
if (pTextFormat != NULL) {
if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)
hr = pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
0.0f, (float)_style.max_height);
else
hr = pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
(float)_style.max_width, 0);
}
if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT)
HR(pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
0.0f, (float)_style.max_height));
else
HR(pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
(float)_style.max_width, 0));

if (SUCCEEDED(hr)) {
if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right
? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
: DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT;
pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
pDWR->SetLayoutFlowDirection(flow);
}
// 获取文本尺寸
DWRITE_TEXT_METRICS textMetrics;
hr = pDWR->GetLayoutMetrics(&textMetrics);
sz = D2D1::SizeF(ceil(textMetrics.widthIncludingTrailingWhitespace),
ceil(textMetrics.height));
if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
DWRITE_FLOW_DIRECTION flow = _style.vertical_text_left_to_right
? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
: DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT;
HR(pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM));
HR(pDWR->SetLayoutFlowDirection(flow));
}
// 获取文本尺寸
DWRITE_TEXT_METRICS textMetrics;
HR(pDWR->GetLayoutMetrics(&textMetrics));
sz = D2D1::SizeF(ceil(textMetrics.widthIncludingTrailingWhitespace),
ceil(textMetrics.height));

lpSize->cx = (int)sz.width;
lpSize->cy = (int)sz.height;
pDWR->ResetLayout();
lpSize->cx = (int)sz.width;
lpSize->cy = (int)sz.height;

if (_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) {
auto max_width = _style.max_width == 0
? textMetrics.widthIncludingTrailingWhitespace
: _style.max_width;
hr = pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
max_width, textMetrics.height);
} else {
auto max_height =
_style.max_height == 0 ? textMetrics.height : _style.max_height;
hr = pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
textMetrics.widthIncludingTrailingWhitespace,
max_height);
}
if (_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT) {
auto max_width = _style.max_width == 0
? textMetrics.widthIncludingTrailingWhitespace
: _style.max_width;
HR(pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
max_width, textMetrics.height));
} else {
auto max_height =
_style.max_height == 0 ? textMetrics.height : _style.max_height;
HR(pDWR->CreateTextLayout(text.c_str(), (int)nCount, pTextFormat.Get(),
textMetrics.widthIncludingTrailingWhitespace,
max_height));
}

if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
pDWR->SetLayoutFlowDirection(DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT);
}
DWRITE_OVERHANG_METRICS overhangMetrics;
hr = pDWR->GetLayoutOverhangMetrics(&overhangMetrics);
{
if (overhangMetrics.left > 0)
lpSize->cx += (LONG)(overhangMetrics.left + 1);
if (overhangMetrics.right > 0)
lpSize->cx += (LONG)(overhangMetrics.right + 1);
if (overhangMetrics.top > 0)
lpSize->cy += (LONG)(overhangMetrics.top + 1);
if (overhangMetrics.bottom > 0)
lpSize->cy += (LONG)(overhangMetrics.bottom + 1);
}
if (_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
HR(pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM));
HR(pDWR->SetLayoutFlowDirection(DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT));
}
DWRITE_OVERHANG_METRICS overhangMetrics;
HR(pDWR->GetLayoutOverhangMetrics(&overhangMetrics));
{
if (overhangMetrics.left > 0)
lpSize->cx += (LONG)(overhangMetrics.left + 1);
if (overhangMetrics.right > 0)
lpSize->cx += (LONG)(overhangMetrics.right + 1);
if (overhangMetrics.top > 0)
lpSize->cy += (LONG)(overhangMetrics.top + 1);
if (overhangMetrics.bottom > 0)
lpSize->cy += (LONG)(overhangMetrics.bottom + 1);
}
pDWR->ResetLayout();
}

CSize StandardLayout::GetPreeditSize(CDCHandle dc,
Expand Down Expand Up @@ -181,13 +175,13 @@ void weasel::StandardLayout::_PrepareRoundInfo(CDCHandle& dc) {
{true, true, true, true}}};

_textRoundInfo.IsTopLeftNeedToRound =
hilite_rd_info[layout_type][_style.inline_preedit][0];
hilite_rd_info[layout_type][!textHemispherical][0];
_textRoundInfo.IsBottomLeftNeedToRound =
hilite_rd_info[layout_type][_style.inline_preedit][1];
hilite_rd_info[layout_type][!textHemispherical][1];
_textRoundInfo.IsTopRightNeedToRound =
hilite_rd_info[layout_type][_style.inline_preedit][2];
hilite_rd_info[layout_type][!textHemispherical][2];
_textRoundInfo.IsBottomRightNeedToRound =
hilite_rd_info[layout_type][_style.inline_preedit][3];
hilite_rd_info[layout_type][!textHemispherical][3];
_textRoundInfo.Hemispherical = textHemispherical;
if (_style.vertical_text_left_to_right &&
_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
Expand Down
4 changes: 2 additions & 2 deletions WeaselUI/StandardLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ class StandardLayout : public Layout {
virtual CSize GetAfterSize() { return _aftersz; }
virtual weasel::TextRange GetPreeditRange() { return _range; }

void GetTextSizeDW(const std::wstring text,
void GetTextSizeDW(const std::wstring& text,
size_t nCount,
ComPtr<IDWriteTextFormat1> pTextFormat,
ComPtr<IDWriteTextFormat1>& pTextFormat,
PDWR pDWR,
LPSIZE lpSize) const;

Expand Down
55 changes: 25 additions & 30 deletions WeaselUI/WeaselPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1235,41 +1235,36 @@ void WeaselPanel::_TextOut(const CRect& rc,
float alpha = (float)((inColor >> 24) & 255) / 255.0f;
HRESULT hr = S_OK;
if (pDWR->pBrush == NULL) {
hr = pDWR->CreateBrush(D2D1::ColorF(r, g, b, alpha));
if (FAILED(hr))
MessageBox(L"Failed CreateBrush", L"Info");
HR(pDWR->CreateBrush(D2D1::ColorF(r, g, b, alpha)));
} else
pDWR->SetBrushColor(D2D1::ColorF(r, g, b, alpha));

if (NULL != pDWR->pBrush && NULL != pTextFormat) {
pDWR->CreateTextLayout(psz.c_str(), (int)cch, pTextFormat,
(float)rc.Width(), (float)rc.Height());
if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
DWRITE_FLOW_DIRECTION flow = m_style.vertical_text_left_to_right
? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
: DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT;
pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
pDWR->SetLayoutFlowDirection(flow);
}
HR(pDWR->CreateTextLayout(psz.c_str(), (int)cch, pTextFormat,
(float)rc.Width(), (float)rc.Height()));
if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT) {
DWRITE_FLOW_DIRECTION flow = m_style.vertical_text_left_to_right
? DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT
: DWRITE_FLOW_DIRECTION_RIGHT_TO_LEFT;
HR(pDWR->SetLayoutReadingDirection(DWRITE_READING_DIRECTION_TOP_TO_BOTTOM));
HR(pDWR->SetLayoutFlowDirection(flow));
}

// offsetx for font glyph over left
float offsetx = (float)rc.left;
float offsety = (float)rc.top;
// prepare for space when first character overhanged
DWRITE_OVERHANG_METRICS omt;
pDWR->GetLayoutOverhangMetrics(&omt);
if (m_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT && omt.left > 0)
offsetx += omt.left;
if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && omt.top > 0)
offsety += omt.top;

if (pDWR->pTextLayout != NULL) {
pDWR->DrawTextLayoutAt({offsetx, offsety});
// offsetx for font glyph over left
float offsetx = (float)rc.left;
float offsety = (float)rc.top;
// prepare for space when first character overhanged
DWRITE_OVERHANG_METRICS omt;
HR(pDWR->GetLayoutOverhangMetrics(&omt));
if (m_style.layout_type != UIStyle::LAYOUT_VERTICAL_TEXT && omt.left > 0)
offsetx += omt.left;
if (m_style.layout_type == UIStyle::LAYOUT_VERTICAL_TEXT && omt.top > 0)
offsety += omt.top;

if (pDWR->pTextLayout != NULL) {
pDWR->DrawTextLayoutAt({offsetx, offsety});
#if 0
D2D1_RECT_F rectf = D2D1::RectF(offsetx, offsety, offsetx + rc.Width(), offsety + rc.Height());
pDWR->DrawRect(&rectf);
D2D1_RECT_F rectf = D2D1::RectF(offsetx, offsety, offsetx + rc.Width(), offsety + rc.Height());
pDWR->DrawRect(&rectf);
#endif
}
pDWR->ResetLayout();
}
}
17 changes: 5 additions & 12 deletions include/WeaselUI.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,10 @@
#include <d2d1.h>
#include <dwrite_2.h>
#include <memory>
#include <wrl/client.h>
#include <functional>
using namespace Microsoft::WRL;
namespace weasel {
#include <WeaselUtility.h>

template <class T>
void SafeRelease(T** ppT) {
if (*ppT) {
(*ppT)->Release();
*ppT = NULL;
}
}
namespace weasel {

enum ClientCapabilities {
INLINE_PREEDIT_CAPABLE = 1,
Expand Down Expand Up @@ -120,7 +112,8 @@ class DirectWriteResources {
const float& height) {
return pDWFactory->CreateTextLayout(
text.c_str(), nCount, txtFormat, width, height,
reinterpret_cast<IDWriteTextLayout**>(pTextLayout.GetAddressOf()));
reinterpret_cast<IDWriteTextLayout**>(
pTextLayout.ReleaseAndGetAddressOf()));
}
void DrawRect(D2D1_RECT_F* const rect,
const float& strokeWidth = 1.0f,
Expand Down Expand Up @@ -167,7 +160,7 @@ class DirectWriteResources {
void _ParseFontFace(const std::wstring& fontFaceStr,
DWRITE_FONT_WEIGHT& fontWeight,
DWRITE_FONT_STYLE& fontStyle);
void _SetFontFallback(ComPtr<IDWriteTextFormat1> pTextFormat,
void _SetFontFallback(ComPtr<IDWriteTextFormat1>& pTextFormat,
const std::vector<std::wstring>& fontVector);
};
} // namespace weasel
78 changes: 78 additions & 0 deletions include/WeaselUtility.h
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#pragma once
#include <filesystem>
#include <string>
#include <sstream>
#include <wrl/client.h>
using namespace Microsoft::WRL;

namespace fs = std::filesystem;

Expand Down Expand Up @@ -241,3 +244,78 @@ inline LANGID get_language_id() {
#define wtoacp(x) wstring_to_string(x, CP_ACP)
#define u8tow(x) string_to_wstring(x, CP_UTF8)
#define acptow(x) string_to_wstring(x, CP_ACP)
#define u8toacp(x) wtoacp(u8tow(x))

class DebugStream {
public:
DebugStream() = default;
~DebugStream() { OutputDebugString(ss.str().c_str()); }
template <typename T>
DebugStream& operator<<(const T& value) {
ss << value;
return *this;
}
DebugStream& operator<<(const char* value) {
if (value) {
std::wstring wvalue(u8tow(value)); // utf-8
ss << wvalue;
}
return *this;
}
DebugStream& operator<<(const std::string value) {
std::wstring wvalue(acptow(value)); // utf-8
ss << wvalue;
return *this;
}

private:
std::wstringstream ss;
};
inline std::string current_time() {
using namespace std::chrono;
auto now = system_clock::now();
auto time_point = system_clock::to_time_t(now);
auto ns = duration_cast<microseconds>(now.time_since_epoch()); // 转换为微秒
std::tm tm = *std::localtime(&time_point);
std::ostringstream oss;
oss << std::put_time(&tm,
"%Y%m%d %H:%M:%S"); // 日期时间格式:20241113 08:54:34
oss << "." << std::setw(6) << std::setfill('0')
<< ns.count() % 1000000; // 微秒部分
return oss.str();
}
#define DEBUG \
(DebugStream() << "[" << current_time() << " " << __FILE__ << ":" \
<< __LINE__ << "] ")

using wstring = std::wstring;
using string = std::string;
template <typename T>
using vector = std::vector<T>;

inline string HRESULTToString(HRESULT hr) {
if (SUCCEEDED(hr))
return "Success";
char buffer[512];
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
DWORD dwSize =
FormatMessageA(dwFlags, nullptr, hr, 0, buffer, sizeof(buffer), nullptr);
if (dwSize == 0)
return "Unknown HRESULT error";
return string(buffer);
}

struct ComException {
HRESULT result;
ComException(HRESULT const value) : result(value) {}
};

#define HR(result) HR_Impl(result, __FILE__, __LINE__)

inline void HR_Impl(HRESULT const result, const char* file, int line) {
if (S_OK != result) {
DebugStream() << "[" << current_time() << " " << file << ":" << line << "] "
<< HRESULTToString(result);
throw ComException(result);
}
}