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 5686c1aca4
Author: Mark Hung <marklh9@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 <marklh9@gmail.com>
This commit is contained in:
parent
c95288aec4
commit
6720e9569d
4 changed files with 74 additions and 10 deletions
|
@ -181,7 +181,9 @@ private:
|
||||||
void DeInitGraphics();
|
void DeInitGraphics();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HFONT ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const & i_rFont, const vcl::font::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(HDC hDC, vcl::font::FontSelectPattern const & i_rFont, const vcl::font::PhysicalFontFace * i_pFontFace, HFONT& o_rOldFont);
|
||||||
|
|
||||||
HDC getHDC() const { return mhLocalDC; }
|
HDC getHDC() const { return mhLocalDC; }
|
||||||
// NOTE: this doesn't transfer ownership! See class comment.
|
// NOTE: this doesn't transfer ownership! See class comment.
|
||||||
|
|
|
@ -44,6 +44,10 @@ public:
|
||||||
|
|
||||||
HFONT GetHFONT() const { return m_hFont; }
|
HFONT GetHFONT() const { return m_hFont; }
|
||||||
float GetScale() const { return m_fScale; }
|
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; }
|
||||||
|
|
||||||
const WinFontFace * GetFontFace() const { return static_cast<const WinFontFace *>(LogicalFontInstance::GetFontFace()); }
|
const WinFontFace * GetFontFace() const { return static_cast<const WinFontFace *>(LogicalFontInstance::GetFontFace()); }
|
||||||
WinFontFace * GetFontFace() { return static_cast<WinFontFace *>(LogicalFontInstance::GetFontFace()); }
|
WinFontFace * GetFontFace() { return static_cast<WinFontFace *>(LogicalFontInstance::GetFontFace()); }
|
||||||
|
@ -59,6 +63,8 @@ private:
|
||||||
WinSalGraphics *m_pGraphics;
|
WinSalGraphics *m_pGraphics;
|
||||||
HFONT m_hFont;
|
HFONT m_hFont;
|
||||||
float m_fScale;
|
float m_fScale;
|
||||||
|
bool m_bIsCJKVerticalFont;
|
||||||
|
sal_Int32 m_nTmDescent;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TextOutRenderer
|
class TextOutRenderer
|
||||||
|
|
|
@ -762,6 +762,12 @@ void WinSalGraphics::SetTextColor( Color nColor )
|
||||||
::SetTextColor( getHDC(), aCol );
|
::SetTextColor( getHDC(), aCol );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CALLBACK SalEnumQueryFontProcExW( const LOGFONTW*, const TEXTMETRICW*, DWORD, LPARAM lParam )
|
||||||
|
{
|
||||||
|
*reinterpret_cast<bool*>(lParam) = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ImplGetLogFontFromFontSelect( const vcl::font::FontSelectPattern& rFont,
|
void ImplGetLogFontFromFontSelect( const vcl::font::FontSelectPattern& rFont,
|
||||||
const vcl::font::PhysicalFontFace* pFontFace,
|
const vcl::font::PhysicalFontFace* pFontFace,
|
||||||
LOGFONTW& rLogFont )
|
LOGFONTW& rLogFont )
|
||||||
|
@ -811,7 +817,7 @@ void ImplGetLogFontFromFontSelect( const vcl::font::FontSelectPattern& rFont,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HFONT WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const & i_rFont,
|
std::tuple<HFONT,bool,sal_Int32> WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const & i_rFont,
|
||||||
const vcl::font::PhysicalFontFace * i_pFontFace,
|
const vcl::font::PhysicalFontFace * i_pFontFace,
|
||||||
HFONT& o_rOldFont)
|
HFONT& o_rOldFont)
|
||||||
{
|
{
|
||||||
|
@ -820,6 +826,27 @@ HFONT WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const
|
||||||
LOGFONTW aLogFont;
|
LOGFONTW aLogFont;
|
||||||
ImplGetLogFontFromFontSelect( i_rFont, i_pFontFace, 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 );
|
hNewFont = ::CreateFontIndirectW( &aLogFont );
|
||||||
|
|
||||||
HDC hdcScreen = nullptr;
|
HDC hdcScreen = nullptr;
|
||||||
|
@ -847,12 +874,13 @@ HFONT WinSalGraphics::ImplDoSetFont(HDC hDC, vcl::font::FontSelectPattern const
|
||||||
SelectFont(hDC, hNewFont2);
|
SelectFont(hDC, hNewFont2);
|
||||||
DeleteFont( hNewFont );
|
DeleteFont( hNewFont );
|
||||||
hNewFont = hNewFont2;
|
hNewFont = hNewFont2;
|
||||||
|
bIsCJKVerticalFont = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( hdcScreen )
|
if( hdcScreen )
|
||||||
::ReleaseDC( nullptr, 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)
|
void WinSalGraphics::SetFont(LogicalFontInstance* pFont, int nFallbackLevel)
|
||||||
|
|
|
@ -83,12 +83,38 @@ bool ExTextOutRenderer::operator()(GenericSalLayout const& rLayout, SalGraphics&
|
||||||
int nStart = 0;
|
int nStart = 0;
|
||||||
Point aPos(0, 0);
|
Point aPos(0, 0);
|
||||||
const GlyphItem* pGlyph;
|
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))
|
while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart))
|
||||||
{
|
{
|
||||||
wchar_t glyphWStr = pGlyph->glyphId();
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +135,8 @@ WinFontInstance::WinFontInstance(const WinFontFace& rPFF, const vcl::font::FontS
|
||||||
, m_pGraphics(nullptr)
|
, m_pGraphics(nullptr)
|
||||||
, m_hFont(nullptr)
|
, m_hFont(nullptr)
|
||||||
, m_fScale(1.0f)
|
, m_fScale(1.0f)
|
||||||
|
, m_bIsCJKVerticalFont(false)
|
||||||
|
, m_nTmDescent(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,9 +288,10 @@ void WinFontInstance::SetGraphics(WinSalGraphics* pGraphics)
|
||||||
if (m_hFont)
|
if (m_hFont)
|
||||||
return;
|
return;
|
||||||
HFONT hOrigFont;
|
HFONT hOrigFont;
|
||||||
m_hFont = m_pGraphics->ImplDoSetFont(m_pGraphics->getHDC(), GetFontSelectPattern(),
|
HDC hDC = m_pGraphics->getHDC();
|
||||||
GetFontFace(), hOrigFont);
|
std::tie(m_hFont, m_bIsCJKVerticalFont, m_nTmDescent)
|
||||||
SelectObject(m_pGraphics->getHDC(), hOrigFont);
|
= m_pGraphics->ImplDoSetFont(hDC, GetFontSelectPattern(), GetFontFace(), hOrigFont);
|
||||||
|
SelectObject(hDC, hOrigFont);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout, HDC hDC, bool bUseDWrite)
|
void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout, HDC hDC, bool bUseDWrite)
|
||||||
|
@ -283,9 +312,8 @@ void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
|
||||||
|
|
||||||
const HFONT hOrigFont = ::SelectFont(hDC, hLayoutFont);
|
const HFONT hOrigFont = ::SelectFont(hDC, hLayoutFont);
|
||||||
|
|
||||||
// There isn't a way for Win32 API ExtTextOutW to render vertical-writing glyphs correctly,
|
// DWrite text renderer performs vertical writing better except printing.
|
||||||
// so let's use DWrite text renderer in this case.
|
DrawTextLayout(rLayout, hDC, !mbPrinter && rLayout.GetFont().GetFontSelectPattern().mbVertical);
|
||||||
DrawTextLayout(rLayout, hDC, rLayout.GetFont().GetFontSelectPattern().mbVertical);
|
|
||||||
|
|
||||||
::SelectFont(hDC, hOrigFont);
|
::SelectFont(hDC, hOrigFont);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue