bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / font / LogicalFontInstance.cxx
blobee9c01b3881f720b1a42fe02485d089a0c298d3b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <hb-ot.h>
23 #include <hb-graphite2.h>
25 #include <font/PhysicalFontFace.hxx>
26 #include <font/LogicalFontInstance.hxx>
27 #include <impfontcache.hxx>
29 LogicalFontInstance::LogicalFontInstance(const vcl::font::PhysicalFontFace& rFontFace,
30 const vcl::font::FontSelectPattern& rFontSelData)
31 : mxFontMetric(new ImplFontMetricData(rFontSelData))
32 , mpConversion(nullptr)
33 , mnLineHeight(0)
34 , mnOwnOrientation(0)
35 , mnOrientation(0)
36 , mbInit(false)
37 , mpFontCache(nullptr)
38 , m_aFontSelData(rFontSelData)
39 , m_pHbFont(nullptr)
40 , m_nAveWidthFactor(1.0f)
41 , m_pFontFace(&const_cast<vcl::font::PhysicalFontFace&>(rFontFace))
45 LogicalFontInstance::~LogicalFontInstance()
47 maUnicodeFallbackList.clear();
48 mpFontCache = nullptr;
49 mxFontMetric = nullptr;
51 if (m_pHbFont)
52 hb_font_destroy(m_pHbFont);
54 if (m_pHbFontUntransformed)
55 hb_font_destroy(m_pHbFontUntransformed);
57 if (m_pHbDrawFuncs)
58 hb_draw_funcs_destroy(m_pHbDrawFuncs);
61 hb_font_t* LogicalFontInstance::InitHbFont()
63 auto pFace = GetFontFace();
64 hb_face_t* pHbFace = pFace->GetHbFace();
65 assert(pHbFace);
66 auto nUPEM = pFace->UnitsPerEm();
68 hb_font_t* pHbFont = hb_font_create(pHbFace);
69 hb_font_set_scale(pHbFont, nUPEM, nUPEM);
70 hb_ot_font_set_funcs(pHbFont);
72 auto aVariations = pFace->GetVariations(*this);
73 if (!aVariations.empty())
74 hb_font_set_variations(pHbFont, aVariations.data(), aVariations.size());
76 // If we are applying artificial italic, instruct HarfBuzz to do the same
77 // so that mark positioning is also transformed.
78 if (NeedsArtificialItalic())
79 hb_font_set_synthetic_slant(pHbFont, ARTIFICIAL_ITALIC_SKEW);
81 ImplInitHbFont(pHbFont);
83 return pHbFont;
86 hb_font_t* LogicalFontInstance::GetHbFontUntransformed() const
88 auto* pHbFont = const_cast<LogicalFontInstance*>(this)->GetHbFont();
90 if (NeedsArtificialItalic()) // || NeedsArtificialBold()
92 if (!m_pHbFontUntransformed)
94 m_pHbFontUntransformed = hb_font_create_sub_font(pHbFont);
95 // Unset slant set on parent font.
96 // Does not actually work: https://github.com/harfbuzz/harfbuzz/issues/3890
97 hb_font_set_synthetic_slant(m_pHbFontUntransformed, 0);
99 return m_pHbFontUntransformed;
102 return pHbFont;
105 int LogicalFontInstance::GetKashidaWidth() const
107 sal_GlyphId nGlyph = GetGlyphIndex(0x0640);
108 if (nGlyph)
109 return std::ceil(GetGlyphWidth(nGlyph));
110 return 0;
113 void LogicalFontInstance::GetScale(double* nXScale, double* nYScale) const
115 double nUPEM = GetFontFace()->UnitsPerEm();
116 double nHeight(m_aFontSelData.mnHeight);
118 // On Windows, mnWidth is relative to average char width not font height,
119 // and we need to keep it that way for GDI to correctly scale the glyphs.
120 // Here we compensate for this so that HarfBuzz gives us the correct glyph
121 // positions.
122 double nWidth(m_aFontSelData.mnWidth ? m_aFontSelData.mnWidth * m_nAveWidthFactor : nHeight);
124 if (nYScale)
125 *nYScale = nHeight / nUPEM;
127 if (nXScale)
128 *nXScale = nWidth / nUPEM;
131 void LogicalFontInstance::AddFallbackForUnicode(sal_UCS4 cChar, FontWeight eWeight,
132 const OUString& rFontName, bool bEmbolden,
133 const ItalicMatrix& rMatrix)
135 MapEntry& rEntry = maUnicodeFallbackList[std::pair<sal_UCS4, FontWeight>(cChar, eWeight)];
136 rEntry.sFontName = rFontName;
137 rEntry.bEmbolden = bEmbolden;
138 rEntry.aItalicMatrix = rMatrix;
141 bool LogicalFontInstance::GetFallbackForUnicode(sal_UCS4 cChar, FontWeight eWeight,
142 OUString* pFontName, bool* pEmbolden,
143 ItalicMatrix* pMatrix) const
145 UnicodeFallbackList::const_iterator it
146 = maUnicodeFallbackList.find(std::pair<sal_UCS4, FontWeight>(cChar, eWeight));
147 if (it == maUnicodeFallbackList.end())
148 return false;
150 const MapEntry& rEntry = (*it).second;
151 *pFontName = rEntry.sFontName;
152 *pEmbolden = rEntry.bEmbolden;
153 *pMatrix = rEntry.aItalicMatrix;
154 return true;
157 void LogicalFontInstance::IgnoreFallbackForUnicode(sal_UCS4 cChar, FontWeight eWeight,
158 std::u16string_view rFontName)
160 UnicodeFallbackList::iterator it
161 = maUnicodeFallbackList.find(std::pair<sal_UCS4, FontWeight>(cChar, eWeight));
162 if (it == maUnicodeFallbackList.end())
163 return;
164 const MapEntry& rEntry = (*it).second;
165 if (rEntry.sFontName == rFontName)
166 maUnicodeFallbackList.erase(it);
169 bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& rRect,
170 bool bVertical) const
172 if (mpFontCache && mpFontCache->GetCachedGlyphBoundRect(this, nID, rRect))
173 return true;
175 bool res = ImplGetGlyphBoundRect(nID, rRect, bVertical);
176 if (mpFontCache && res)
177 mpFontCache->CacheGlyphBoundRect(this, nID, rRect);
178 return res;
181 sal_GlyphId LogicalFontInstance::GetGlyphIndex(uint32_t nUnicode, uint32_t nVariationSelector) const
183 auto* pHbFont = const_cast<LogicalFontInstance*>(this)->GetHbFont();
184 sal_GlyphId nGlyph = 0;
185 if (hb_font_get_glyph(pHbFont, nUnicode, nVariationSelector, &nGlyph))
186 return nGlyph;
187 return 0;
190 double LogicalFontInstance::GetGlyphWidth(sal_GlyphId nGlyph, bool bVertical, bool bScale) const
192 auto* pHbFont = const_cast<LogicalFontInstance*>(this)->GetHbFont();
193 int nWidth;
194 if (bVertical)
195 nWidth = hb_font_get_glyph_v_advance(pHbFont, nGlyph);
196 else
197 nWidth = hb_font_get_glyph_h_advance(pHbFont, nGlyph);
199 if (!bScale)
200 return nWidth;
202 double nScale = 0;
203 GetScale(&nScale, nullptr);
204 return double(nWidth * nScale);
207 bool LogicalFontInstance::IsGraphiteFont()
209 if (!m_xbIsGraphiteFont)
211 m_xbIsGraphiteFont
212 = hb_graphite2_face_get_gr_face(hb_font_get_face(GetHbFont())) != nullptr;
214 return *m_xbIsGraphiteFont;
217 bool LogicalFontInstance::NeedOffsetCorrection(sal_Int32 nYOffset)
219 if (!m_xeFontFamilyEnum)
221 m_xeFontFamilyEnum = FontFamilyEnum::Unclassified;
223 // DFKai-SB (ukai.ttf) is a built-in font under traditional Chinese
224 // Windows. It has wrong extent values in glyf table. The problem results
225 // in wrong positioning of glyphs in vertical writing.
226 // Check https://github.com/harfbuzz/harfbuzz/issues/3521 for reference.
227 if (GetFontFace()->GetName(vcl::font::NAME_ID_FONT_FAMILY) == "DFKai-SB")
228 m_xeFontFamilyEnum = FontFamilyEnum::DFKaiSB;
231 bool bRet = true;
233 switch (*m_xeFontFamilyEnum)
235 case FontFamilyEnum::DFKaiSB:
236 // -839: optimization for one third of ukai.ttf
237 if (nYOffset == -839)
238 bRet = false;
239 break;
240 default:
241 bRet = false;
244 return bRet;
247 bool LogicalFontInstance::NeedsArtificialBold() const
249 return m_aFontSelData.GetWeight() > WEIGHT_MEDIUM && m_pFontFace->GetWeight() <= WEIGHT_MEDIUM;
252 bool LogicalFontInstance::NeedsArtificialItalic() const
254 return m_aFontSelData.GetItalic() != ITALIC_NONE && m_pFontFace->GetItalic() == ITALIC_NONE;
257 namespace
259 void move_to_func(hb_draw_funcs_t*, void* /*pDrawData*/, hb_draw_state_t*, float to_x, float to_y,
260 void* pUserData)
262 auto pPoly = static_cast<basegfx::B2DPolygon*>(pUserData);
263 pPoly->append(basegfx::B2DPoint(to_x, -to_y));
266 void line_to_func(hb_draw_funcs_t*, void* /*pDrawData*/, hb_draw_state_t*, float to_x, float to_y,
267 void* pUserData)
269 auto pPoly = static_cast<basegfx::B2DPolygon*>(pUserData);
270 pPoly->append(basegfx::B2DPoint(to_x, -to_y));
273 void cubic_to_func(hb_draw_funcs_t*, void* /*pDrawData*/, hb_draw_state_t*, float control1_x,
274 float control1_y, float control2_x, float control2_y, float to_x, float to_y,
275 void* pUserData)
277 auto pPoly = static_cast<basegfx::B2DPolygon*>(pUserData);
278 pPoly->appendBezierSegment(basegfx::B2DPoint(control1_x, -control1_y),
279 basegfx::B2DPoint(control2_x, -control2_y),
280 basegfx::B2DPoint(to_x, -to_y));
283 void close_path_func(hb_draw_funcs_t*, void* pDrawData, hb_draw_state_t*, void* pUserData)
285 auto pPolyPoly = static_cast<basegfx::B2DPolyPolygon*>(pDrawData);
286 auto pPoly = static_cast<basegfx::B2DPolygon*>(pUserData);
287 pPolyPoly->append(*pPoly);
288 pPoly->clear();
292 basegfx::B2DPolyPolygon LogicalFontInstance::GetGlyphOutlineUntransformed(sal_GlyphId nGlyph) const
294 if (!m_pHbDrawFuncs)
296 m_pHbDrawFuncs = hb_draw_funcs_create();
297 auto pUserData = const_cast<basegfx::B2DPolygon*>(&m_aDrawPolygon);
298 hb_draw_funcs_set_move_to_func(m_pHbDrawFuncs, move_to_func, pUserData, nullptr);
299 hb_draw_funcs_set_line_to_func(m_pHbDrawFuncs, line_to_func, pUserData, nullptr);
300 hb_draw_funcs_set_cubic_to_func(m_pHbDrawFuncs, cubic_to_func, pUserData, nullptr);
301 // B2DPolyPolygon does not support quadratic curves, HarfBuzz will
302 // convert them to cubic curves for us if we don’t set a callback
303 // function.
304 //hb_draw_funcs_set_quadratic_to_func(m_pHbDrawFuncs, quadratic_to_func, pUserData, nullptr);
305 hb_draw_funcs_set_close_path_func(m_pHbDrawFuncs, close_path_func, pUserData, nullptr);
308 basegfx::B2DPolyPolygon aPolyPoly;
309 #if HB_VERSION_ATLEAST(7, 0, 0)
310 hb_font_draw_glyph(GetHbFontUntransformed(), nGlyph, m_pHbDrawFuncs, &aPolyPoly);
311 #else
312 hb_font_get_glyph_shape(GetHbFontUntransformed(), nGlyph, m_pHbDrawFuncs, &aPolyPoly);
313 #endif
314 return aPolyPoly;
317 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */