build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / font / fontmetric.cxx
blob42d8ea593a5aa36541eec362fc6f2cc270b4daab
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 <i18nlangtag/mslangid.hxx>
21 #include <vcl/fontcharmap.hxx>
22 #include <vcl/metric.hxx>
24 #include "impfontmetric.hxx"
25 #include "impfontmetricdata.hxx"
26 #include "PhysicalFontFace.hxx"
27 #include "sft.hxx"
29 #include <vector>
30 #include <set>
31 #include <cstdio>
33 using namespace ::com::sun::star;
34 using namespace ::com::sun::star::uno;
35 using namespace ::rtl;
36 using namespace ::utl;
38 FontMetric::FontMetric()
39 : mxImplMetric( new ImplFontMetric() )
42 FontMetric::FontMetric( const FontMetric& rFontMetric )
43 : Font( rFontMetric )
44 , mxImplMetric( rFontMetric.mxImplMetric )
47 FontMetric::~FontMetric()
49 mxImplMetric = nullptr;
52 FontMetric& FontMetric::operator=(const FontMetric& rFontMetric)
54 Font::operator=(rFontMetric);
55 mxImplMetric = rFontMetric.mxImplMetric;
56 return *this;
59 FontMetric& FontMetric::operator=(FontMetric&& rFontMetric)
61 Font::operator=(std::move(rFontMetric));
62 mxImplMetric = std::move(rFontMetric.mxImplMetric);
63 return *this;
66 bool FontMetric::operator==( const FontMetric& rFontMetric ) const
68 if( !Font::operator==( rFontMetric ) )
69 return false;
70 if( mxImplMetric == rFontMetric.mxImplMetric )
71 return true;
72 if( *mxImplMetric == *rFontMetric.mxImplMetric )
73 return true;
74 return false;
77 long FontMetric::GetAscent() const
79 return mxImplMetric->GetAscent();
82 void FontMetric::SetAscent( long nAscent )
84 mxImplMetric->SetAscent( nAscent );
87 long FontMetric::GetDescent() const
89 return mxImplMetric->GetDescent();
92 void FontMetric::SetDescent( long nDescent )
94 mxImplMetric->SetDescent( nDescent );
97 long FontMetric::GetInternalLeading() const
99 return mxImplMetric->GetInternalLeading();
102 void FontMetric::SetInternalLeading( long nLeading )
104 mxImplMetric->SetInternalLeading( nLeading );
107 long FontMetric::GetExternalLeading() const
109 return mxImplMetric->GetExternalLeading();
112 void FontMetric::SetExternalLeading( long nLeading )
114 mxImplMetric->SetExternalLeading( nLeading );
117 long FontMetric::GetLineHeight() const
119 return mxImplMetric->GetLineHeight();
122 void FontMetric::SetLineHeight( long nHeight )
124 mxImplMetric->SetLineHeight( nHeight );
127 long FontMetric::GetSlant() const
129 return mxImplMetric->GetSlant();
132 void FontMetric::SetSlant( long nSlant )
134 mxImplMetric->SetSlant( nSlant );
137 long FontMetric::GetBulletOffset() const
139 return mxImplMetric->GetBulletOffset();
142 void FontMetric::SetBulletOffset( long nOffset )
144 mxImplMetric->SetBulletOffset( nOffset );
147 bool FontMetric::IsFullstopCentered() const
149 return mxImplMetric->IsFullstopCentered();
152 void FontMetric::SetFullstopCenteredFlag(bool bScalable)
154 mxImplMetric->SetFullstopCenteredFlag( bScalable );
158 ImplFontMetric::ImplFontMetric()
159 : mnAscent( 0 ),
160 mnDescent( 0 ),
161 mnIntLeading( 0 ),
162 mnExtLeading( 0 ),
163 mnLineHeight( 0 ),
164 mnSlant( 0 ),
165 mnBulletOffset( 0 ),
166 mbFullstopCentered( false )
169 bool ImplFontMetric::operator==( const ImplFontMetric& r ) const
171 if (mbFullstopCentered != r.mbFullstopCentered)
172 return false;
173 if( mnAscent != r.mnAscent )
174 return false;
175 if( mnDescent != r.mnDescent )
176 return false;
177 if( mnIntLeading != r.mnIntLeading )
178 return false;
179 if( mnExtLeading != r.mnExtLeading )
180 return false;
181 if( mnSlant != r.mnSlant )
182 return false;
184 return true;
187 ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData )
188 : FontAttributes( rFontSelData )
189 , mnHeight ( rFontSelData.mnHeight )
190 , mnWidth ( rFontSelData.mnWidth )
191 , mnOrientation( (short)(rFontSelData.mnOrientation) )
192 , mnAscent( 0 )
193 , mnDescent( 0 )
194 , mnIntLeading( 0 )
195 , mnExtLeading( 0 )
196 , mnSlant( 0 )
197 , mnMinKashida( 0 )
198 , mbFullstopCentered( false )
199 , mnBulletOffset( 0 )
200 , mnUnderlineSize( 0 )
201 , mnUnderlineOffset( 0 )
202 , mnBUnderlineSize( 0 )
203 , mnBUnderlineOffset( 0 )
204 , mnDUnderlineSize( 0 )
205 , mnDUnderlineOffset1( 0 )
206 , mnDUnderlineOffset2( 0 )
207 , mnWUnderlineSize( 0 )
208 , mnWUnderlineOffset( 0 )
209 , mnAboveUnderlineSize( 0 )
210 , mnAboveUnderlineOffset( 0 )
211 , mnAboveBUnderlineSize( 0 )
212 , mnAboveBUnderlineOffset( 0 )
213 , mnAboveDUnderlineSize( 0 )
214 , mnAboveDUnderlineOffset1( 0 )
215 , mnAboveDUnderlineOffset2( 0 )
216 , mnAboveWUnderlineSize( 0 )
217 , mnAboveWUnderlineOffset( 0 )
218 , mnStrikeoutSize( 0 )
219 , mnStrikeoutOffset( 0 )
220 , mnBStrikeoutSize( 0 )
221 , mnBStrikeoutOffset( 0 )
222 , mnDStrikeoutSize( 0 )
223 , mnDStrikeoutOffset1( 0 )
224 , mnDStrikeoutOffset2( 0 )
226 // intialize the used font name
227 if( rFontSelData.mpFontData )
229 SetFamilyName( rFontSelData.mpFontData->GetFamilyName() );
230 SetStyleName( rFontSelData.mpFontData->GetStyleName() );
232 else
234 sal_Int32 nTokenPos = 0;
235 SetFamilyName( GetNextFontToken( rFontSelData.GetFamilyName(), nTokenPos ) );
236 SetStyleName( rFontSelData.GetStyleName() );
241 void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
243 long nDescent = mnDescent;
244 if ( nDescent <= 0 )
246 nDescent = mnAscent / 10;
247 if ( !nDescent )
248 nDescent = 1;
251 // #i55341# for some fonts it is not a good idea to calculate
252 // their text line metrics from the real font descent
253 // => work around this problem just for these fonts
254 if( 3*nDescent > mnAscent )
255 nDescent = mnAscent / 3;
257 long nLineHeight = ((nDescent*25)+50) / 100;
258 if ( !nLineHeight )
259 nLineHeight = 1;
260 long nLineHeight2 = nLineHeight / 2;
261 if ( !nLineHeight2 )
262 nLineHeight2 = 1;
264 long nBLineHeight = ((nDescent*50)+50) / 100;
265 if ( nBLineHeight == nLineHeight )
266 nBLineHeight++;
267 long nBLineHeight2 = nBLineHeight/2;
268 if ( !nBLineHeight2 )
269 nBLineHeight2 = 1;
271 long n2LineHeight = ((nDescent*16)+50) / 100;
272 if ( !n2LineHeight )
273 n2LineHeight = 1;
274 long n2LineDY = n2LineHeight;
275 /* #117909#
276 * add some pixels to minimum double line distance on higher resolution devices
278 long nMin2LineDY = 1 + pDev->GetDPIY()/150;
279 if ( n2LineDY < nMin2LineDY )
280 n2LineDY = nMin2LineDY;
281 long n2LineDY2 = n2LineDY/2;
282 if ( !n2LineDY2 )
283 n2LineDY2 = 1;
285 long nUnderlineOffset = mnDescent/2 + 1;
286 long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
288 mnUnderlineSize = nLineHeight;
289 mnUnderlineOffset = nUnderlineOffset - nLineHeight2;
291 mnBUnderlineSize = nBLineHeight;
292 mnBUnderlineOffset = nUnderlineOffset - nBLineHeight2;
294 mnDUnderlineSize = n2LineHeight;
295 mnDUnderlineOffset1 = nUnderlineOffset - n2LineDY2 - n2LineHeight;
296 mnDUnderlineOffset2 = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
298 long nWCalcSize = mnDescent;
299 if ( nWCalcSize < 6 )
301 if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
302 mnWUnderlineSize = nWCalcSize;
303 else
304 mnWUnderlineSize = 3;
306 else
307 mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
309 // Don't assume that wavelines are never placed below the descent, because for most fonts the waveline
310 // is drawn into the text
311 mnWUnderlineOffset = nUnderlineOffset;
313 mnStrikeoutSize = nLineHeight;
314 mnStrikeoutOffset = nStrikeoutOffset - nLineHeight2;
316 mnBStrikeoutSize = nBLineHeight;
317 mnBStrikeoutOffset = nStrikeoutOffset - nBLineHeight2;
319 mnDStrikeoutSize = n2LineHeight;
320 mnDStrikeoutOffset1 = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
321 mnDStrikeoutOffset2 = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
323 const vcl::Font& rFont ( pDev->GetFont() );
324 bool bCentered = true;
325 if (MsLangId::isCJK(rFont.GetLanguage()))
327 const OUString sFullstop( sal_Unicode( 0x3001 ) ); // Fullwidth fullstop
328 Rectangle aRect;
329 pDev->GetTextBoundRect( aRect, sFullstop );
330 const sal_uInt16 nH = rFont.GetFontSize().Height();
331 const sal_uInt16 nB = aRect.Left();
332 // Use 18.75% as a threshold to define a centered fullwidth fullstop.
333 // In general, nB/nH < 5% for most Japanese fonts.
334 bCentered = nB > (((nH >> 1)+nH)>>3);
336 SetFullstopCenteredFlag( bCentered );
338 mnBulletOffset = ( pDev->GetTextWidth( OUString( sal_Unicode( 0x20 ) ) ) - pDev->GetTextWidth( OUString( sal_Unicode( 0xb7 ) ) ) ) >> 1 ;
343 void ImplFontMetricData::ImplInitAboveTextLineSize()
345 long nIntLeading = mnIntLeading;
346 // TODO: assess usage of nLeading below (changed in extleading CWS)
347 // if no leading is available, we assume 15% of the ascent
348 if ( nIntLeading <= 0 )
350 nIntLeading = mnAscent*15/100;
351 if ( !nIntLeading )
352 nIntLeading = 1;
355 long nLineHeight = ((nIntLeading*25)+50) / 100;
356 if ( !nLineHeight )
357 nLineHeight = 1;
359 long nBLineHeight = ((nIntLeading*50)+50) / 100;
360 if ( nBLineHeight == nLineHeight )
361 nBLineHeight++;
363 long n2LineHeight = ((nIntLeading*16)+50) / 100;
364 if ( !n2LineHeight )
365 n2LineHeight = 1;
367 long nCeiling = -mnAscent;
369 mnAboveUnderlineSize = nLineHeight;
370 mnAboveUnderlineOffset = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
372 mnAboveBUnderlineSize = nBLineHeight;
373 mnAboveBUnderlineOffset = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
375 mnAboveDUnderlineSize = n2LineHeight;
376 mnAboveDUnderlineOffset1 = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
377 mnAboveDUnderlineOffset2 = nCeiling + (nIntLeading + n2LineHeight + 1) / 2;
379 long nWCalcSize = nIntLeading;
380 if ( nWCalcSize < 6 )
382 if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
383 mnAboveWUnderlineSize = nWCalcSize;
384 else
385 mnAboveWUnderlineSize = 3;
387 else
388 mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
390 mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
394 * Calculate line spacing:
396 * - hhea metrics should be used, since hhea is a mandatory font table and
397 * should always be present.
398 * - But if OS/2 is present, it should be used since it is mandatory in
399 * Windows.
400 * OS/2 has Typo and Win metrics, but the later was meant to control
401 * text clipping not line spacing and can be ridiculously large.
402 * Unfortunately many Windows application incorrectly use the Win metrics
403 * (thanks to GDI’s TEXTMETRIC) and old fonts might be designed with this
404 * in mind, so OpenType introduced a flag for fonts to indicate that they
405 * really want to use Typo metrics. So for best backward compatibility:
406 * - Use Win metrics if available.
407 * - Unless USE_TYPO_METRICS flag is set, in which case use Typo metrics.
409 void ImplFontMetricData::ImplCalcLineSpacing(const std::vector<uint8_t>& rHheaData,
410 const std::vector<uint8_t>& rOS2Data, int nUPEM)
412 mnAscent = mnDescent = mnExtLeading = mnIntLeading = 0;
414 double fScale = static_cast<double>(mnHeight) / nUPEM;
415 double fAscent = 0, fDescent = 0, fExtLeading = 0;
417 vcl::TTGlobalFontInfo rInfo;
418 memset(&rInfo, 0, sizeof(vcl::TTGlobalFontInfo));
419 GetTTFontMterics(rHheaData, rOS2Data, &rInfo);
421 // Try hhea table first.
422 if (rInfo.ascender || rInfo.descender)
424 fAscent = rInfo.ascender * fScale;
425 fDescent = -rInfo.descender * fScale;
426 fExtLeading = rInfo.linegap * fScale;
429 // But if OS/2 is present, prefer it.
430 if (rInfo.winAscent || rInfo.winDescent || rInfo.typoAscender || rInfo.typoDescender)
432 if (fAscent == 0 && fDescent == 0)
434 fAscent = rInfo.winAscent * fScale;
435 fDescent = rInfo.winDescent * fScale;
436 fExtLeading = 0;
439 const uint16_t kUseTypoMetricsMask = 1 << 7;
440 if (rInfo.fsSelection & kUseTypoMetricsMask)
442 fAscent = rInfo.typoAscender * fScale;
443 fDescent = -rInfo.typoDescender * fScale;
444 fExtLeading = rInfo.typoLineGap * fScale;
448 mnAscent = round(fAscent);
449 mnDescent = round(fDescent);
450 mnExtLeading = round(fExtLeading);
452 if (mnAscent || mnDescent)
453 mnIntLeading = mnAscent + mnDescent - mnHeight;
455 SAL_INFO("vcl.gdi.fontmetric",
456 "fsSelection: " << rInfo.fsSelection
457 << ", typoAscender: " << rInfo.typoAscender
458 << ", typoDescender: " << rInfo.typoDescender
459 << ", typoLineGap: " << rInfo.typoLineGap
460 << ", winAscent: " << rInfo.winAscent
461 << ", winDescent: " << rInfo.winDescent
462 << ", ascender: " << rInfo.ascender
463 << ", descender: " << rInfo.descender
464 << ", linegap: " << rInfo.linegap
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */