vcl/inc/win/salgdi.h | 6 ++++-- vcl/inc/win/winlayout.hxx | 7 ++++--- vcl/win/gdi/salfont.cxx | 40 ++++++++++++++-------------------------- vcl/win/gdi/winlayout.cxx | 44 ++++++++++++++++++++------------------------ 4 files changed, 42 insertions(+), 55 deletions(-)
New commits: commit b06e7814d2edbc369b7c441941c3392df1266423 Author: Jonathan Clark <jonat...@libreoffice.org> AuthorDate: Thu Jan 9 04:52:40 2025 -0700 Commit: Jonathan Clark <jonat...@libreoffice.org> CommitDate: Thu Jan 9 14:50:23 2025 +0100 tdf#152515 vcl: Implement Win32 vert CJK printing for all fonts Previously, vertical CJK printing was implemented on Windows by substituting the font with an @-prefixed alternate. This was a naming convention once used by Microsoft to indicate that a font is a specially-prepared vertical variant containing pre-rotated CJK glyphs. However, modern fonts don't ship these variants and cannot be printed correctly if this approach is used. This change deletes the @-prefix substitution. Instead, a secondary HFONT is used for printing upright characters, as determined by the shaper. This implementation should work with all fonts, and the printed output should now match the screen better. Change-Id: I3c474980f90ade8475073926364ab59dd9310ca0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180014 Reviewed-by: Jonathan Clark <jonat...@libreoffice.org> Tested-by: Jenkins diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index f8107a4a2a00..d210dd22bb68 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -171,9 +171,11 @@ private: void DeInitGraphics(); public: - // Return HFONT, and whether the font is for vertical writing ( prefixed with '@' ) + // Returns base HFONT, an optional HFONT for non-rotated CJK glyphs, // and tmDescent value for adjusting offset in vertical writing mode. - std::tuple<HFONT,bool,sal_Int32> ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const & i_rFont, const vcl::font::PhysicalFontFace * i_pFontFace, HFONT& o_rOldFont); + std::tuple<HFONT, HFONT, sal_Int32> + ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const& i_rFont, + const vcl::font::PhysicalFontFace* i_pFontFace, HFONT& o_rOldFont); HDC getHDC() const { return mhLocalDC; } // NOTE: this doesn't transfer ownership! See class comment. diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 6e536d0a8dd8..f03547035e80 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -42,9 +42,10 @@ public: WinSalGraphics* GetGraphics() const { return m_pGraphics; } HFONT GetHFONT() const { return m_hFont; } + HFONT GetVerticalHFONT() const { return m_hVerticalFont; } + // Return true if the font is for vertical writing. - // I.e. the font name of the LOGFONT is prefixed with '@'. - bool IsCJKVerticalFont() const { return m_bIsCJKVerticalFont; } + bool IsCJKVerticalFont() const { return m_hVerticalFont != nullptr; } sal_Int32 GetTmDescent() const { return m_nTmDescent; } const WinFontFace * GetFontFace() const { return static_cast<const WinFontFace *>(LogicalFontInstance::GetFontFace()); } @@ -61,7 +62,7 @@ private: WinSalGraphics *m_pGraphics; HFONT m_hFont; - bool m_bIsCJKVerticalFont; + HFONT m_hVerticalFont = nullptr; sal_Int32 m_nTmDescent; mutable sal::systools::COMReference<IDWriteFontFace> mxDWFontFace; }; diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index 28a6dcf4dba5..06a90a361f18 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -719,36 +719,15 @@ void ImplGetLogFontFromFontSelect( const vcl::font::FontSelectPattern& rFont, rLogFont.lfQuality = bAntiAliased ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY; } -std::tuple<HFONT,bool,sal_Int32> WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const & i_rFont, - const vcl::font::PhysicalFontFace * i_pFontFace, - HFONT& o_rOldFont) +std::tuple<HFONT, HFONT, sal_Int32> +WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const& i_rFont, + const vcl::font::PhysicalFontFace* i_pFontFace, HFONT& o_rOldFont) { HFONT hNewFont = nullptr; LOGFONTW aLogFont; ImplGetLogFontFromFontSelect( i_rFont, i_pFontFace, aLogFont, getAntiAlias()); - bool bIsCJKVerticalFont = false; - // select vertical mode for printing if requested and available - if ( i_rFont.mbVertical && mbPrinter ) - { - constexpr size_t nLen = sizeof(aLogFont.lfFaceName) - sizeof(aLogFont.lfFaceName[0]); - // vertical fonts start with an '@' - memmove( &aLogFont.lfFaceName[1], &aLogFont.lfFaceName[0], nLen ); - aLogFont.lfFaceName[0] = '@'; - aLogFont.lfFaceName[LF_FACESIZE - 1] = 0; - - // check availability of vertical mode for this font - EnumFontFamiliesExW( getHDC(), &aLogFont, SalEnumQueryFontProcExW, - reinterpret_cast<LPARAM>(&bIsCJKVerticalFont), 0 ); - if( !bIsCJKVerticalFont ) - { - // restore non-vertical name if not vertical mode isn't available - memcpy( &aLogFont.lfFaceName[0], &aLogFont.lfFaceName[1], nLen ); - aLogFont.lfFaceName[LF_FACESIZE - 1] = 0; - } - } - hNewFont = ::CreateFontIndirectW( &aLogFont ); o_rOldFont = ::SelectFont(hDC, hNewFont); @@ -763,10 +742,19 @@ std::tuple<HFONT,bool,sal_Int32> WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::fon SelectFont(hDC, hNewFont2); DeleteFont( hNewFont ); hNewFont = hNewFont2; - bIsCJKVerticalFont = false; } - return std::make_tuple(hNewFont, bIsCJKVerticalFont, static_cast<sal_Int32>(aTextMetricW.tmDescent)); + // Optionally create a secondary font for non-rotated CJK glyphs in vertical context + HFONT hNewVerticalFont = nullptr; + if (i_rFont.mbVertical && mbPrinter) + { + aLogFont.lfEscapement = 0; + aLogFont.lfOrientation = 0; + hNewVerticalFont = ::CreateFontIndirectW(&aLogFont); + } + + return std::make_tuple(hNewFont, hNewVerticalFont, + static_cast<sal_Int32>(aTextMetricW.tmDescent)); } void WinSalGraphics::SetFont(LogicalFontInstance* pFont, int nFallbackLevel) diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 83c3a653b1ae..6f5538140a2e 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -88,36 +88,27 @@ bool ExTextOutRenderer::operator()(GenericSalLayout const& rLayout, SalGraphics& basegfx::B2DPoint aPos; const GlyphItem* pGlyph; const WinFontInstance* pWinFont = static_cast<const WinFontInstance*>(&rLayout.GetFont()); - UINT nTextAlign = GetTextAlign(hDC); - UINT nCurTextAlign = nTextAlign; - sal_Int32 nGlyphOffset = -pWinFont->GetTmDescent(); - while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) - { - wchar_t glyphWStr = pGlyph->glyphId(); - UINT32 nNewTextAlign = nCurTextAlign; - sal_Int32 nYOffset = 0; - - if (pWinFont->IsCJKVerticalFont() && pGlyph->IsVertical()) + bool bVertFontSelected = false; + auto fnUseVertFont = [&](bool bValue) { + if (bVertFontSelected != bValue) { - nNewTextAlign = VTA_CENTER | TA_BOTTOM; - nYOffset = nGlyphOffset; + bVertFontSelected = bValue; + SelectFont(hDC, + bVertFontSelected ? pWinFont->GetVerticalHFONT() : pWinFont->GetHFONT()); } - else - nNewTextAlign = nTextAlign; + }; - if (nCurTextAlign != nNewTextAlign) - SetTextAlign(hDC, nNewTextAlign); + while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) + { + wchar_t glyphWStr = pGlyph->glyphId(); - ExtTextOutW(hDC, aPos.getX(), aPos.getY() + nYOffset, ETO_GLYPH_INDEX, nullptr, &glyphWStr, - 1, nullptr); + fnUseVertFont(pWinFont->IsCJKVerticalFont() && pGlyph->IsVertical()); - nCurTextAlign = nNewTextAlign; + ExtTextOutW(hDC, aPos.getX(), aPos.getY(), ETO_GLYPH_INDEX, nullptr, &glyphWStr, 1, + nullptr); } - if (nCurTextAlign != nTextAlign) - SetTextAlign(hDC, nTextAlign); - return true; } @@ -137,7 +128,7 @@ WinFontInstance::WinFontInstance(const WinFontFace& rPFF, const vcl::font::FontS : LogicalFontInstance(rPFF, rFSP) , m_pGraphics(nullptr) , m_hFont(nullptr) - , m_bIsCJKVerticalFont(false) + , m_hVerticalFont(nullptr) , m_nTmDescent(0) { } @@ -146,6 +137,11 @@ WinFontInstance::~WinFontInstance() { if (m_hFont) ::DeleteFont(m_hFont); + + if (m_hVerticalFont) + { + ::DeleteFont(m_hVerticalFont); + } } float WinFontInstance::getHScale() const @@ -191,7 +187,7 @@ void WinFontInstance::SetGraphics(WinSalGraphics* pGraphics) return; HFONT hOrigFont; HDC hDC = m_pGraphics->getHDC(); - std::tie(m_hFont, m_bIsCJKVerticalFont, m_nTmDescent) + std::tie(m_hFont, m_hVerticalFont, m_nTmDescent) = m_pGraphics->ImplDoSetFont(hDC, GetFontSelectPattern(), GetFontFace(), hOrigFont); SelectObject(hDC, hOrigFont); }