123 lines
3.4 KiB
C++
123 lines
3.4 KiB
C++
#include "NativeRendererInternal.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
|
|
namespace XCEngine::UI::Editor::Host {
|
|
|
|
using namespace NativeRendererInternal;
|
|
|
|
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
|