xref: /core/vcl/win/gdi/winlayout.cxx (revision 2a20616d09709427e8cf2474d4721836bce66b8e)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 #include <config_features.h>
22 
23 #include <memory>
24 
25 #include <o3tl/safeint.hxx>
26 #include <osl/module.h>
27 #include <osl/file.h>
28 #include <sal/log.hxx>
29 
30 #include <comphelper/scopeguard.hxx>
31 
32 #include <win/salgdi.h>
33 #include <win/saldata.hxx>
34 #include <win/wingdiimpl.hxx>
35 #include <ImplOutDevData.hxx>
36 
37 #include <win/DWriteTextRenderer.hxx>
38 #include <win/scoped_gdi.hxx>
39 
40 #include <sallayout.hxx>
41 
42 #include <cstdio>
43 #include <cstdlib>
44 
45 #include <rtl/character.hxx>
46 
47 #include <algorithm>
48 
49 #include <shlwapi.h>
50 #include <winver.h>
51 
get(bool bUseDWrite,bool bRenderingModeNatural,bool bAntiAlias)52 TextOutRenderer& TextOutRenderer::get(bool bUseDWrite, bool bRenderingModeNatural, bool bAntiAlias)
53 {
54     SalData* const pSalData = GetSalData();
55 
56     if (!pSalData)
57     { // don't call this after DeInitVCL()
58         fprintf(stderr, "TextOutRenderer fatal error: no SalData");
59         abort();
60     }
61 
62     if (bUseDWrite)
63     {
64         const auto mode = D2DWriteTextOutRenderer::GetMode(bRenderingModeNatural, bAntiAlias);
65         if (pSalData->m_pD2DWriteTextOutRenderer)
66         {
67             auto pRenderer
68                 = static_cast<D2DWriteTextOutRenderer*>(pSalData->m_pD2DWriteTextOutRenderer.get());
69             if (pRenderer->GetRenderingMode() == mode)
70                 return *pSalData->m_pD2DWriteTextOutRenderer;
71         }
72 
73         pSalData->m_pD2DWriteTextOutRenderer.reset(new D2DWriteTextOutRenderer(mode));
74         return *pSalData->m_pD2DWriteTextOutRenderer;
75     }
76     if (!pSalData->m_pExTextOutRenderer)
77     {
78         pSalData->m_pExTextOutRenderer.reset(new ExTextOutRenderer);
79     }
80     return *pSalData->m_pExTextOutRenderer;
81 }
82 
operator ()(GenericSalLayout const & rLayout,SalGraphics &,HDC hDC)83 bool ExTextOutRenderer::operator()(GenericSalLayout const& rLayout, SalGraphics& /*rGraphics*/,
84                                    HDC hDC)
85 {
86     int nStart = 0;
87     basegfx::B2DPoint aPos;
88     const GlyphItem* pGlyph;
89     const WinFontInstance* pWinFont = static_cast<const WinFontInstance*>(&rLayout.GetFont());
90 
91     bool bVertFontSelected = false;
92     auto fnUseVertFont = [&](bool bValue) {
93         if (bVertFontSelected != bValue)
94         {
95             bVertFontSelected = bValue;
96             SelectFont(hDC,
97                        bVertFontSelected ? pWinFont->GetVerticalHFONT() : pWinFont->GetHFONT());
98         }
99     };
100 
101     while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart))
102     {
103         wchar_t glyphWStr = pGlyph->glyphId();
104 
105         fnUseVertFont(pWinFont->IsCJKVerticalFont() && pGlyph->IsVertical());
106 
107         ExtTextOutW(hDC, aPos.getX(), aPos.getY(), ETO_GLYPH_INDEX, nullptr, &glyphWStr, 1,
108                     nullptr);
109     }
110 
111     return true;
112 }
113 
GetTextLayout(int nFallbackLevel)114 std::unique_ptr<GenericSalLayout> WinSalGraphics::GetTextLayout(int nFallbackLevel)
115 {
116     assert(mpWinFontEntry[nFallbackLevel]);
117     if (!mpWinFontEntry[nFallbackLevel])
118         return nullptr;
119 
120     assert(mpWinFontEntry[nFallbackLevel]->GetFontFace());
121 
122     mpWinFontEntry[nFallbackLevel]->SetGraphics(this);
123     return std::make_unique<GenericSalLayout>(*mpWinFontEntry[nFallbackLevel]);
124 }
125 
WinFontInstance(const WinFontFace & rPFF,const vcl::font::FontSelectPattern & rFSP)126 WinFontInstance::WinFontInstance(const WinFontFace& rPFF, const vcl::font::FontSelectPattern& rFSP)
127     : LogicalFontInstance(rPFF, rFSP)
128     , m_pGraphics(nullptr)
129     , m_hFont(nullptr)
130     , m_hVerticalFont(nullptr)
131     , m_nTmDescent(0)
132 {
133 }
134 
~WinFontInstance()135 WinFontInstance::~WinFontInstance()
136 {
137     if (m_hFont)
138         ::DeleteFont(m_hFont);
139 
140     if (m_hVerticalFont)
141         ::DeleteFont(m_hVerticalFont);
142 }
143 
getHScale() const144 float WinFontInstance::getHScale() const
145 {
146     const vcl::font::FontSelectPattern& rPattern = GetFontSelectPattern();
147     if (!rPattern.mnHeight || !rPattern.mnWidth)
148         return 1.0;
149     return rPattern.mnWidth * GetAverageWidthFactor() / rPattern.mnHeight;
150 }
151 
ImplInitHbFont(hb_font_t *)152 void WinFontInstance::ImplInitHbFont(hb_font_t* /*pHbFont*/)
153 {
154     assert(m_pGraphics);
155     // Calculate the AverageWidthFactor, see LogicalFontInstance::GetScale().
156     if (!GetFontSelectPattern().mnWidth)
157         return;
158 
159     double nUPEM = GetFontFace()->UnitsPerEm();
160 
161     LOGFONTW aLogFont;
162     GetObjectW(m_hFont, sizeof(LOGFONTW), &aLogFont);
163 
164     // Set the height (font size) to EM to minimize rounding errors.
165     aLogFont.lfHeight = -nUPEM;
166     // Set width to the default to get the original value in the metrics.
167     aLogFont.lfWidth = 0;
168 
169     TEXTMETRICW aFontMetric;
170     {
171         // Get the font metrics.
172         HDC hDC = m_pGraphics->getHDC();
173         ScopedSelectedHFONT hFont(hDC, CreateFontIndirectW(&aLogFont));
174         GetTextMetricsW(hDC, &aFontMetric);
175     }
176 
177     SetAverageWidthFactor(nUPEM / aFontMetric.tmAveCharWidth);
178 }
179 
SetGraphics(WinSalGraphics * pGraphics)180 void WinFontInstance::SetGraphics(WinSalGraphics* pGraphics)
181 {
182     m_pGraphics = pGraphics;
183     if (m_hFont)
184         return;
185     HFONT hOrigFont;
186     HDC hDC = m_pGraphics->getHDC();
187     std::tie(m_hFont, m_hVerticalFont, m_nTmDescent)
188         = m_pGraphics->ImplDoSetFont(hDC, GetFontSelectPattern(), GetFontFace(), hOrigFont);
189     SelectObject(hDC, hOrigFont);
190 }
191 
DrawTextLayout(const GenericSalLayout & rLayout,HDC hDC,bool bUseDWrite,bool bRenderingModeNatural)192 void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout, HDC hDC, bool bUseDWrite,
193                                     bool bRenderingModeNatural)
194 {
195     auto& render = TextOutRenderer::get(bUseDWrite, bRenderingModeNatural, getAntiAlias());
196     render(rLayout, *this, hDC);
197 }
198 
DrawTextLayout(const GenericSalLayout & rLayout)199 void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
200 {
201     if (!mbPrinter && mWinSalGraphicsImplBase->DrawTextLayout(rLayout))
202         return; // handled by mWinSalGraphicsImplBase
203 
204     HDC hDC = getHDC();
205     const WinFontInstance* pWinFont = static_cast<const WinFontInstance*>(&rLayout.GetFont());
206     const HFONT hLayoutFont = pWinFont->GetHFONT();
207 
208     const HFONT hOrigFont = ::SelectFont(hDC, hLayoutFont);
209 
210     // DWrite text renderer performs vertical writing better except printing.
211     const bool bVerticalScreenText
212         = !mbPrinter && rLayout.GetFont().GetFontSelectPattern().mbVertical;
213     const bool bRenderingModeNatural = rLayout.GetSubpixelPositioning();
214     const bool bUseDWrite = bVerticalScreenText || bRenderingModeNatural;
215     DrawTextLayout(rLayout, hDC, bUseDWrite, bRenderingModeNatural);
216 
217     ::SelectFont(hDC, hOrigFont);
218 }
219 
220 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
221