Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/font/fontmetric.cxx
Line
Count
Source
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
22
#include <i18nlangtag/mslangid.hxx>
23
#include <officecfg/Office/Common.hxx>
24
#include <sal/log.hxx>
25
#include <tools/stream.hxx>
26
#include <unotools/configmgr.hxx>
27
#include <unotools/fontdefs.hxx>
28
#include <vcl/metric.hxx>
29
#include <vcl/outdev.hxx>
30
31
#include <font/FontSelectPattern.hxx>
32
#include <font/PhysicalFontFace.hxx>
33
#include <font/LogicalFontInstance.hxx>
34
#include <font/FontMetricData.hxx>
35
#include <font/TrueTypeFont.hxx>
36
37
#include <com/sun/star/uno/Sequence.hxx>
38
#include <comphelper/sequence.hxx>
39
#include <hb-ot.h>
40
41
using namespace ::com::sun::star;
42
using namespace ::com::sun::star::uno;
43
using namespace ::rtl;
44
45
FontMetric::FontMetric()
46
19.4M
    : mnAscent(0)
47
19.4M
    , mnDescent(0)
48
19.4M
    , mnIntLeading(0)
49
19.4M
    , mnExtLeading(0)
50
19.4M
    , mnLineHeight(0)
51
19.4M
    , mnSlant(0)
52
19.4M
    , mnBulletOffset(0)
53
19.4M
    , mnHangingBaseline(0)
54
19.4M
    , mdEmSize(0.0)
55
19.4M
    , mdHorCJKAdvanceSize(0.0)
56
19.4M
    , mdVertCJKAdvanceSize(0.0)
57
19.4M
    , mbFullstopCentered(false)
58
19.4M
{}
59
60
14.9M
FontMetric::FontMetric( const FontMetric& rFontMetric ) = default;
61
62
FontMetric::FontMetric(vcl::font::PhysicalFontFace const& rFace)
63
1.94M
    : FontMetric()
64
1.94M
{
65
1.94M
    SetFamilyName(rFace.GetFamilyName());
66
1.94M
    SetStyleName(rFace.GetStyleName());
67
1.94M
    SetCharSet(rFace.IsMicrosoftSymbolEncoded() ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE);
68
1.94M
    SetFamily(rFace.GetFamilyType());
69
1.94M
    SetPitch(rFace.GetPitch());
70
1.94M
    SetWeight(rFace.GetWeight());
71
1.94M
    SetItalic(rFace.GetItalic());
72
1.94M
    SetAlignment(TextAlign::ALIGN_TOP);
73
1.94M
    SetWidthType(rFace.GetWidthType());
74
1.94M
    SetQuality(rFace.GetQuality() );
75
1.94M
}
76
77
FontMetric::~FontMetric()
78
34.4M
{
79
34.4M
}
80
81
194k
FontMetric& FontMetric::operator=(const FontMetric& rFontMetric) = default;
82
83
25.0k
FontMetric& FontMetric::operator=(FontMetric&& rFontMetric) = default;
84
85
bool FontMetric::EqualNoBase( const FontMetric& r ) const
86
6.94M
{
87
6.94M
    if (mbFullstopCentered != r.mbFullstopCentered)
88
0
        return false;
89
6.94M
    if( mnAscent     != r.mnAscent )
90
0
        return false;
91
6.94M
    if( mnDescent    != r.mnDescent )
92
0
        return false;
93
6.94M
    if( mnIntLeading != r.mnIntLeading )
94
0
        return false;
95
6.94M
    if( mnExtLeading != r.mnExtLeading )
96
0
        return false;
97
6.94M
    if( mnSlant      != r.mnSlant )
98
0
        return false;
99
100
6.94M
    return true;
101
6.94M
}
102
103
bool FontMetric::operator==( const FontMetric& r ) const
104
0
{
105
0
    if( Font::operator!=(r) )
106
0
        return false;
107
0
    return EqualNoBase(r);
108
0
}
109
110
bool FontMetric::EqualIgnoreColor( const FontMetric& r ) const
111
6.94M
{
112
6.94M
    if( !Font::EqualIgnoreColor(r) )
113
0
        return false;
114
6.94M
    return EqualNoBase(r);
115
6.94M
}
116
117
size_t FontMetric::GetHashValueNoBase() const
118
10.7M
{
119
10.7M
    size_t hash = 0;
120
10.7M
    o3tl::hash_combine( hash, mbFullstopCentered );
121
10.7M
    o3tl::hash_combine( hash, mnAscent );
122
10.7M
    o3tl::hash_combine( hash, mnDescent );
123
10.7M
    o3tl::hash_combine( hash, mnIntLeading );
124
10.7M
    o3tl::hash_combine( hash, mnExtLeading );
125
10.7M
    o3tl::hash_combine( hash, mnSlant );
126
10.7M
    return hash;
127
10.7M
}
128
129
size_t FontMetric::GetHashValueIgnoreColor() const
130
10.7M
{
131
10.7M
    size_t hash = GetHashValueNoBase();
132
10.7M
    o3tl::hash_combine( hash, Font::GetHashValueIgnoreColor());
133
10.7M
    return hash;
134
10.7M
}
135
136
FontMetricData::FontMetricData( const vcl::font::FontSelectPattern& rFontSelData )
137
161k
    : FontAttributes( rFontSelData )
138
161k
    , mnHeight ( rFontSelData.mnHeight )
139
161k
    , mnWidth ( rFontSelData.mnWidth )
140
161k
    , mnOrientation( static_cast<short>(rFontSelData.mnOrientation) )
141
161k
    , mnAscent( 0 )
142
161k
    , mnDescent( 0 )
143
161k
    , mnIntLeading( 0 )
144
161k
    , mnExtLeading( 0 )
145
161k
    , mnSlant( 0 )
146
161k
    , mnMinKashida( 0 )
147
161k
    , mnHangingBaseline( 0 )
148
161k
    , mdEmSize(0.0)
149
161k
    , mdHorCJKAdvanceSize(0.0)
150
161k
    , mdVertCJKAdvanceSize(0.0)
151
161k
    , mbFullstopCentered( false )
152
161k
    , mnBulletOffset( 0 )
153
161k
    , mnUnderlineSize( 0 )
154
161k
    , mnUnderlineOffset( 0 )
155
161k
    , mnBUnderlineSize( 0 )
156
161k
    , mnBUnderlineOffset( 0 )
157
161k
    , mnDUnderlineSize( 0 )
158
161k
    , mnDUnderlineOffset1( 0 )
159
161k
    , mnDUnderlineOffset2( 0 )
160
161k
    , mnWUnderlineSize( 0 )
161
161k
    , mnWUnderlineOffset( 0 )
162
161k
    , mnAboveUnderlineSize( 0 )
163
161k
    , mnAboveUnderlineOffset( 0 )
164
161k
    , mnAboveBUnderlineSize( 0 )
165
161k
    , mnAboveBUnderlineOffset( 0 )
166
161k
    , mnAboveDUnderlineSize( 0 )
167
161k
    , mnAboveDUnderlineOffset1( 0 )
168
161k
    , mnAboveDUnderlineOffset2( 0 )
169
161k
    , mnAboveWUnderlineSize( 0 )
170
161k
    , mnAboveWUnderlineOffset( 0 )
171
161k
    , mnStrikeoutSize( 0 )
172
161k
    , mnStrikeoutOffset( 0 )
173
161k
    , mnBStrikeoutSize( 0 )
174
161k
    , mnBStrikeoutOffset( 0 )
175
161k
    , mnDStrikeoutSize( 0 )
176
161k
    , mnDStrikeoutOffset1( 0 )
177
161k
    , mnDStrikeoutOffset2( 0 )
178
161k
{
179
    // initialize the used font name
180
161k
    sal_Int32 nTokenPos = 0;
181
161k
    SetFamilyName( OUString(GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos )) );
182
161k
    SetStyleName( rFontSelData.GetStyleName() );
183
161k
}
184
185
bool FontMetricData::ShouldNotUseUnderlineMetrics() const
186
323k
{
187
323k
    if (comphelper::IsFuzzing())
188
323k
        return false;
189
190
0
    css::uno::Sequence<OUString> rNoUnderlineMetricsList(
191
0
        officecfg::Office::Common::Misc::FontsDontUseUnderlineMetrics::get());
192
0
    if (comphelper::findValue(rNoUnderlineMetricsList, GetFamilyName()) != -1)
193
0
    {
194
0
        SAL_INFO("vcl.gdi.fontmetric", "Not using underline metrics for: " << GetFamilyName());
195
0
        return true;
196
0
    }
197
0
    return false;
198
0
}
199
200
bool FontMetricData::ImplInitTextLineSizeHarfBuzz(LogicalFontInstance* pFont)
201
323k
{
202
323k
    if (ShouldNotUseUnderlineMetrics())
203
0
        return false;
204
205
323k
    auto* pHbFont = pFont->GetHbFont();
206
207
323k
    hb_position_t nUnderlineSize;
208
323k
    if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_UNDERLINE_SIZE, &nUnderlineSize))
209
0
        return false;
210
323k
    hb_position_t nUnderlineOffset;
211
323k
    if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_UNDERLINE_OFFSET, &nUnderlineOffset))
212
0
        return false;
213
323k
    hb_position_t nStrikeoutSize;
214
323k
    if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_STRIKEOUT_SIZE, &nStrikeoutSize))
215
0
        return false;
216
323k
    hb_position_t nStrikeoutOffset;
217
323k
    if (!hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, &nStrikeoutOffset))
218
0
        return false;
219
220
323k
    double fScale = 0;
221
323k
    pFont->GetScale(nullptr, &fScale);
222
223
323k
    double nOffset = -nUnderlineOffset * fScale;
224
323k
    double nSize = nUnderlineSize * fScale;
225
323k
    double nSize2 = nSize / 2.;
226
323k
    double nBSize = nSize * 2.;
227
323k
    double n2Size = nBSize / 3.;
228
229
323k
    mnUnderlineSize = std::ceil(nSize);
230
323k
    mnUnderlineOffset = std::ceil(nOffset);
231
232
323k
    mnBUnderlineSize = std::ceil(nBSize);
233
323k
    mnBUnderlineOffset = std::ceil(nOffset - nSize2);
234
235
323k
    mnDUnderlineSize = std::ceil(n2Size);
236
323k
    mnDUnderlineOffset1 = mnBUnderlineOffset;
237
323k
    mnDUnderlineOffset2 = mnBUnderlineOffset + mnDUnderlineSize * 2;
238
239
323k
    mnWUnderlineSize = mnBUnderlineSize;
240
323k
    mnWUnderlineOffset = std::ceil(nOffset + nSize);
241
242
323k
    nOffset = -nStrikeoutOffset * fScale;
243
323k
    nSize = nStrikeoutSize * fScale;
244
323k
    nSize2 = nSize / 2.;
245
323k
    nBSize = nSize * 2.;
246
323k
    n2Size = nBSize / 3.;
247
248
323k
    mnStrikeoutSize = std::ceil(nSize);
249
323k
    mnStrikeoutOffset = std::ceil(nOffset);
250
251
323k
    mnBStrikeoutSize = std::ceil(nBSize);
252
323k
    mnBStrikeoutOffset = std::round(nOffset - nSize2);
253
254
323k
    mnDStrikeoutSize = std::ceil(n2Size);
255
323k
    mnDStrikeoutOffset1 = mnBStrikeoutOffset;
256
323k
    mnDStrikeoutOffset2 = mnBStrikeoutOffset + mnDStrikeoutSize * 2;
257
258
323k
    return true;
259
323k
}
260
261
void FontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
262
323k
{
263
323k
    mnBulletOffset = ( pDev->GetTextWidth( OUString( u' ' ) ) - pDev->GetTextWidth( OUString( u'\x00b7' ) ) ) >> 1 ;
264
265
323k
    if (ImplInitTextLineSizeHarfBuzz(const_cast<LogicalFontInstance*>(pDev->GetFontInstance())))
266
323k
        return;
267
268
0
    tools::Long nDescent = mnDescent;
269
0
    if ( nDescent <= 0 )
270
0
    {
271
0
        nDescent = mnAscent / 10;
272
0
        if ( !nDescent )
273
0
            nDescent = 1;
274
0
    }
275
276
    // #i55341# for some fonts it is not a good idea to calculate
277
    // their text line metrics from the real font descent
278
    // => work around this problem just for these fonts
279
0
    if( 3*nDescent > mnAscent )
280
0
        nDescent = mnAscent / 3;
281
282
0
    tools::Long nLineHeight = ((nDescent*25)+50) / 100;
283
0
    if ( !nLineHeight )
284
0
        nLineHeight = 1;
285
0
    tools::Long nLineHeight2 = nLineHeight / 2;
286
0
    if ( !nLineHeight2 )
287
0
        nLineHeight2 = 1;
288
289
0
    tools::Long nBLineHeight = ((nDescent*50)+50) / 100;
290
0
    if ( nBLineHeight == nLineHeight )
291
0
        nBLineHeight++;
292
0
    tools::Long nBLineHeight2 = nBLineHeight/2;
293
0
    if ( !nBLineHeight2 )
294
0
        nBLineHeight2 = 1;
295
296
0
    tools::Long n2LineHeight = ((nDescent*16)+50) / 100;
297
0
    if ( !n2LineHeight )
298
0
        n2LineHeight = 1;
299
0
    tools::Long n2LineDY = n2LineHeight;
300
     /* #117909#
301
      * add some pixels to minimum double line distance on higher resolution devices
302
      */
303
0
    tools::Long nMin2LineDY = 1 + pDev->GetDPIY()/150;
304
0
    if ( n2LineDY < nMin2LineDY )
305
0
        n2LineDY = nMin2LineDY;
306
0
    tools::Long n2LineDY2 = n2LineDY/2;
307
0
    if ( !n2LineDY2 )
308
0
        n2LineDY2 = 1;
309
310
0
    const vcl::Font& rFont ( pDev->GetFont() );
311
0
    bool bCJKVertical = MsLangId::isCJK(rFont.GetLanguage()) && rFont.IsVertical();
312
0
    tools::Long nUnderlineOffset = bCJKVertical ? mnDescent : (mnDescent/2 + 1);
313
0
    tools::Long nStrikeoutOffset = rFont.IsVertical() ? -((mnAscent - mnDescent) / 2) : -((mnAscent - mnIntLeading) / 3);
314
315
0
    mnUnderlineSize        = nLineHeight;
316
0
    mnUnderlineOffset      = nUnderlineOffset - nLineHeight2;
317
318
0
    mnBUnderlineSize       = nBLineHeight;
319
0
    mnBUnderlineOffset     = nUnderlineOffset - nBLineHeight2;
320
321
0
    mnDUnderlineSize       = n2LineHeight;
322
0
    mnDUnderlineOffset1    = nUnderlineOffset - n2LineDY2 - n2LineHeight;
323
0
    mnDUnderlineOffset2    = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
324
325
0
    tools::Long nWCalcSize = mnDescent;
326
0
    if ( nWCalcSize < 6 )
327
0
    {
328
0
        if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
329
0
            mnWUnderlineSize = nWCalcSize;
330
0
        else
331
0
            mnWUnderlineSize = 3;
332
0
    }
333
0
    else
334
0
        mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
335
336
337
    // Don't assume that wavelines are never placed below the descent, because for most fonts the waveline
338
    // is drawn into the text
339
0
    mnWUnderlineOffset     = nUnderlineOffset;
340
341
0
    mnStrikeoutSize        = nLineHeight;
342
0
    mnStrikeoutOffset      = nStrikeoutOffset - nLineHeight2;
343
344
0
    mnBStrikeoutSize       = nBLineHeight;
345
0
    mnBStrikeoutOffset     = nStrikeoutOffset - nBLineHeight2;
346
347
0
    mnDStrikeoutSize       = n2LineHeight;
348
0
    mnDStrikeoutOffset1    = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
349
0
    mnDStrikeoutOffset2    = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
350
351
0
}
352
353
354
void FontMetricData::ImplInitAboveTextLineSize( const OutputDevice* pDev )
355
161k
{
356
161k
    ImplInitTextLineSize(pDev);
357
358
161k
    tools::Long nIntLeading = mnIntLeading;
359
    // TODO: assess usage of nLeading below (changed in extleading CWS)
360
    // if no leading is available, we assume 15% of the ascent
361
161k
    if ( nIntLeading <= 0 )
362
4.73k
    {
363
4.73k
        nIntLeading = mnAscent*15/100;
364
4.73k
        if ( !nIntLeading )
365
4.73k
            nIntLeading = 1;
366
4.73k
    }
367
368
161k
    tools::Long nCeiling = -mnAscent;
369
370
161k
    mnAboveUnderlineSize       = mnUnderlineSize;
371
161k
    mnAboveUnderlineOffset     = nCeiling + (nIntLeading - mnUnderlineSize + 1) / 2;
372
373
161k
    mnAboveBUnderlineSize      = mnBUnderlineSize;
374
161k
    mnAboveBUnderlineOffset    = nCeiling + (nIntLeading - mnBUnderlineSize + 1) / 2;
375
376
161k
    mnAboveDUnderlineSize      = mnDUnderlineSize;
377
161k
    mnAboveDUnderlineOffset1   = nCeiling + (nIntLeading - 3*mnDUnderlineSize + 1) / 2;
378
161k
    mnAboveDUnderlineOffset2   = nCeiling + (nIntLeading +   mnDUnderlineSize + 1) / 2;
379
380
161k
    mnAboveWUnderlineSize = mnWUnderlineSize;
381
161k
    mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
382
161k
}
383
384
void FontMetricData::ImplInitFlags( const OutputDevice* pDev )
385
161k
{
386
161k
    const vcl::Font& rFont ( pDev->GetFont() );
387
161k
    bool bCentered = true;
388
161k
    if (MsLangId::isCJK(rFont.GetLanguage()))
389
2.02k
    {
390
2.02k
        tools::Rectangle aRect;
391
2.02k
        pDev->GetTextBoundRect( aRect, u"\x3001"_ustr ); // Fullwidth fullstop
392
2.02k
        const auto nH = rFont.GetFontSize().Height();
393
2.02k
        const auto nB = aRect.Left();
394
        // Use 18.75% as a threshold to define a centered fullwidth fullstop.
395
        // In general, nB/nH < 5% for most Japanese fonts.
396
2.02k
        bCentered = nB > (((nH >> 1)+nH)>>3);
397
2.02k
    }
398
161k
    SetFullstopCenteredFlag( bCentered );
399
161k
}
400
401
bool FontMetricData::ShouldUseWinMetrics(int nAscent, int nDescent, int nTypoAscent,
402
                                             int nTypoDescent, int nWinAscent,
403
                                             int nWinDescent) const
