#include "NativeRendererInternal.h" #include #include 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 textLayout; HRESULT hr = m_dwriteFactory->CreateTextLayout( text.c_str(), static_cast(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(std::lround(resolvedFontSize * 10.0f)); const auto found = m_textFormats.find(key); if (found != m_textFormats.end()) { return found->second.Get(); } Microsoft::WRL::ComPtr 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(text.size()), nullptr, 0); if (sizeNeeded <= 0) { return {}; } std::wstring wideText(static_cast(sizeNeeded), L'\0'); MultiByteToWideChar( CP_UTF8, 0, text.data(), static_cast(text.size()), wideText.data(), sizeNeeded); return wideText; } } // namespace XCEngine::UI::Editor::Host