vcl/inc/win/salgdi.h      |    4 +++-
 vcl/inc/win/winlayout.hxx |    6 ++++++
 vcl/win/gdi/salfont.cxx   |   32 ++++++++++++++++++++++++++++++--
 vcl/win/gdi/winlayout.cxx |   38 +++++++++++++++++++++++++++++++++-----
 4 files changed, 72 insertions(+), 8 deletions(-)

New commits:
commit 25b77b4a684695e8948c8a97902c8e9de80b446e
Author:     Mark Hung <mark...@gmail.com>
AuthorDate: Mon Nov 1 20:53:19 2021 +0800
Commit:     Adolfo Jayme Barrientos <fit...@ubuntu.com>
CommitDate: Sat Dec 11 17:55:56 2021 +0100

    tdf#145322, tdf#144378 fix printing for vertical writing
    
    Printing still uses ExTextOutRenderer to render text because
    Skia haven't yet support printing and DWriteTextRenderer can't
    bind the printer DC.
    
    ExTextOutRenderer uses win32 API ExtTextOutW. In order to
    renderer upright CJK text in vertical writing with that API,
    the HFONT created with CreateFontIndirectW needs a font name
    prefixed with '@'. OTOH, use '@' prefixed font with Skia break
    the vertical writing unit test.
    
    - WinSalGraphics::ImplDoSetFont: use '@' prefixed font name
    if the requested font is vertical and is for printing.
    
    - ExTextOutRenderer: use SetTextAlign and text metric tmDescent
    to adjust vertical glyphs. It's not consistent with Skia or
    DWriteTextRenderer, and is still incorrect in many cases.
    
    The patch is adapted from reverting
    
    commit 5686c1aca40beb9514d40c86b4a3780a8a1334ba
    Author: Mark Hung <mark...@gmail.com>
    Date:   Sun May 2 14:45:45 2021 +0800
    
        vcl: use DWriteTextRenderer for vertical writing.
    
    Change-Id: Ib2d3df8b68cad4bebe0672c9da0a16b62aed99e6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125978
    Tested-by: Jenkins
    Reviewed-by: Mark Hung <mark...@gmail.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126545
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 959d8abc0301..bcd25f8e92dd 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -166,7 +166,9 @@ private:
     int                     mnPenWidth;         // line width
 
 public:
-    HFONT ImplDoSetFont(FontSelectPattern const & i_rFont, const 
PhysicalFontFace * i_pFontFace, HFONT& o_rOldFont);
+    // Return HFONT, and whether the font is for vertical writing ( prefixed 
with '@' )
+    // and tmDescent value for adjusting offset in vertical writing mode.
+    std::tuple<HFONT,bool,sal_Int32> ImplDoSetFont(FontSelectPattern const & 
i_rFont, const PhysicalFontFace * i_pFontFace, HFONT& o_rOldFont);
 
     HDC getHDC() const { return mhLocalDC; }
     void setHDC(HDC aNew) { mhLocalDC = aNew; }
diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx
index b4e51d8dc4bb..7cedb3f7a40b 100644
--- a/vcl/inc/win/winlayout.hxx
+++ b/vcl/inc/win/winlayout.hxx
@@ -43,6 +43,10 @@ public:
 
     HFONT GetHFONT() const { return m_hFont; }
     float GetScale() const { return m_fScale; }
+    // 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; }
+    sal_Int32 GetTmDescent() const { return m_nTmDescent; }
 
     // Prevent deletion of the HFONT in the WinFontInstance destructor
     // Used for the ScopedFont handling
@@ -62,6 +66,8 @@ private:
     WinSalGraphics *m_pGraphics;
     HFONT m_hFont;
     float m_fScale;
+    bool  m_bIsCJKVerticalFont;
+    sal_Int32 m_nTmDescent;
 };
 
 class TextOutRenderer
diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx
index 2830d6048590..4b74741d3b9e 100644
--- a/vcl/win/gdi/salfont.cxx
+++ b/vcl/win/gdi/salfont.cxx
@@ -760,6 +760,12 @@ void WinSalGraphics::SetTextColor( Color nColor )
     ::SetTextColor( getHDC(), aCol );
 }
 
+static int CALLBACK SalEnumQueryFontProcExW( const LOGFONTW*, const 
TEXTMETRICW*, DWORD, LPARAM lParam )
+{
+    *reinterpret_cast<bool*>(lParam) = true;
+    return 0;
+}
+
 void ImplGetLogFontFromFontSelect( const FontSelectPattern& rFont,
                                    const PhysicalFontFace* pFontFace,
                                    LOGFONTW& rLogFont )
@@ -809,7 +815,7 @@ void ImplGetLogFontFromFontSelect( const FontSelectPattern& 
rFont,
 
 }
 
-HFONT WinSalGraphics::ImplDoSetFont(FontSelectPattern const & i_rFont,
+std::tuple<HFONT,bool,sal_Int32> 
WinSalGraphics::ImplDoSetFont(FontSelectPattern const & i_rFont,
                                     const PhysicalFontFace * i_pFontFace,
                                     HFONT& o_rOldFont)
 {
@@ -818,6 +824,27 @@ HFONT WinSalGraphics::ImplDoSetFont(FontSelectPattern 
const & i_rFont,
     LOGFONTW aLogFont;
     ImplGetLogFontFromFontSelect( i_rFont, i_pFontFace, aLogFont );
 
+    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 );
 
     HDC hdcScreen = nullptr;
@@ -845,12 +872,13 @@ HFONT WinSalGraphics::ImplDoSetFont(FontSelectPattern 
const & i_rFont,
         SelectFont( getHDC(), hNewFont2 );
         DeleteFont( hNewFont );
         hNewFont = hNewFont2;
+        bIsCJKVerticalFont = false;
     }
 
     if( hdcScreen )
         ::ReleaseDC( nullptr, hdcScreen );
 
-    return hNewFont;
+    return std::make_tuple(hNewFont, bIsCJKVerticalFont, 
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 9c82ba88a279..c6b1a13dfe5e 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -83,12 +83,38 @@ bool ExTextOutRenderer::operator()(GenericSalLayout const& 
rLayout, SalGraphics&
     int nStart = 0;
     Point aPos(0, 0);
     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();
-        ExtTextOutW(hDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX, nullptr, 
&glyphWStr, 1, nullptr);
+        UINT32 nNewTextAlign = nCurTextAlign;
+        sal_Int32 nYOffset = 0;
+
+        if (pWinFont->IsCJKVerticalFont() && pGlyph->IsVertical())
+        {
+            tools::Rectangle aRect;
+            nNewTextAlign = VTA_CENTER | TA_BOTTOM;
+            nYOffset = nGlyphOffset;
+        }
+        else
+            nNewTextAlign = nTextAlign;
+
+        if (nCurTextAlign != nNewTextAlign)
+            SetTextAlign(hDC, nNewTextAlign);
+
+        ExtTextOutW(hDC, aPos.X(), aPos.Y() + nYOffset, ETO_GLYPH_INDEX, 
nullptr, &glyphWStr, 1,
+                    nullptr);
+
+        nCurTextAlign = nNewTextAlign;
     }
 
+    if (nCurTextAlign != nTextAlign)
+        SetTextAlign(hDC, nTextAlign);
+
     return true;
 }
 
@@ -109,6 +135,8 @@ WinFontInstance::WinFontInstance(const WinFontFace& rPFF, 
const FontSelectPatter
     , m_pGraphics(nullptr)
     , m_hFont(nullptr)
     , m_fScale(1.0f)
+    , m_bIsCJKVerticalFont(false)
+    , m_nTmDescent(0)
 {
 }
 
@@ -259,7 +287,8 @@ void WinFontInstance::SetGraphics(WinSalGraphics* pGraphics)
     if (m_hFont)
         return;
     HFONT hOrigFont;
-    m_hFont = m_pGraphics->ImplDoSetFont(GetFontSelectPattern(), 
GetFontFace(), hOrigFont);
+    std::tie(m_hFont, m_bIsCJKVerticalFont, m_nTmDescent)
+        = m_pGraphics->ImplDoSetFont(GetFontSelectPattern(), GetFontFace(), 
hOrigFont);
     SelectObject(m_pGraphics->getHDC(), hOrigFont);
 }
 
@@ -281,9 +310,8 @@ void WinSalGraphics::DrawTextLayout(const GenericSalLayout& 
rLayout)
 
     const HFONT hOrigFont = ::SelectFont(hDC, hLayoutFont);
 
-    // There isn't a way for Win32 API ExtTextOutW to render vertical-writing 
glyphs correctly,
-    // so let's use DWrite text renderer in this case.
-    DrawTextLayout(rLayout, hDC, 
rLayout.GetFont().GetFontSelectPattern().mbVertical);
+    // DWrite text renderer performs vertical writing better except printing.
+    DrawTextLayout(rLayout, hDC, !mbPrinter && 
rLayout.GetFont().GetFontSelectPattern().mbVertical);
 
     ::SelectFont(hDC, hOrigFont);
 }

Reply via email to