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
)
55 SalData
* const pSalData
= GetSalData();
58 { // don't call this after DeInitVCL()
59 fprintf(stderr
, "TextOutRenderer fatal error: no SalData");
65 if (!pSalData
->m_pD2DWriteTextOutRenderer
66 || static_cast<D2DWriteTextOutRenderer
*>(pSalData
->m_pD2DWriteTextOutRenderer
.get())
67 ->GetRenderingModeNatural()
68 != bRenderingModeNatural
)
70 pSalData
->m_pD2DWriteTextOutRenderer
.reset(
71 new D2DWriteTextOutRenderer(bRenderingModeNatural
));
73 return *pSalData
->m_pD2DWriteTextOutRenderer
;
75 if (!pSalData
->m_pExTextOutRenderer
)
77 pSalData
->m_pExTextOutRenderer
.reset(new ExTextOutRenderer
);
79 return *pSalData
->m_pExTextOutRenderer
;
82 bool ExTextOutRenderer::operator()(GenericSalLayout
const& rLayout
, SalGraphics
& /*rGraphics*/,
83 HDC hDC
, bool /*bRenderingModeNatural*/)
87 const GlyphItem
* pGlyph
;
88 const WinFontInstance
* pWinFont
= static_cast<const WinFontInstance
*>(&rLayout
.GetFont());
89 UINT nTextAlign
= GetTextAlign(hDC
);
90 UINT nCurTextAlign
= nTextAlign
;
91 sal_Int32 nGlyphOffset
= -pWinFont
->GetTmDescent();
93 while (rLayout
.GetNextGlyph(&pGlyph
, aPos
, nStart
))
95 wchar_t glyphWStr
= pGlyph
->glyphId();
96 UINT32 nNewTextAlign
= nCurTextAlign
;
97 sal_Int32 nYOffset
= 0;
99 if (pWinFont
->IsCJKVerticalFont() && pGlyph
->IsVertical())
101 nNewTextAlign
= VTA_CENTER
| TA_BOTTOM
;
102 nYOffset
= nGlyphOffset
;
105 nNewTextAlign
= nTextAlign
;
107 if (nCurTextAlign
!= nNewTextAlign
)
108 SetTextAlign(hDC
, nNewTextAlign
);
110 ExtTextOutW(hDC
, aPos
.getX(), aPos
.getY() + nYOffset
, ETO_GLYPH_INDEX
, nullptr, &glyphWStr
,
113 nCurTextAlign
= nNewTextAlign
;
116 if (nCurTextAlign
!= nTextAlign
)
117 SetTextAlign(hDC
, nTextAlign
);
122 std::unique_ptr
<GenericSalLayout
> WinSalGraphics::GetTextLayout(int nFallbackLevel
)
124 assert(mpWinFontEntry
[nFallbackLevel
]);
125 if (!mpWinFontEntry
[nFallbackLevel
])
128 assert(mpWinFontEntry
[nFallbackLevel
]->GetFontFace());
130 mpWinFontEntry
[nFallbackLevel
]->SetGraphics(this);
131 return std::make_unique
<GenericSalLayout
>(*mpWinFontEntry
[nFallbackLevel
]);
134 WinFontInstance::WinFontInstance(const WinFontFace
& rPFF
, const vcl::font::FontSelectPattern
& rFSP
)
135 : LogicalFontInstance(rPFF
, rFSP
)
136 , m_pGraphics(nullptr)
139 , m_bIsCJKVerticalFont(false)
144 WinFontInstance::~WinFontInstance()
147 ::DeleteFont(m_hFont
);
150 bool WinFontInstance::hasHScale() const
152 const vcl::font::FontSelectPattern
& rPattern
= GetFontSelectPattern();
153 int nHeight(rPattern
.mnHeight
);
154 int nWidth(rPattern
.mnWidth
? rPattern
.mnWidth
* GetAverageWidthFactor() : nHeight
);
155 return nWidth
!= nHeight
;
158 float WinFontInstance::getHScale() const
160 const vcl::font::FontSelectPattern
& rPattern
= GetFontSelectPattern();
161 int nHeight(rPattern
.mnHeight
);
164 float nWidth(rPattern
.mnWidth
? rPattern
.mnWidth
* GetAverageWidthFactor() : nHeight
);
165 return nWidth
/ nHeight
;
168 void WinFontInstance::ImplInitHbFont(hb_font_t
* /*pHbFont*/)
171 // Calculate the AverageWidthFactor, see LogicalFontInstance::GetScale().
172 if (GetFontSelectPattern().mnWidth
)
174 double nUPEM
= GetFontFace()->UnitsPerEm();
177 GetObjectW(m_hFont
, sizeof(LOGFONTW
), &aLogFont
);
179 // Set the height (font size) to EM to minimize rounding errors.
180 aLogFont
.lfHeight
= -nUPEM
;
181 // Set width to the default to get the original value in the metrics.
182 aLogFont
.lfWidth
= 0;
184 TEXTMETRICW aFontMetric
;
186 // Get the font metrics.
187 HDC hDC
= m_pGraphics
->getHDC();
188 ScopedSelectedHFONT
hFont(hDC
, CreateFontIndirectW(&aLogFont
));
189 GetTextMetricsW(hDC
, &aFontMetric
);
192 SetAverageWidthFactor(nUPEM
/ aFontMetric
.tmAveCharWidth
);
196 void WinFontInstance::SetGraphics(WinSalGraphics
* pGraphics
)
198 m_pGraphics
= pGraphics
;
202 HDC hDC
= m_pGraphics
->getHDC();
203 std::tie(m_hFont
, m_bIsCJKVerticalFont
, m_nTmDescent
)
204 = m_pGraphics
->ImplDoSetFont(hDC
, GetFontSelectPattern(), GetFontFace(), hOrigFont
);
205 SelectObject(hDC
, hOrigFont
);
208 void WinSalGraphics::DrawTextLayout(const GenericSalLayout
& rLayout
, HDC hDC
, bool bUseDWrite
,
209 bool bRenderingModeNatural
)
211 TextOutRenderer
& render
= TextOutRenderer::get(bUseDWrite
, bRenderingModeNatural
);
212 render(rLayout
, *this, hDC
, bRenderingModeNatural
);
215 void WinSalGraphics::DrawTextLayout(const GenericSalLayout
& rLayout
)
217 if (!mbPrinter
&& mWinSalGraphicsImplBase
->DrawTextLayout(rLayout
))
218 return; // handled by mWinSalGraphicsImplBase
221 const WinFontInstance
* pWinFont
= static_cast<const WinFontInstance
*>(&rLayout
.GetFont());
222 const HFONT hLayoutFont
= pWinFont
->GetHFONT();
224 const HFONT hOrigFont
= ::SelectFont(hDC
, hLayoutFont
);
226 // DWrite text renderer performs vertical writing better except printing.
227 const bool bVerticalScreenText
228 = !mbPrinter
&& rLayout
.GetFont().GetFontSelectPattern().mbVertical
;
229 const bool bRenderingModeNatural
= rLayout
.GetTextRenderModeForResolutionIndependentLayout();
230 const bool bUseDWrite
= bVerticalScreenText
|| bRenderingModeNatural
;
231 DrawTextLayout(rLayout
, hDC
, bUseDWrite
, bRenderingModeNatural
);
233 ::SelectFont(hDC
, hOrigFont
);
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */