refactor(new_editor/app): reorganize host structure and add smoke test
This commit is contained in:
122
new_editor/app/Rendering/Native/NativeRendererText.cpp
Normal file
122
new_editor/app/Rendering/Native/NativeRendererText.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
#include "NativeRendererSupport.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace XCEngine::UI::Editor::Host {
|
||||
|
||||
using namespace NativeRendererSupport;
|
||||
|
||||
float NativeRenderer::MeasureTextWidth(
|
||||
const ::XCEngine::UI::Editor::UIEditorTextMeasureRequest& request) const {
|
||||
if (!m_dwriteFactory || request.text.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const std::wstring text = Utf8ToWide(request.text);
|
||||
if (text.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const float dpiScale = ClampDpiScale(m_dpiScale);
|
||||
const float scaledFontSize = ResolveFontSize(request.fontSize) * dpiScale;
|
||||
IDWriteTextFormat* textFormat = GetTextFormat(scaledFontSize);
|
||||
if (textFormat == nullptr) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteTextLayout> textLayout;
|
||||
HRESULT hr = m_dwriteFactory->CreateTextLayout(
|
||||
text.c_str(),
|
||||
static_cast<UINT32>(text.size()),
|
||||
textFormat,
|
||||
4096.0f,
|
||||
scaledFontSize * 2.0f,
|
||||
textLayout.ReleaseAndGetAddressOf());
|
||||
if (FAILED(hr) || !textLayout) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
DWRITE_TEXT_METRICS textMetrics = {};
|
||||
hr = textLayout->GetMetrics(&textMetrics);
|
||||
if (FAILED(hr)) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
DWRITE_OVERHANG_METRICS overhangMetrics = {};
|
||||
float width = textMetrics.widthIncludingTrailingWhitespace;
|
||||
if (SUCCEEDED(textLayout->GetOverhangMetrics(&overhangMetrics))) {
|
||||
width += (std::max)(overhangMetrics.left, 0.0f);
|
||||
width += (std::max)(overhangMetrics.right, 0.0f);
|
||||
}
|
||||
|
||||
return std::ceil(width) / dpiScale;
|
||||
}
|
||||
|
||||
IDWriteTextFormat* NativeRenderer::GetTextFormat(float fontSize) const {
|
||||
if (!m_dwriteFactory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const float resolvedFontSize = ResolveFontSize(fontSize);
|
||||
const int key = static_cast<int>(std::lround(resolvedFontSize * 10.0f));
|
||||
const auto found = m_textFormats.find(key);
|
||||
if (found != m_textFormats.end()) {
|
||||
return found->second.Get();
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<IDWriteTextFormat> textFormat;
|
||||
const HRESULT hr = m_dwriteFactory->CreateTextFormat(
|
||||
L"Segoe UI",
|
||||
nullptr,
|
||||
DWRITE_FONT_WEIGHT_REGULAR,
|
||||
DWRITE_FONT_STYLE_NORMAL,
|
||||
DWRITE_FONT_STRETCH_NORMAL,
|
||||
resolvedFontSize,
|
||||
L"",
|
||||
textFormat.ReleaseAndGetAddressOf());
|
||||
if (FAILED(hr)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
|
||||
textFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
|
||||
textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
|
||||
|
||||
IDWriteTextFormat* result = textFormat.Get();
|
||||
m_textFormats.emplace(key, std::move(textFormat));
|
||||
return result;
|
||||
}
|
||||
|
||||
D2D1_COLOR_F NativeRenderer::ToD2DColor(const ::XCEngine::UI::UIColor& color) {
|
||||
return D2D1::ColorF(color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
std::wstring NativeRenderer::Utf8ToWide(std::string_view text) {
|
||||
if (text.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const int sizeNeeded = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
0,
|
||||
text.data(),
|
||||
static_cast<int>(text.size()),
|
||||
nullptr,
|
||||
0);
|
||||
if (sizeNeeded <= 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::wstring wideText(static_cast<size_t>(sizeNeeded), L'\0');
|
||||
MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
0,
|
||||
text.data(),
|
||||
static_cast<int>(text.size()),
|
||||
wideText.data(),
|
||||
sizeNeeded);
|
||||
return wideText;
|
||||
}
|
||||
|
||||
} // namespace XCEngine::UI::Editor::Host
|
||||
Reference in New Issue
Block a user