1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <config_features.h>
25 #include <o3tl/safeint.hxx>
26 #include <osl/module.h>
28 #include <sal/log.hxx>
30 #include <comphelper/windowserrorstring.hxx>
31 #include <comphelper/scopeguard.hxx>
33 #include <win/salgdi.h>
34 #include <win/saldata.hxx>
35 #include <win/wingdiimpl.hxx>
36 #include <ImplOutDevData.hxx>
38 #include <win/DWriteTextRenderer.hxx>
39 #include <win/scoped_gdi.hxx>
41 #include <sallayout.hxx>
46 #include <rtl/character.hxx>
53 TextOutRenderer
& TextOutRenderer::get(bool bUseDWrite
, bool bRenderingModeNatural
, bool bAntiAlias
)
55 SalData
* const pSalData
= GetSalData();
58 { // don't call this after DeInitVCL()
59 fprintf(stderr
, "TextOutRenderer fatal error: no SalData");
65 const auto mode
= D2DWriteTextOutRenderer::GetMode(bRenderingModeNatural
, bAntiAlias
);
66 if (pSalData
->m_pD2DWriteTextOutRenderer
)
69 = static_cast<D2DWriteTextOutRenderer
*>(pSalData
->m_pD2DWriteTextOutRenderer
.get());
70 if (pRenderer
->GetRenderingMode() == mode
)
71 return *pSalData
->m_pD2DWriteTextOutRenderer
;
74 pSalData
->m_pD2DWriteTextOutRenderer
.reset(new D2DWriteTextOutRenderer(mode
));
75 return *pSalData
->m_pD2DWriteTextOutRenderer
;
77 if (!pSalData
->m_pExTextOutRenderer
)
79 pSalData
->m_pExTextOutRenderer
.reset(new ExTextOutRenderer
);
81 return *pSalData
->m_pExTextOutRenderer
;
84 bool ExTextOutRenderer::operator()(GenericSalLayout
const& rLayout
, SalGraphics
& /*rGraphics*/,
88 basegfx::B2DPoint aPos
;
89 const GlyphItem
* pGlyph
;
90 const WinFontInstance
* pWinFont
= static_cast<const WinFontInstance
*>(&rLayout
.GetFont());
91 UINT nTextAlign
= GetTextAlign(hDC
);
92 UINT nCurTextAlign
= nTextAlign
;
93 sal_Int32 nGlyphOffset
= -pWinFont
->GetTmDescent();
95 while (rLayout
.GetNextGlyph(&pGlyph
, aPos
, nStart
))
97 wchar_t glyphWStr
= pGlyph
->glyphId();
98 UINT32 nNewTextAlign
= nCurTextAlign
;
99 sal_Int32 nYOffset
= 0;
101 if (pWinFont
->IsCJKVerticalFont() && pGlyph
->IsVertical())
103 nNewTextAlign
= VTA_CENTER
| TA_BOTTOM
;
104 nYOffset
= nGlyphOffset
;
107 nNewTextAlign
= nTextAlign
;
109 if (nCurTextAlign
!= nNewTextAlign
)
110 SetTextAlign(hDC
, nNewTextAlign
);
112 ExtTextOutW(hDC
, aPos
.getX(), aPos
.getY() + nYOffset
, ETO_GLYPH_INDEX
, nullptr, &glyphWStr
,
115 nCurTextAlign
= nNewTextAlign
;
118 if (nCurTextAlign
!= nTextAlign
)
119 SetTextAlign(hDC
, nTextAlign
);
124 std::unique_ptr
<GenericSalLayout
> WinSalGraphics::GetTextLayout(int nFallbackLevel
)
126 assert(mpWinFontEntry
[nFallbackLevel
]);
127 if (!mpWinFontEntry
[nFallbackLevel
])
130 assert(mpWinFontEntry
[nFallbackLevel
]->GetFontFace());
132 mpWinFontEntry
[nFallbackLevel
]->SetGraphics(this);
133 return std::make_unique
<GenericSalLayout
>(*mpWinFontEntry
[nFallbackLevel
]);
136 WinFontInstance::WinFontInstance(const WinFontFace
& rPFF
, const vcl::font::FontSelectPattern
& rFSP
)
137 : LogicalFontInstance(rPFF
, rFSP
)
138 , m_pGraphics(nullptr)
140 , m_bIsCJKVerticalFont(false)
145 WinFontInstance::~WinFontInstance()
148 ::DeleteFont(m_hFont
);
151 float WinFontInstance::getHScale() const
153 const vcl::font::FontSelectPattern
& rPattern
= GetFontSelectPattern();
154 if (!rPattern
.mnHeight
|| !rPattern
.mnWidth
)
156 return rPattern
.mnWidth
* GetAverageWidthFactor() / rPattern
.mnHeight
;
159 void WinFontInstance::ImplInitHbFont(hb_font_t
* /*pHbFont*/)
162 // Calculate the AverageWidthFactor, see LogicalFontInstance::GetScale().
163 if (GetFontSelectPattern().mnWidth
)
165 double nUPEM
= GetFontFace()->UnitsPerEm();
168 GetObjectW(m_hFont
, sizeof(LOGFONTW
), &aLogFont
);
170 // Set the height (font size) to EM to minimize rounding errors.
171 aLogFont
.lfHeight
= -nUPEM
;
172 // Set width to the default to get the original value in the metrics.
173 aLogFont
.lfWidth
= 0;
175 TEXTMETRICW aFontMetric
;
177 // Get the font metrics.
178 HDC hDC
= m_pGraphics
->getHDC();
179 ScopedSelectedHFONT
hFont(hDC
, CreateFontIndirectW(&aLogFont
));
180 GetTextMetricsW(hDC
, &aFontMetric
);
183 SetAverageWidthFactor(nUPEM
/ aFontMetric
.tmAveCharWidth
);
187 void WinFontInstance::SetGraphics(WinSalGraphics
* pGraphics
)
189 m_pGraphics
= pGraphics
;
193 HDC hDC
= m_pGraphics
->getHDC();
194 std::tie(m_hFont
, m_bIsCJKVerticalFont
, m_nTmDescent
)
195 = m_pGraphics
->ImplDoSetFont(hDC
, GetFontSelectPattern(), GetFontFace(), hOrigFont
);
196 SelectObject(hDC
, hOrigFont
);
199 void WinSalGraphics::DrawTextLayout(const GenericSalLayout
& rLayout
, HDC hDC
, bool bUseDWrite
,
200 bool bRenderingModeNatural
)
202 auto& render
= TextOutRenderer::get(bUseDWrite
, bRenderingModeNatural
, getAntiAlias());
203 render(rLayout
, *this, hDC
);
206 void WinSalGraphics::DrawTextLayout(const GenericSalLayout
& rLayout
)
208 if (!mbPrinter
&& mWinSalGraphicsImplBase
->DrawTextLayout(rLayout
))
209 return; // handled by mWinSalGraphicsImplBase
212 const WinFontInstance
* pWinFont
= static_cast<const WinFontInstance
*>(&rLayout
.GetFont());
213 const HFONT hLayoutFont
= pWinFont
->GetHFONT();
215 const HFONT hOrigFont
= ::SelectFont(hDC
, hLayoutFont
);
217 // DWrite text renderer performs vertical writing better except printing.
218 const bool bVerticalScreenText
219 = !mbPrinter
&& rLayout
.GetFont().GetFontSelectPattern().mbVertical
;
220 const bool bRenderingModeNatural
= rLayout
.GetSubpixelPositioning();
221 const bool bUseDWrite
= bVerticalScreenText
|| bRenderingModeNatural
;
222 DrawTextLayout(rLayout
, hDC
, bUseDWrite
, bRenderingModeNatural
);
224 ::SelectFont(hDC
, hOrigFont
);
227 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */