It's precise enough for me.
Here's my C++ if you or anyone else wants to rip it apart/tell me what I'm doing wrong.
STDMETHODIMP Utils::CreateTextLayout(BSTR text, BSTR font_name, float font_size, UINT32 font_weight, UINT32 font_style, UINT32 font_stretch, UINT32 text_alignment, UINT32 paragraph_alignment, UINT32 word_wrapping, ITextLayout** out)
{
RETURN_HR_IF_NULL(E_POINTER, out);
const std::wstring name_checked = FontHelper::get().get_name_checked(font_name);
wil::com_ptr_t<IDWriteTextFormat> text_format;
wil::com_ptr_t<IDWriteTextLayout> text_layout;
RETURN_IF_FAILED(g_dwrite_factory->CreateTextFormat(name_checked.data(), nullptr, static_cast<DWRITE_FONT_WEIGHT>(font_weight), static_cast<DWRITE_FONT_STYLE>(font_style), static_cast<DWRITE_FONT_STRETCH>(font_stretch), font_size, L"", &text_format));
RETURN_IF_FAILED(g_dwrite_factory->CreateTextLayout(text, SysStringLen(text), text_format.get(), 512.f, FLT_MAX, &text_layout));
RETURN_IF_FAILED(JSGraphics::apply_alignment(text_layout.get(), text_alignment, paragraph_alignment, word_wrapping));
*out = new ComObjectImpl<TextLayout>(text_layout);
return S_OK;
}
STDMETHODIMP TextLayout::CalcTextHeight(float max_width, float* out)
{
RETURN_HR_IF_NULL(E_POINTER, out);
RETURN_HR_IF(E_POINTER, !m_text_layout);
DWRITE_TEXT_METRICS metrics{};
RETURN_IF_FAILED(m_text_layout->SetMaxWidth(max_width));
RETURN_IF_FAILED(m_text_layout->GetMetrics(&metrics));
*out = metrics.height;
return S_OK;
}