404
161k
{
405
161k
    if (comphelper::IsFuzzing())
406
161k
        return false;
407
408
0
    OUString aFontIdentifier(
409
0
        GetFamilyName() + ","
410
0
        + OUString::number(nAscent) + "," + OUString::number(nDescent) + ","
411
0
        + OUString::number(nTypoAscent) + "," + OUString::number(nTypoDescent) + ","
412
0
        + OUString::number(nWinAscent) + "," + OUString::number(nWinDescent));
413
414
0
    css::uno::Sequence<OUString> rWinMetricFontList(
415
0
        officecfg::Office::Common::Misc::FontsUseWinMetrics::get());
416
0
    if (comphelper::findValue(rWinMetricFontList, aFontIdentifier) != -1)
417
0
    {
418
0
        SAL_INFO("vcl.gdi.fontmetric", "Using win metrics for: " << aFontIdentifier);
419
0
        return true;
420
0
    }
421
0
    return false;
422
0
}
423
424
// These are “private” HarfBuzz metrics tags, they are supported by not exposed
425
// in the public header. They are safe to use, HarfBuzz just does not want to
426
// advertise them.
427
constexpr auto ASCENT_OS2 = static_cast<hb_ot_metrics_tag_t>(HB_TAG('O', 'a', 's', 'c'));
428
constexpr auto DESCENT_OS2 = static_cast<hb_ot_metrics_tag_t>(HB_TAG('O', 'd', 's', 'c'));
429
constexpr auto LINEGAP_OS2 = static_cast<hb_ot_metrics_tag_t>(HB_TAG('O', 'l', 'g', 'p'));
430
constexpr auto ASCENT_HHEA = static_cast<hb_ot_metrics_tag_t>(HB_TAG('H', 'a', 's', 'c'));
431
constexpr auto DESCENT_HHEA = static_cast<hb_ot_metrics_tag_t>(HB_TAG('H', 'd', 's', 'c'));
432
constexpr auto LINEGAP_HHEA = static_cast<hb_ot_metrics_tag_t>(HB_TAG('H', 'l', 'g', 'p'));
433
434
void FontMetricData::ImplCalcLineSpacing(LogicalFontInstance* pFontInstance)
435
161k
{
436
161k
    mnAscent = mnDescent = mnExtLeading = mnIntLeading = 0;
437
161k
    auto* pFace = pFontInstance->GetFontFace();
438
161k
    auto* pHbFont = pFontInstance->GetHbFont();
439
440
161k
    double fScale = 0;
441
161k
    pFontInstance->GetScale(nullptr, &fScale);
442
161k
    double fAscent = 0, fDescent = 0, fExtLeading = 0;
443
444
161k
    if (hb_ot_var_has_data(pFace->GetHbFace()))
445
0
    {
446
        // This is a variable font, trust HarfBuzz to give us the right metrics
447
        // and apply variations to them.
448
0
        hb_position_t nAscent, nDescent, nLineGap;
449
0
        if (hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &nAscent)
450
0
            && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER,
451
0
                                          &nDescent)
452
0
            && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP,
453
0
                                          &nLineGap))
454
0
        {
455
0
            fAscent = nAscent * fScale;
456
0
            fDescent = -nDescent * fScale;
457
0
            fExtLeading = nLineGap * fScale;
458
0
        }
459
0
    }
460
161k
    else
461
161k
    {
462
        // This is not a variable font, we try to choose the best metrics
463
        // ourselves for backward comparability:
464
        //
465
        // - hhea metrics should be used, since hhea is a mandatory font table
466
        //   and should always be present.
467
        // - But if OS/2 is present, it should be used since it is mandatory in
468
        //   Windows.
469
        //   OS/2 has Typo and Win metrics, but the later was meant to control
470
        //   text clipping not line spacing and can be ridiculously large.
471
        //   Unfortunately many Windows application incorrectly use the Win
472
        //   metrics (thanks to GDI’s TEXTMETRIC) and old fonts might be
473
        //   designed with this in mind, so OpenType introduced a flag for
474
        //   fonts to indicate that they really want to use Typo metrics. So
475
        //   for best backward compatibility:
476
        //   - Use Win metrics if available.
477
        //   - Unless USE_TYPO_METRICS flag is set, in which case use Typo
478
        //     metrics.
479
480
        // Try hhea table first.
481
161k
        hb_position_t nAscent = 0, nDescent = 0, nLineGap = 0;
482
161k
        if (hb_ot_metrics_get_position(pHbFont, ASCENT_HHEA, &nAscent)
483
161k
            && hb_ot_metrics_get_position(pHbFont, DESCENT_HHEA, &nDescent)
484
161k
            && hb_ot_metrics_get_position(pHbFont, LINEGAP_HHEA, &nLineGap))
485
161k
        {
486
            // tdf#107605: Some fonts have weird values here, so check that
487
            // ascender is +ve and descender is -ve as they normally should.
488
161k
            if (nAscent >= 0 && nDescent <= 0)
489
161k
            {
490
161k
                fAscent = nAscent * fScale;
491
161k
                fDescent = -nDescent * fScale;
492
161k
                fExtLeading = nLineGap * fScale;
493
161k
            }
494
161k
        }
495
496
        // But if OS/2 is present, prefer it.
497
161k
        hb_position_t nTypoAscent, nTypoDescent, nTypoLineGap, nWinAscent, nWinDescent;
498
161k
        if (hb_ot_metrics_get_position(pHbFont, ASCENT_OS2, &nTypoAscent)
499
161k
            && hb_ot_metrics_get_position(pHbFont, DESCENT_OS2, &nTypoDescent)
500
161k
            && hb_ot_metrics_get_position(pHbFont, LINEGAP_OS2, &nTypoLineGap)
501
161k
            && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT,
502
161k
                                          &nWinAscent)
503
161k
            && hb_ot_metrics_get_position(pHbFont, HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT,
504
161k
                                          &nWinDescent))
505
161k
        {
506
161k
            if ((fAscent == 0.0 && fDescent == 0.0)
507
161k
                || ShouldUseWinMetrics(nAscent, nDescent, nTypoAscent, nTypoDescent, nWinAscent,
508
161k
                                       nWinDescent))
509
2
            {
510
2
                fAscent = nWinAscent * fScale;
511
2
                fDescent = nWinDescent * fScale;
512
2
                fExtLeading = 0;
513
2
            }
514
515
161k
            bool bUseTypoMetrics
516
161k
                = hb_ot_fetch_bits(pFace->GetHbFace(), HB_OT_BITS_TAG_FS_SELECTION) & (1 << 7);
517
161k
            if (bUseTypoMetrics && nTypoAscent >= 0 && nTypoDescent <= 0)
518
0
            {
519
0
                fAscent = nTypoAscent * fScale;
520
0
                fDescent = -nTypoDescent * fScale;
521
0
                fExtLeading = nTypoLineGap * fScale;
522
0
            }
523
161k
        }
524
161k
    }
525
526
161k
    mnAscent = round(fAscent);
527
161k
    mnDescent = round(fDescent);
528
161k
    mnExtLeading = round(fExtLeading);
529
530
161k
    if (mnAscent || mnDescent)
531
161k
        mnIntLeading = mnAscent + mnDescent - mnHeight;
532
533
    // tdf#36709: Additional font metrics are needed for font-relative indentation
534
161k
    mdEmSize = static_cast<double>(mnHeight);
535
536
    // The ic is defined as the advance of CJK UNIFIED IDEOGRAPH-6C34 (水).
537
    // If this character does not exist, it defaults to em.
538
161k
    mdHorCJKAdvanceSize = mdEmSize;
539
161k
    mdVertCJKAdvanceSize = mdEmSize;
540
541
161k
    hb_codepoint_t nIcGlyph;
542
161k
    if (hb_font_get_glyph(pHbFont, 0x6C34, /*variation selector*/ 0, &nIcGlyph))
543
0
    {
544
0
        auto nIcHAdvance = hb_font_get_glyph_h_advance(pHbFont, nIcGlyph);
545
0
        mdHorCJKAdvanceSize = static_cast<double>(nIcHAdvance) * fScale;
546
547
0
        auto nIcVAdvance = hb_font_get_glyph_v_advance(pHbFont, nIcGlyph);
548
0
        mdVertCJKAdvanceSize = static_cast<double>(nIcVAdvance) * fScale;
549
0
    }
550
161k
}
551
552
void FontMetricData::ImplInitBaselines(LogicalFontInstance *pFontInstance)
553
161k
{
554
161k
    hb_font_t* pHbFont = pFontInstance->GetHbFont();
555
161k
    double fScale = 0;
556
161k
    pFontInstance->GetScale(nullptr, &fScale);
557
161k
    hb_position_t nBaseline = 0;
558
559
161k
    if (hb_ot_layout_get_baseline(pHbFont,
560
161k
             HB_OT_LAYOUT_BASELINE_TAG_HANGING,
561
161k
                                HB_DIRECTION_INVALID,
562
161k
                                HB_SCRIPT_UNKNOWN,
563
161k
                                HB_TAG_NONE,
564
161k
                                &nBaseline))
565
0
    {
566
0
        mnHangingBaseline = nBaseline * fScale;
567
0
    }
568
161k
    else
569
161k
    {
570
161k
        mnHangingBaseline = 0;
571
161k
    }
572
161k
}
573
574
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */