File: | home/maarten/src/libreoffice/core/include/tools/ref.hxx |
Warning: | line 56, column 30 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <i18nlangtag/mslangid.hxx> | ||||
21 | #include <i18nlangtag/lang.h> | ||||
22 | |||||
23 | #include <unotools/configmgr.hxx> | ||||
24 | #include <vcl/metric.hxx> | ||||
25 | #include <vcl/virdev.hxx> | ||||
26 | #include <vcl/print.hxx> | ||||
27 | #include <vcl/sysdata.hxx> | ||||
28 | #include <vcl/fontcharmap.hxx> | ||||
29 | #include <vcl/event.hxx> | ||||
30 | #include <font/FeatureCollector.hxx> | ||||
31 | #include <rtl/ustrbuf.hxx> | ||||
32 | #include <sal/log.hxx> | ||||
33 | #include <tools/debug.hxx> | ||||
34 | |||||
35 | #include <sallayout.hxx> | ||||
36 | #include <salgdi.hxx> | ||||
37 | #include <svdata.hxx> | ||||
38 | #include <impglyphitem.hxx> | ||||
39 | |||||
40 | #include <outdev.h> | ||||
41 | #include <window.h> | ||||
42 | |||||
43 | #include <PhysicalFontCollection.hxx> | ||||
44 | |||||
45 | #include <strings.hrc> | ||||
46 | |||||
47 | FontMetric OutputDevice::GetDevFont( int nDevFontIndex ) const | ||||
48 | { | ||||
49 | FontMetric aFontMetric; | ||||
50 | |||||
51 | ImplInitFontList(); | ||||
52 | |||||
53 | int nCount = GetDevFontCount(); | ||||
54 | if( nDevFontIndex < nCount ) | ||||
55 | { | ||||
56 | const PhysicalFontFace& rData = *mpDeviceFontList->Get( nDevFontIndex ); | ||||
57 | aFontMetric.SetFamilyName( rData.GetFamilyName() ); | ||||
58 | aFontMetric.SetStyleName( rData.GetStyleName() ); | ||||
59 | aFontMetric.SetCharSet( rData.GetCharSet() ); | ||||
60 | aFontMetric.SetFamily( rData.GetFamilyType() ); | ||||
61 | aFontMetric.SetPitch( rData.GetPitch() ); | ||||
62 | aFontMetric.SetWeight( rData.GetWeight() ); | ||||
63 | aFontMetric.SetItalic( rData.GetItalic() ); | ||||
64 | aFontMetric.SetAlignment( TextAlign::ALIGN_TOP ); | ||||
65 | aFontMetric.SetWidthType( rData.GetWidthType() ); | ||||
66 | aFontMetric.SetQuality( rData.GetQuality() ); | ||||
67 | } | ||||
68 | |||||
69 | return aFontMetric; | ||||
70 | } | ||||
71 | |||||
72 | int OutputDevice::GetDevFontCount() const | ||||
73 | { | ||||
74 | if( !mpDeviceFontList ) | ||||
75 | { | ||||
76 | if (!mxFontCollection) | ||||
77 | { | ||||
78 | return 0; | ||||
79 | } | ||||
80 | |||||
81 | mpDeviceFontList = mxFontCollection->GetDeviceFontList(); | ||||
82 | |||||
83 | if (!mpDeviceFontList->Count()) | ||||
84 | { | ||||
85 | mpDeviceFontList.reset(); | ||||
86 | return 0; | ||||
87 | } | ||||
88 | } | ||||
89 | return mpDeviceFontList->Count(); | ||||
90 | } | ||||
91 | |||||
92 | bool OutputDevice::IsFontAvailable( const OUString& rFontName ) const | ||||
93 | { | ||||
94 | ImplInitFontList(); | ||||
95 | PhysicalFontFamily* pFound = mxFontCollection->FindFontFamily( rFontName ); | ||||
96 | return (pFound != nullptr); | ||||
97 | } | ||||
98 | |||||
99 | int OutputDevice::GetDevFontSizeCount( const vcl::Font& rFont ) const | ||||
100 | { | ||||
101 | mpDeviceFontSizeList.reset(); | ||||
102 | |||||
103 | ImplInitFontList(); | ||||
104 | mpDeviceFontSizeList = mxFontCollection->GetDeviceFontSizeList( rFont.GetFamilyName() ); | ||||
105 | return mpDeviceFontSizeList->Count(); | ||||
106 | } | ||||
107 | |||||
108 | Size OutputDevice::GetDevFontSize( const vcl::Font& rFont, int nSizeIndex ) const | ||||
109 | { | ||||
110 | // check range | ||||
111 | int nCount = GetDevFontSizeCount( rFont ); | ||||
112 | if ( nSizeIndex >= nCount ) | ||||
113 | return Size(); | ||||
114 | |||||
115 | // when mapping is enabled round to .5 points | ||||
116 | Size aSize( 0, mpDeviceFontSizeList->Get( nSizeIndex ) ); | ||||
117 | if ( mbMap ) | ||||
118 | { | ||||
119 | aSize.setHeight( aSize.Height() * 10 ); | ||||
120 | MapMode aMap( MapUnit::Map10thInch, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) ); | ||||
121 | aSize = PixelToLogic( aSize, aMap ); | ||||
122 | aSize.AdjustHeight(5 ); | ||||
123 | aSize.setHeight( aSize.Height() / 10 ); | ||||
124 | long nRound = aSize.Height() % 5; | ||||
125 | if ( nRound >= 3 ) | ||||
126 | aSize.AdjustHeight(5-nRound); | ||||
127 | else | ||||
128 | aSize.AdjustHeight( -nRound ); | ||||
129 | aSize.setHeight( aSize.Height() * 10 ); | ||||
130 | aSize = LogicToPixel( aSize, aMap ); | ||||
131 | aSize = PixelToLogic( aSize ); | ||||
132 | aSize.AdjustHeight(5 ); | ||||
133 | aSize.setHeight( aSize.Height() / 10 ); | ||||
134 | } | ||||
135 | return aSize; | ||||
136 | } | ||||
137 | |||||
138 | namespace | ||||
139 | { | ||||
140 | struct UpdateFontsGuard | ||||
141 | { | ||||
142 | UpdateFontsGuard() | ||||
143 | { | ||||
144 | OutputDevice::ImplClearAllFontData(true); | ||||
145 | } | ||||
146 | |||||
147 | ~UpdateFontsGuard() | ||||
148 | { | ||||
149 | OutputDevice::ImplRefreshAllFontData(true); | ||||
150 | } | ||||
151 | }; | ||||
152 | } | ||||
153 | |||||
154 | bool OutputDevice::AddTempDevFont( const OUString& rFileURL, const OUString& rFontName ) | ||||
155 | { | ||||
156 | UpdateFontsGuard aUpdateFontsGuard; | ||||
157 | |||||
158 | ImplInitFontList(); | ||||
159 | |||||
160 | if( !mpGraphics && !AcquireGraphics() ) | ||||
161 | return false; | ||||
162 | |||||
163 | bool bRC = mpGraphics->AddTempDevFont( mxFontCollection.get(), rFileURL, rFontName ); | ||||
164 | if( !bRC ) | ||||
165 | return false; | ||||
166 | |||||
167 | if( mpAlphaVDev ) | ||||
168 | mpAlphaVDev->AddTempDevFont( rFileURL, rFontName ); | ||||
169 | |||||
170 | return true; | ||||
171 | } | ||||
172 | |||||
173 | bool OutputDevice::GetFontFeatures(std::vector<vcl::font::Feature>& rFontFeatures) const | ||||
174 | { | ||||
175 | if (!ImplNewFont()) | ||||
176 | return false; | ||||
177 | |||||
178 | LogicalFontInstance* pFontInstance = mpFontInstance.get(); | ||||
179 | if (!pFontInstance) | ||||
180 | return false; | ||||
181 | |||||
182 | hb_font_t* pHbFont = pFontInstance->GetHbFont(); | ||||
183 | if (!pHbFont) | ||||
184 | return false; | ||||
185 | |||||
186 | hb_face_t* pHbFace = hb_font_get_face(pHbFont); | ||||
187 | if (!pHbFace) | ||||
188 | return false; | ||||
189 | |||||
190 | const LanguageType eOfficeLanguage = Application::GetSettings().GetLanguageTag().getLanguageType(); | ||||
191 | |||||
192 | vcl::font::FeatureCollector aFeatureCollector(pHbFace, rFontFeatures, eOfficeLanguage); | ||||
193 | aFeatureCollector.collect(); | ||||
194 | |||||
195 | return true; | ||||
196 | } | ||||
197 | |||||
198 | FontMetric OutputDevice::GetFontMetric() const | ||||
199 | { | ||||
200 | FontMetric aMetric; | ||||
201 | if (!ImplNewFont()) | ||||
202 | return aMetric; | ||||
203 | |||||
204 | LogicalFontInstance* pFontInstance = mpFontInstance.get(); | ||||
205 | ImplFontMetricDataRef xFontMetric = pFontInstance->mxFontMetric; | ||||
206 | |||||
207 | // prepare metric | ||||
208 | aMetric = maFont; | ||||
209 | |||||
210 | // set aMetric with info from font | ||||
211 | aMetric.SetFamilyName( maFont.GetFamilyName() ); | ||||
212 | aMetric.SetStyleName( xFontMetric->GetStyleName() ); | ||||
213 | aMetric.SetFontSize( PixelToLogic( Size( xFontMetric->GetWidth(), xFontMetric->GetAscent() + xFontMetric->GetDescent() - xFontMetric->GetInternalLeading() ) ) ); | ||||
214 | aMetric.SetCharSet( xFontMetric->IsSymbolFont() ? RTL_TEXTENCODING_SYMBOL(((rtl_TextEncoding) 10)) : RTL_TEXTENCODING_UNICODE(((rtl_TextEncoding) 0xFFFF)) ); | ||||
215 | aMetric.SetFamily( xFontMetric->GetFamilyType() ); | ||||
216 | aMetric.SetPitch( xFontMetric->GetPitch() ); | ||||
217 | aMetric.SetWeight( xFontMetric->GetWeight() ); | ||||
218 | aMetric.SetItalic( xFontMetric->GetItalic() ); | ||||
219 | aMetric.SetAlignment( TextAlign::ALIGN_TOP ); | ||||
220 | aMetric.SetWidthType( xFontMetric->GetWidthType() ); | ||||
221 | if ( pFontInstance->mnOwnOrientation ) | ||||
222 | aMetric.SetOrientation( pFontInstance->mnOwnOrientation ); | ||||
223 | else | ||||
224 | aMetric.SetOrientation( xFontMetric->GetOrientation() ); | ||||
225 | |||||
226 | // set remaining metric fields | ||||
227 | aMetric.SetFullstopCenteredFlag( xFontMetric->IsFullstopCentered() ); | ||||
228 | aMetric.SetBulletOffset( xFontMetric->GetBulletOffset() ); | ||||
229 | aMetric.SetAscent( ImplDevicePixelToLogicHeight( xFontMetric->GetAscent() + mnEmphasisAscent ) ); | ||||
230 | aMetric.SetDescent( ImplDevicePixelToLogicHeight( xFontMetric->GetDescent() + mnEmphasisDescent ) ); | ||||
231 | aMetric.SetInternalLeading( ImplDevicePixelToLogicHeight( xFontMetric->GetInternalLeading() + mnEmphasisAscent ) ); | ||||
232 | // OutputDevice has its own external leading function due to #i60945# | ||||
233 | aMetric.SetExternalLeading( ImplDevicePixelToLogicHeight( GetFontExtLeading() ) ); | ||||
234 | aMetric.SetLineHeight( ImplDevicePixelToLogicHeight( xFontMetric->GetAscent() + xFontMetric->GetDescent() + mnEmphasisAscent + mnEmphasisDescent ) ); | ||||
235 | aMetric.SetSlant( ImplDevicePixelToLogicHeight( xFontMetric->GetSlant() ) ); | ||||
236 | |||||
237 | // get miscellaneous data | ||||
238 | aMetric.SetQuality( xFontMetric->GetQuality() ); | ||||
239 | |||||
240 | SAL_INFO("vcl.gdi.fontmetric", "OutputDevice::GetFontMetric:" << aMetric)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi.fontmetric")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "OutputDevice::GetFontMetric:" << aMetric) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi.fontmetric"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "240" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetFontMetric:" << aMetric), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "OutputDevice::GetFontMetric:" << aMetric; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ( "vcl.gdi.fontmetric"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "240" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::GetFontMetric:" << aMetric) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi.fontmetric" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "240" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetFontMetric:" << aMetric), 0); } else { ::std::ostringstream sal_detail_stream ; sal_detail_stream << "OutputDevice::GetFontMetric:" << aMetric; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO), ( "vcl.gdi.fontmetric"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "240" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
241 | |||||
242 | xFontMetric = nullptr; | ||||
243 | |||||
244 | return aMetric; | ||||
245 | } | ||||
246 | |||||
247 | FontMetric OutputDevice::GetFontMetric( const vcl::Font& rFont ) const | ||||
248 | { | ||||
249 | // select font, query metrics, select original font again | ||||
250 | vcl::Font aOldFont = GetFont(); | ||||
251 | const_cast<OutputDevice*>(this)->SetFont( rFont ); | ||||
252 | FontMetric aMetric( GetFontMetric() ); | ||||
253 | const_cast<OutputDevice*>(this)->SetFont( aOldFont ); | ||||
254 | return aMetric; | ||||
255 | } | ||||
256 | |||||
257 | bool OutputDevice::GetFontCharMap( FontCharMapRef& rxFontCharMap ) const | ||||
258 | { | ||||
259 | if (!InitFont()) | ||||
260 | return false; | ||||
261 | |||||
262 | FontCharMapRef xFontCharMap ( mpGraphics->GetFontCharMap() ); | ||||
263 | if (!xFontCharMap.is()) | ||||
264 | { | ||||
265 | FontCharMapRef xDefaultMap( new FontCharMap() ); | ||||
266 | rxFontCharMap = xDefaultMap; | ||||
267 | } | ||||
268 | else | ||||
269 | rxFontCharMap = xFontCharMap; | ||||
270 | |||||
271 | return !rxFontCharMap->IsDefaultMap(); | ||||
272 | } | ||||
273 | |||||
274 | bool OutputDevice::GetFontCapabilities( vcl::FontCapabilities& rFontCapabilities ) const | ||||
275 | { | ||||
276 | if (!InitFont()) | ||||
277 | return false; | ||||
278 | return mpGraphics->GetFontCapabilities(rFontCapabilities); | ||||
279 | } | ||||
280 | |||||
281 | void OutputDevice::ImplGetEmphasisMark( tools::PolyPolygon& rPolyPoly, bool& rPolyLine, | ||||
282 | tools::Rectangle& rRect1, tools::Rectangle& rRect2, | ||||
283 | long& rYOff, long& rWidth, | ||||
284 | FontEmphasisMark eEmphasis, | ||||
285 | long nHeight ) | ||||
286 | { | ||||
287 | static const PolyFlags aAccentPolyFlags[24] = | ||||
288 | { | ||||
289 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control, | ||||
290 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control, | ||||
291 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control, | ||||
292 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control, | ||||
293 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control, | ||||
294 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control, | ||||
295 | PolyFlags::Normal, PolyFlags::Normal, PolyFlags::Control, | ||||
296 | PolyFlags::Normal, PolyFlags::Control, PolyFlags::Control | ||||
297 | }; | ||||
298 | |||||
299 | static const long aAccentPos[48] = | ||||
300 | { | ||||
301 | 78, 0, | ||||
302 | 348, 79, | ||||
303 | 599, 235, | ||||
304 | 843, 469, | ||||
305 | 938, 574, | ||||
306 | 990, 669, | ||||
307 | 990, 773, | ||||
308 | 990, 843, | ||||
309 | 964, 895, | ||||
310 | 921, 947, | ||||
311 | 886, 982, | ||||
312 | 860, 999, | ||||
313 | 825, 999, | ||||
314 | 764, 999, | ||||
315 | 721, 964, | ||||
316 | 686, 895, | ||||
317 | 625, 791, | ||||
318 | 556, 660, | ||||
319 | 469, 504, | ||||
320 | 400, 400, | ||||
321 | 261, 252, | ||||
322 | 61, 61, | ||||
323 | 0, 27, | ||||
324 | 9, 0 | ||||
325 | }; | ||||
326 | |||||
327 | rWidth = 0; | ||||
328 | rYOff = 0; | ||||
329 | rPolyLine = false; | ||||
330 | |||||
331 | if ( !nHeight ) | ||||
332 | return; | ||||
333 | |||||
334 | FontEmphasisMark nEmphasisStyle = eEmphasis & FontEmphasisMark::Style; | ||||
335 | long nDotSize = 0; | ||||
336 | switch ( nEmphasisStyle ) | ||||
337 | { | ||||
338 | case FontEmphasisMark::Dot: | ||||
339 | // Dot has 55% of the height | ||||
340 | nDotSize = (nHeight*550)/1000; | ||||
341 | if ( !nDotSize ) | ||||
342 | nDotSize = 1; | ||||
343 | if ( nDotSize <= 2 ) | ||||
344 | rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) ); | ||||
345 | else | ||||
346 | { | ||||
347 | long nRad = nDotSize/2; | ||||
348 | tools::Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); | ||||
349 | rPolyPoly.Insert( aPoly ); | ||||
350 | } | ||||
351 | rYOff = ((nHeight*250)/1000)/2; // Center to the another EmphasisMarks | ||||
352 | rWidth = nDotSize; | ||||
353 | break; | ||||
354 | |||||
355 | case FontEmphasisMark::Circle: | ||||
356 | // Dot has 80% of the height | ||||
357 | nDotSize = (nHeight*800)/1000; | ||||
358 | if ( !nDotSize ) | ||||
359 | nDotSize = 1; | ||||
360 | if ( nDotSize <= 2 ) | ||||
361 | rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) ); | ||||
362 | else | ||||
363 | { | ||||
364 | long nRad = nDotSize/2; | ||||
365 | tools::Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); | ||||
366 | rPolyPoly.Insert( aPoly ); | ||||
367 | // BorderWidth is 15% | ||||
368 | long nBorder = (nDotSize*150)/1000; | ||||
369 | if ( nBorder <= 1 ) | ||||
370 | rPolyLine = true; | ||||
371 | else | ||||
372 | { | ||||
373 | tools::Polygon aPoly2( Point( nRad, nRad ), | ||||
374 | nRad-nBorder, nRad-nBorder ); | ||||
375 | rPolyPoly.Insert( aPoly2 ); | ||||
376 | } | ||||
377 | } | ||||
378 | rWidth = nDotSize; | ||||
379 | break; | ||||
380 | |||||
381 | case FontEmphasisMark::Disc: | ||||
382 | // Dot has 80% of the height | ||||
383 | nDotSize = (nHeight*800)/1000; | ||||
384 | if ( !nDotSize ) | ||||
385 | nDotSize = 1; | ||||
386 | if ( nDotSize <= 2 ) | ||||
387 | rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) ); | ||||
388 | else | ||||
389 | { | ||||
390 | long nRad = nDotSize/2; | ||||
391 | tools::Polygon aPoly( Point( nRad, nRad ), nRad, nRad ); | ||||
392 | rPolyPoly.Insert( aPoly ); | ||||
393 | } | ||||
394 | rWidth = nDotSize; | ||||
395 | break; | ||||
396 | |||||
397 | case FontEmphasisMark::Accent: | ||||
398 | // Dot has 80% of the height | ||||
399 | nDotSize = (nHeight*800)/1000; | ||||
400 | if ( !nDotSize ) | ||||
401 | nDotSize = 1; | ||||
402 | if ( nDotSize <= 2 ) | ||||
403 | { | ||||
404 | if ( nDotSize == 1 ) | ||||
405 | { | ||||
406 | rRect1 = tools::Rectangle( Point(), Size( nDotSize, nDotSize ) ); | ||||
407 | rWidth = nDotSize; | ||||
408 | } | ||||
409 | else | ||||
410 | { | ||||
411 | rRect1 = tools::Rectangle( Point(), Size( 1, 1 ) ); | ||||
412 | rRect2 = tools::Rectangle( Point( 1, 1 ), Size( 1, 1 ) ); | ||||
413 | } | ||||
414 | } | ||||
415 | else | ||||
416 | { | ||||
417 | tools::Polygon aPoly( SAL_N_ELEMENTS( aAccentPos )(sizeof(sal_n_array_size(aAccentPos))) / 2, | ||||
418 | reinterpret_cast<const Point*>(aAccentPos), | ||||
419 | aAccentPolyFlags ); | ||||
420 | double dScale = static_cast<double>(nDotSize)/1000.0; | ||||
421 | aPoly.Scale( dScale, dScale ); | ||||
422 | tools::Polygon aTemp; | ||||
423 | aPoly.AdaptiveSubdivide( aTemp ); | ||||
424 | tools::Rectangle aBoundRect = aTemp.GetBoundRect(); | ||||
425 | rWidth = aBoundRect.GetWidth(); | ||||
426 | nDotSize = aBoundRect.GetHeight(); | ||||
427 | rPolyPoly.Insert( aTemp ); | ||||
428 | } | ||||
429 | break; | ||||
430 | default: break; | ||||
431 | } | ||||
432 | |||||
433 | // calculate position | ||||
434 | long nOffY = 1+(mnDPIY/300); // one visible pixel space | ||||
435 | long nSpaceY = nHeight-nDotSize; | ||||
436 | if ( nSpaceY >= nOffY*2 ) | ||||
437 | rYOff += nOffY; | ||||
438 | if ( !(eEmphasis & FontEmphasisMark::PosBelow) ) | ||||
439 | rYOff += nDotSize; | ||||
440 | } | ||||
441 | |||||
442 | FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const vcl::Font& rFont ) | ||||
443 | { | ||||
444 | FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark(); | ||||
445 | |||||
446 | // If no Position is set, then calculate the default position, which | ||||
447 | // depends on the language | ||||
448 | if ( !(nEmphasisMark & (FontEmphasisMark::PosAbove | FontEmphasisMark::PosBelow)) ) | ||||
449 | { | ||||
450 | LanguageType eLang = rFont.GetLanguage(); | ||||
451 | // In Chinese Simplified the EmphasisMarks are below/left | ||||
452 | if (MsLangId::isSimplifiedChinese(eLang)) | ||||
453 | nEmphasisMark |= FontEmphasisMark::PosBelow; | ||||
454 | else | ||||
455 | { | ||||
456 | eLang = rFont.GetCJKContextLanguage(); | ||||
457 | // In Chinese Simplified the EmphasisMarks are below/left | ||||
458 | if (MsLangId::isSimplifiedChinese(eLang)) | ||||
459 | nEmphasisMark |= FontEmphasisMark::PosBelow; | ||||
460 | else | ||||
461 | nEmphasisMark |= FontEmphasisMark::PosAbove; | ||||
462 | } | ||||
463 | } | ||||
464 | |||||
465 | return nEmphasisMark; | ||||
466 | } | ||||
467 | |||||
468 | long OutputDevice::GetFontExtLeading() const | ||||
469 | { | ||||
470 | return mpFontInstance->mxFontMetric->GetExternalLeading(); | ||||
471 | } | ||||
472 | |||||
473 | void OutputDevice::ImplClearFontData( const bool bNewFontLists ) | ||||
474 | { | ||||
475 | // the currently selected logical font is no longer needed | ||||
476 | mpFontInstance.clear(); | ||||
477 | |||||
478 | mbInitFont = true; | ||||
479 | mbNewFont = true; | ||||
480 | |||||
481 | if ( bNewFontLists ) | ||||
482 | { | ||||
483 | mpDeviceFontList.reset(); | ||||
484 | mpDeviceFontSizeList.reset(); | ||||
485 | |||||
486 | // release all physically selected fonts on this device | ||||
487 | if( AcquireGraphics() ) | ||||
488 | mpGraphics->ReleaseFonts(); | ||||
489 | } | ||||
490 | |||||
491 | ImplSVData* pSVData = ImplGetSVData(); | ||||
492 | |||||
493 | if (mxFontCache && mxFontCache != pSVData->maGDIData.mxScreenFontCache) | ||||
494 | mxFontCache->Invalidate(); | ||||
495 | |||||
496 | if (bNewFontLists && AcquireGraphics()) | ||||
497 | { | ||||
498 | if (mxFontCollection && mxFontCollection != pSVData->maGDIData.mxScreenFontList) | ||||
499 | mxFontCollection->Clear(); | ||||
500 | } | ||||
501 | } | ||||
502 | |||||
503 | void OutputDevice::RefreshFontData( const bool bNewFontLists ) | ||||
504 | { | ||||
505 | ImplRefreshFontData( bNewFontLists ); | ||||
506 | } | ||||
507 | |||||
508 | void OutputDevice::ImplRefreshFontData( const bool bNewFontLists ) | ||||
509 | { | ||||
510 | if (bNewFontLists && AcquireGraphics()) | ||||
511 | mpGraphics->GetDevFontList( mxFontCollection.get() ); | ||||
512 | } | ||||
513 | |||||
514 | void OutputDevice::ImplUpdateFontData() | ||||
515 | { | ||||
516 | ImplClearFontData( true/*bNewFontLists*/ ); | ||||
517 | ImplRefreshFontData( true/*bNewFontLists*/ ); | ||||
518 | } | ||||
519 | |||||
520 | void OutputDevice::ImplClearAllFontData(bool bNewFontLists) | ||||
521 | { | ||||
522 | ImplSVData* pSVData = ImplGetSVData(); | ||||
523 | |||||
524 | ImplUpdateFontDataForAllFrames( &OutputDevice::ImplClearFontData, bNewFontLists ); | ||||
525 | |||||
526 | // clear global font lists to have them updated | ||||
527 | pSVData->maGDIData.mxScreenFontCache->Invalidate(); | ||||
528 | if ( !bNewFontLists ) | ||||
529 | return; | ||||
530 | |||||
531 | pSVData->maGDIData.mxScreenFontList->Clear(); | ||||
532 | vcl::Window * pFrame = pSVData->maFrameData.mpFirstFrame; | ||||
533 | if ( pFrame ) | ||||
534 | { | ||||
535 | if ( pFrame->AcquireGraphics() ) | ||||
536 | { | ||||
537 | OutputDevice *pDevice = pFrame; | ||||
538 | pDevice->mpGraphics->ClearDevFontCache(); | ||||
539 | pDevice->mpGraphics->GetDevFontList(pFrame->mpWindowImpl->mpFrameData->mxFontCollection.get()); | ||||
540 | } | ||||
541 | } | ||||
542 | } | ||||
543 | |||||
544 | void OutputDevice::ImplRefreshAllFontData(bool bNewFontLists) | ||||
545 | { | ||||
546 | auto svdata = ImplGetSVData(); | ||||
547 | DBG_TESTSOLARMUTEX()do { DbgTestSolarMutex(); } while(false); | ||||
548 | if (!svdata->mnFontUpdatesLockCount) | ||||
549 | ImplUpdateFontDataForAllFrames(&OutputDevice::ImplRefreshFontData, bNewFontLists); | ||||
550 | else | ||||
551 | { | ||||
552 | svdata->mbFontUpdatesPending = true; | ||||
553 | if (bNewFontLists) | ||||
554 | svdata->mbFontUpdatesNewLists = true; | ||||
555 | } | ||||
556 | } | ||||
557 | |||||
558 | void OutputDevice::ImplUpdateAllFontData(bool bNewFontLists) | ||||
559 | { | ||||
560 | OutputDevice::ImplClearAllFontData(bNewFontLists); | ||||
561 | OutputDevice::ImplRefreshAllFontData(bNewFontLists); | ||||
562 | } | ||||
563 | |||||
564 | void OutputDevice::ImplUpdateFontDataForAllFrames( const FontUpdateHandler_t pHdl, const bool bNewFontLists ) | ||||
565 | { | ||||
566 | ImplSVData* const pSVData = ImplGetSVData(); | ||||
567 | |||||
568 | // update all windows | ||||
569 | vcl::Window* pFrame = pSVData->maFrameData.mpFirstFrame; | ||||
570 | while ( pFrame ) | ||||
571 | { | ||||
572 | ( pFrame->*pHdl )( bNewFontLists ); | ||||
573 | |||||
574 | vcl::Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap; | ||||
575 | while ( pSysWin ) | ||||
576 | { | ||||
577 | ( pSysWin->*pHdl )( bNewFontLists ); | ||||
578 | pSysWin = pSysWin->mpWindowImpl->mpNextOverlap; | ||||
579 | } | ||||
580 | |||||
581 | pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame; | ||||
582 | } | ||||
583 | |||||
584 | // update all virtual devices | ||||
585 | VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev; | ||||
586 | while ( pVirDev ) | ||||
587 | { | ||||
588 | ( pVirDev->*pHdl )( bNewFontLists ); | ||||
589 | pVirDev = pVirDev->mpNext; | ||||
590 | } | ||||
591 | |||||
592 | // update all printers | ||||
593 | Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter; | ||||
594 | while ( pPrinter ) | ||||
595 | { | ||||
596 | ( pPrinter->*pHdl )( bNewFontLists ); | ||||
597 | pPrinter = pPrinter->mpNext; | ||||
598 | } | ||||
599 | } | ||||
600 | |||||
601 | void OutputDevice::LockFontUpdates(bool bLock) | ||||
602 | { | ||||
603 | auto svdata = ImplGetSVData(); | ||||
604 | DBG_TESTSOLARMUTEX()do { DbgTestSolarMutex(); } while(false); | ||||
605 | if (bLock) | ||||
606 | { | ||||
607 | ++svdata->mnFontUpdatesLockCount; | ||||
608 | } | ||||
609 | else if (svdata->mnFontUpdatesLockCount > 0) | ||||
610 | { | ||||
611 | --svdata->mnFontUpdatesLockCount; | ||||
612 | if (!svdata->mnFontUpdatesLockCount && svdata->mbFontUpdatesPending) | ||||
613 | { | ||||
614 | ImplRefreshAllFontData(svdata->mbFontUpdatesNewLists); | ||||
615 | |||||
616 | svdata->mbFontUpdatesPending = false; | ||||
617 | svdata->mbFontUpdatesNewLists = false; | ||||
618 | } | ||||
619 | } | ||||
620 | } | ||||
621 | |||||
622 | void OutputDevice::BeginFontSubstitution() | ||||
623 | { | ||||
624 | ImplSVData* pSVData = ImplGetSVData(); | ||||
625 | pSVData->maGDIData.mbFontSubChanged = false; | ||||
626 | } | ||||
627 | |||||
628 | void OutputDevice::EndFontSubstitution() | ||||
629 | { | ||||
630 | ImplSVData* pSVData = ImplGetSVData(); | ||||
631 | if ( pSVData->maGDIData.mbFontSubChanged ) | ||||
632 | { | ||||
633 | ImplUpdateAllFontData( false ); | ||||
634 | |||||
635 | DataChangedEvent aDCEvt( DataChangedEventType::FONTSUBSTITUTION ); | ||||
636 | Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt); | ||||
637 | Application::NotifyAllWindows( aDCEvt ); | ||||
638 | pSVData->maGDIData.mbFontSubChanged = false; | ||||
639 | } | ||||
640 | } | ||||
641 | |||||
642 | void OutputDevice::AddFontSubstitute( const OUString& rFontName, | ||||
643 | const OUString& rReplaceFontName, | ||||
644 | AddFontSubstituteFlags nFlags ) | ||||
645 | { | ||||
646 | ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; | ||||
647 | if( !rpSubst ) | ||||
648 | rpSubst = new ImplDirectFontSubstitution; | ||||
649 | rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags ); | ||||
650 | ImplGetSVData()->maGDIData.mbFontSubChanged = true; | ||||
651 | } | ||||
652 | |||||
653 | void ImplDirectFontSubstitution::AddFontSubstitute( const OUString& rFontName, | ||||
654 | const OUString& rSubstFontName, AddFontSubstituteFlags nFlags ) | ||||
655 | { | ||||
656 | maFontSubstList.emplace_back( rFontName, rSubstFontName, nFlags ); | ||||
657 | } | ||||
658 | |||||
659 | ImplFontSubstEntry::ImplFontSubstEntry( const OUString& rFontName, | ||||
660 | const OUString& rSubstFontName, AddFontSubstituteFlags nSubstFlags ) | ||||
661 | : mnFlags( nSubstFlags ) | ||||
662 | { | ||||
663 | maSearchName = GetEnglishSearchFontName( rFontName ); | ||||
664 | maSearchReplaceName = GetEnglishSearchFontName( rSubstFontName ); | ||||
665 | } | ||||
666 | |||||
667 | void OutputDevice::RemoveFontsSubstitute() | ||||
668 | { | ||||
669 | ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; | ||||
670 | if( pSubst ) | ||||
671 | pSubst->RemoveFontsSubstitute(); | ||||
672 | } | ||||
673 | |||||
674 | void ImplDirectFontSubstitution::RemoveFontsSubstitute() | ||||
675 | { | ||||
676 | maFontSubstList.clear(); | ||||
677 | } | ||||
678 | |||||
679 | bool ImplDirectFontSubstitution::FindFontSubstitute( OUString& rSubstName, | ||||
680 | const OUString& rSearchName ) const | ||||
681 | { | ||||
682 | // TODO: get rid of O(N) searches | ||||
683 | std::vector<ImplFontSubstEntry>::const_iterator it = std::find_if ( | ||||
684 | maFontSubstList.begin(), maFontSubstList.end(), | ||||
685 | [&] (const ImplFontSubstEntry& s) { return (s.mnFlags & AddFontSubstituteFlags::ALWAYS) | ||||
686 | && (s.maSearchName == rSearchName); } ); | ||||
687 | if (it != maFontSubstList.end()) | ||||
688 | { | ||||
689 | rSubstName = it->maSearchReplaceName; | ||||
690 | return true; | ||||
691 | } | ||||
692 | return false; | ||||
693 | } | ||||
694 | |||||
695 | void ImplFontSubstitute( OUString& rFontName ) | ||||
696 | { | ||||
697 | // must be canonicalised | ||||
698 | assert( GetEnglishSearchFontName( rFontName ) == rFontName )(static_cast <bool> (GetEnglishSearchFontName( rFontName ) == rFontName) ? void (0) : __assert_fail ("GetEnglishSearchFontName( rFontName ) == rFontName" , "/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" , 698, __extension__ __PRETTY_FUNCTION__)); | ||||
699 | |||||
700 | OUString aSubstFontName; | ||||
701 | |||||
702 | // apply user-configurable font replacement (eg, from the list in Tools->Options) | ||||
703 | const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst; | ||||
704 | if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName ) ) | ||||
705 | { | ||||
706 | rFontName = aSubstFontName; | ||||
707 | return; | ||||
708 | } | ||||
709 | } | ||||
710 | |||||
711 | //hidpi TODO: This routine has hard-coded font-sizes that break places such as DialControl | ||||
712 | vcl::Font OutputDevice::GetDefaultFont( DefaultFontType nType, LanguageType eLang, | ||||
713 | GetDefaultFontFlags nFlags, const OutputDevice* pOutDev ) | ||||
714 | { | ||||
715 | if (!pOutDev && !utl::ConfigManager::IsFuzzing()) // default is NULL | ||||
716 | pOutDev = Application::GetDefaultDevice(); | ||||
717 | |||||
718 | OUString aSearch; | ||||
719 | if (!utl::ConfigManager::IsFuzzing()) | ||||
720 | { | ||||
721 | LanguageTag aLanguageTag( | ||||
722 | ( eLang == LANGUAGE_NONELanguageType(0x00FF) || eLang == LANGUAGE_SYSTEMLanguageType(0x0000) || eLang == LANGUAGE_DONTKNOWLanguageType(0x03FF) ) ? | ||||
723 | Application::GetSettings().GetUILanguageTag() : | ||||
724 | LanguageTag( eLang )); | ||||
725 | |||||
726 | utl::DefaultFontConfiguration& rDefaults = utl::DefaultFontConfiguration::get(); | ||||
727 | OUString aDefault = rDefaults.getDefaultFont( aLanguageTag, nType ); | ||||
728 | |||||
729 | if( !aDefault.isEmpty() ) | ||||
730 | aSearch = aDefault; | ||||
731 | else | ||||
732 | aSearch = rDefaults.getUserInterfaceFont( aLanguageTag ); // use the UI font as a fallback | ||||
733 | } | ||||
734 | else | ||||
735 | aSearch = "Liberation Serif"; | ||||
736 | |||||
737 | vcl::Font aFont; | ||||
738 | aFont.SetPitch( PITCH_VARIABLE ); | ||||
739 | |||||
740 | switch ( nType ) | ||||
741 | { | ||||
742 | case DefaultFontType::SANS_UNICODE: | ||||
743 | case DefaultFontType::UI_SANS: | ||||
744 | aFont.SetFamily( FAMILY_SWISS ); | ||||
745 | break; | ||||
746 | |||||
747 | case DefaultFontType::SANS: | ||||
748 | case DefaultFontType::LATIN_HEADING: | ||||
749 | case DefaultFontType::LATIN_SPREADSHEET: | ||||
750 | case DefaultFontType::LATIN_DISPLAY: | ||||
751 | aFont.SetFamily( FAMILY_SWISS ); | ||||
752 | break; | ||||
753 | |||||
754 | case DefaultFontType::SERIF: | ||||
755 | case DefaultFontType::LATIN_TEXT: | ||||
756 | case DefaultFontType::LATIN_PRESENTATION: | ||||
757 | aFont.SetFamily( FAMILY_ROMAN ); | ||||
758 | break; | ||||
759 | |||||
760 | case DefaultFontType::FIXED: | ||||
761 | case DefaultFontType::LATIN_FIXED: | ||||
762 | case DefaultFontType::UI_FIXED: | ||||
763 | aFont.SetPitch( PITCH_FIXED ); | ||||
764 | aFont.SetFamily( FAMILY_MODERN ); | ||||
765 | break; | ||||
766 | |||||
767 | case DefaultFontType::SYMBOL: | ||||
768 | aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL(((rtl_TextEncoding) 10)) ); | ||||
769 | break; | ||||
770 | |||||
771 | case DefaultFontType::CJK_TEXT: | ||||
772 | case DefaultFontType::CJK_PRESENTATION: | ||||
773 | case DefaultFontType::CJK_SPREADSHEET: | ||||
774 | case DefaultFontType::CJK_HEADING: | ||||
775 | case DefaultFontType::CJK_DISPLAY: | ||||
776 | aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... | ||||
777 | break; | ||||
778 | |||||
779 | case DefaultFontType::CTL_TEXT: | ||||
780 | case DefaultFontType::CTL_PRESENTATION: | ||||
781 | case DefaultFontType::CTL_SPREADSHEET: | ||||
782 | case DefaultFontType::CTL_HEADING: | ||||
783 | case DefaultFontType::CTL_DISPLAY: | ||||
784 | aFont.SetFamily( FAMILY_SYSTEM ); // don't care, but don't use font subst config later... | ||||
785 | break; | ||||
786 | } | ||||
787 | |||||
788 | if ( !aSearch.isEmpty() ) | ||||
789 | { | ||||
790 | aFont.SetFontHeight( 12 ); // corresponds to nDefaultHeight | ||||
791 | aFont.SetWeight( WEIGHT_NORMAL ); | ||||
792 | aFont.SetLanguage( eLang ); | ||||
793 | |||||
794 | if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW(((rtl_TextEncoding) 0)) ) | ||||
795 | aFont.SetCharSet( osl_getThreadTextEncoding() ); | ||||
796 | |||||
797 | // Should we only return available fonts on the given device | ||||
798 | if ( pOutDev ) | ||||
799 | { | ||||
800 | pOutDev->ImplInitFontList(); | ||||
801 | |||||
802 | // Search Font in the FontList | ||||
803 | OUString aName; | ||||
804 | sal_Int32 nIndex = 0; | ||||
805 | do | ||||
806 | { | ||||
807 | PhysicalFontFamily* pFontFamily = pOutDev->mxFontCollection->FindFontFamily( GetNextFontToken( aSearch, nIndex ) ); | ||||
808 | if( pFontFamily ) | ||||
809 | { | ||||
810 | AddTokenFontName( aName, pFontFamily->GetFamilyName() ); | ||||
811 | if( nFlags & GetDefaultFontFlags::OnlyOne ) | ||||
812 | break; | ||||
813 | } | ||||
814 | } | ||||
815 | while ( nIndex != -1 ); | ||||
816 | aFont.SetFamilyName( aName ); | ||||
817 | } | ||||
818 | |||||
819 | // No Name, then set all names | ||||
820 | if ( aFont.GetFamilyName().isEmpty() ) | ||||
821 | { | ||||
822 | if ( nFlags & GetDefaultFontFlags::OnlyOne ) | ||||
823 | { | ||||
824 | if( !pOutDev ) | ||||
825 | { | ||||
826 | SAL_WARN_IF(!utl::ConfigManager::IsFuzzing(), "vcl.gdi", "No default window has been set for the application - we really shouldn't be able to get here")do { if (true && (!utl::ConfigManager::IsFuzzing())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl.gdi" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "No default window has been set for the application - we really shouldn't be able to get here" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "826" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "No default window has been set for the application - we really shouldn't be able to get here" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "No default window has been set for the application - we really shouldn't be able to get here" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "826" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "No default window has been set for the application - we really shouldn't be able to get here" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "826" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "No default window has been set for the application - we really shouldn't be able to get here" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "No default window has been set for the application - we really shouldn't be able to get here" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "826" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
827 | aFont.SetFamilyName( aSearch.getToken( 0, ';' ) ); | ||||
828 | } | ||||
829 | else | ||||
830 | { | ||||
831 | pOutDev->ImplInitFontList(); | ||||
832 | |||||
833 | aFont.SetFamilyName( aSearch ); | ||||
834 | |||||
835 | // convert to pixel height | ||||
836 | Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetFontSize() ); | ||||
837 | if ( !aSize.Height() ) | ||||
838 | { | ||||
839 | // use default pixel height only when logical height is zero | ||||
840 | if ( aFont.GetFontHeight() ) | ||||
841 | aSize.setHeight( 1 ); | ||||
842 | else | ||||
843 | aSize.setHeight( (12*pOutDev->mnDPIY)/72 ); | ||||
844 | } | ||||
845 | |||||
846 | // use default width only when logical width is zero | ||||
847 | if( (0 == aSize.Width()) && (0 != aFont.GetFontSize().Width()) ) | ||||
848 | aSize.setWidth( 1 ); | ||||
849 | |||||
850 | // get the name of the first available font | ||||
851 | float fExactHeight = static_cast<float>(aSize.Height()); | ||||
852 | rtl::Reference<LogicalFontInstance> pFontInstance = pOutDev->mxFontCache->GetFontInstance( pOutDev->mxFontCollection.get(), aFont, aSize, fExactHeight ); | ||||
853 | if (pFontInstance) | ||||
854 | { | ||||
855 | assert(pFontInstance->GetFontFace())(static_cast <bool> (pFontInstance->GetFontFace()) ? void (0) : __assert_fail ("pFontInstance->GetFontFace()", "/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" , 855, __extension__ __PRETTY_FUNCTION__)); | ||||
856 | aFont.SetFamilyName(pFontInstance->GetFontFace()->GetFamilyName()); | ||||
857 | } | ||||
858 | } | ||||
859 | } | ||||
860 | else | ||||
861 | aFont.SetFamilyName( aSearch ); | ||||
862 | } | ||||
863 | } | ||||
864 | |||||
865 | #if OSL_DEBUG_LEVEL1 > 2 | ||||
866 | const char* s = "SANS_UNKNOWN"; | ||||
867 | switch ( nType ) | ||||
868 | { | ||||
869 | case DefaultFontType::SANS_UNICODE: s = "SANS_UNICODE"; break; | ||||
870 | case DefaultFontType::UI_SANS: s = "UI_SANS"; break; | ||||
871 | |||||
872 | case DefaultFontType::SANS: s = "SANS"; break; | ||||
873 | case DefaultFontType::LATIN_HEADING: s = "LATIN_HEADING"; break; | ||||
874 | case DefaultFontType::LATIN_SPREADSHEET: s = "LATIN_SPREADSHEET"; break; | ||||
875 | case DefaultFontType::LATIN_DISPLAY: s = "LATIN_DISPLAY"; break; | ||||
876 | |||||
877 | case DefaultFontType::SERIF: s = "SERIF"; break; | ||||
878 | case DefaultFontType::LATIN_TEXT: s = "LATIN_TEXT"; break; | ||||
879 | case DefaultFontType::LATIN_PRESENTATION: s = "LATIN_PRESENTATION"; break; | ||||
880 | |||||
881 | case DefaultFontType::FIXED: s = "FIXED"; break; | ||||
882 | case DefaultFontType::LATIN_FIXED: s = "LATIN_FIXED"; break; | ||||
883 | case DefaultFontType::UI_FIXED: s = "UI_FIXED"; break; | ||||
884 | |||||
885 | case DefaultFontType::SYMBOL: s = "SYMBOL"; break; | ||||
886 | |||||
887 | case DefaultFontType::CJK_TEXT: s = "CJK_TEXT"; break; | ||||
888 | case DefaultFontType::CJK_PRESENTATION: s = "CJK_PRESENTATION"; break; | ||||
889 | case DefaultFontType::CJK_SPREADSHEET: s = "CJK_SPREADSHEET"; break; | ||||
890 | case DefaultFontType::CJK_HEADING: s = "CJK_HEADING"; break; | ||||
891 | case DefaultFontType::CJK_DISPLAY: s = "CJK_DISPLAY"; break; | ||||
892 | |||||
893 | case DefaultFontType::CTL_TEXT: s = "CTL_TEXT"; break; | ||||
894 | case DefaultFontType::CTL_PRESENTATION: s = "CTL_PRESENTATION"; break; | ||||
895 | case DefaultFontType::CTL_SPREADSHEET: s = "CTL_SPREADSHEET"; break; | ||||
896 | case DefaultFontType::CTL_HEADING: s = "CTL_HEADING"; break; | ||||
897 | case DefaultFontType::CTL_DISPLAY: s = "CTL_DISPLAY"; break; | ||||
898 | } | ||||
899 | SAL_INFO("vcl.gdi",do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||
900 | "OutputDevice::GetDefaultFont() Type=" << sdo { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||
901 | << " lang=" << eLangdo { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||
902 | << " flags=" << static_cast<int>(nFlags)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | ||||
903 | << " family=\"" << aFont.GetFamilyName() << "\"")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\"") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int>(nFlags) << " family=\"" << aFont.GetFamilyName() << "\""), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::GetDefaultFont() Type=" << s << " lang=" << eLang << " flags=" << static_cast<int >(nFlags) << " family=\"" << aFont.GetFamilyName () << "\""; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_INFO ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "903" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
904 | #endif | ||||
905 | |||||
906 | return aFont; | ||||
907 | } | ||||
908 | |||||
909 | void OutputDevice::ImplInitFontList() const | ||||
910 | { | ||||
911 | if( mxFontCollection->Count() ) | ||||
912 | return; | ||||
913 | |||||
914 | if( !(mpGraphics || AcquireGraphics()) ) | ||||
915 | return; | ||||
916 | |||||
917 | SAL_INFO( "vcl.gdi", "OutputDevice::ImplInitFontList()" )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::ImplInitFontList()" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "917" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::ImplInitFontList()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::ImplInitFontList()"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "917" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::ImplInitFontList()") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "917" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::ImplInitFontList()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::ImplInitFontList()"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_INFO), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "917" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
918 | mpGraphics->GetDevFontList(mxFontCollection.get()); | ||||
919 | |||||
920 | // There is absolutely no way there should be no fonts available on the device | ||||
921 | if( !mxFontCollection->Count() ) | ||||
922 | { | ||||
923 | OUString aError( "Application error: no fonts and no vcl resource found on your system" ); | ||||
924 | OUString aResStr(VclResId(SV_ACCESSERROR_NO_FONTSreinterpret_cast<char const *>("SV_ACCESSERROR_NO_FONTS" "\004" u8"No fonts could be found on the system."))); | ||||
925 | if (!aResStr.isEmpty()) | ||||
926 | aError = aResStr; | ||||
927 | Application::Abort(aError); | ||||
928 | } | ||||
929 | } | ||||
930 | |||||
931 | bool OutputDevice::InitFont() const | ||||
932 | { | ||||
933 | DBG_TESTSOLARMUTEX()do { DbgTestSolarMutex(); } while(false); | ||||
934 | |||||
935 | if (!ImplNewFont()) | ||||
936 | return false; | ||||
937 | if (!mpFontInstance) | ||||
938 | return false; | ||||
939 | if (!mpGraphics) | ||||
940 | { | ||||
941 | if (!AcquireGraphics()) | ||||
942 | return false; | ||||
943 | } | ||||
944 | else if (!mbInitFont) | ||||
945 | return true; | ||||
946 | |||||
947 | mpGraphics->SetFont(mpFontInstance.get(), 0); | ||||
948 | mbInitFont = false; | ||||
949 | return true; | ||||
950 | } | ||||
951 | |||||
952 | const LogicalFontInstance* OutputDevice::GetFontInstance() const | ||||
953 | { | ||||
954 | if (!InitFont()) | ||||
955 | return nullptr; | ||||
956 | return mpFontInstance.get(); | ||||
957 | } | ||||
958 | |||||
959 | bool OutputDevice::ImplNewFont() const | ||||
960 | { | ||||
961 | DBG_TESTSOLARMUTEX()do { DbgTestSolarMutex(); } while(false); | ||||
962 | |||||
963 | // get correct font list on the PDF writer if necessary | ||||
964 | if (GetOutDevType() == OUTDEV_PDF) | ||||
965 | { | ||||
966 | const ImplSVData* pSVData = ImplGetSVData(); | ||||
967 | if( mxFontCollection == pSVData->maGDIData.mxScreenFontList | ||||
968 | || mxFontCache == pSVData->maGDIData.mxScreenFontCache ) | ||||
969 | const_cast<OutputDevice&>(*this).ImplUpdateFontData(); | ||||
970 | } | ||||
971 | |||||
972 | if ( !mbNewFont ) | ||||
973 | return true; | ||||
974 | |||||
975 | // we need a graphics | ||||
976 | if ( !mpGraphics && !AcquireGraphics() ) | ||||
977 | { | ||||
978 | SAL_WARN("vcl.gdi", "OutputDevice::ImplNewFont(): no Graphics, no Font")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::ImplNewFont(): no Graphics, no Font" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "978" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::ImplNewFont(): no Graphics, no Font" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::ImplNewFont(): no Graphics, no Font" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "978" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::ImplNewFont(): no Graphics, no Font" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "978" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "OutputDevice::ImplNewFont(): no Graphics, no Font" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::ImplNewFont(): no Graphics, no Font" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "978" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
979 | return false; | ||||
980 | } | ||||
981 | |||||
982 | ImplInitFontList(); | ||||
983 | |||||
984 | // convert to pixel height | ||||
985 | // TODO: replace integer based aSize completely with subpixel accurate type | ||||
986 | float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetFontHeight()) ); | ||||
987 | Size aSize = ImplLogicToDevicePixel( maFont.GetFontSize() ); | ||||
988 | if ( !aSize.Height() ) | ||||
989 | { | ||||
990 | // use default pixel height only when logical height is zero | ||||
991 | if ( maFont.GetFontSize().Height() ) | ||||
992 | aSize.setHeight( 1 ); | ||||
993 | else | ||||
994 | aSize.setHeight( (12*mnDPIY)/72 ); | ||||
995 | fExactHeight = static_cast<float>(aSize.Height()); | ||||
996 | } | ||||
997 | |||||
998 | // select the default width only when logical width is zero | ||||
999 | if( (0 == aSize.Width()) && (0 != maFont.GetFontSize().Width()) ) | ||||
1000 | aSize.setWidth( 1 ); | ||||
1001 | |||||
1002 | // decide if antialiasing is appropriate | ||||
1003 | bool bNonAntialiased(GetAntialiasing() & AntialiasingFlags::DisableText); | ||||
1004 | if (!utl::ConfigManager::IsFuzzing()) | ||||
1005 | { | ||||
1006 | const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); | ||||
1007 | bNonAntialiased |= bool(rStyleSettings.GetDisplayOptions() & DisplayOptions::AADisable); | ||||
1008 | bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > maFont.GetFontSize().Height()); | ||||
1009 | } | ||||
1010 | |||||
1011 | // get font entry | ||||
1012 | rtl::Reference<LogicalFontInstance> pOldFontInstance = mpFontInstance; | ||||
1013 | mpFontInstance = mxFontCache->GetFontInstance(mxFontCollection.get(), maFont, aSize, fExactHeight, bNonAntialiased); | ||||
1014 | const bool bNewFontInstance = pOldFontInstance.get() != mpFontInstance.get(); | ||||
1015 | pOldFontInstance.clear(); | ||||
1016 | |||||
1017 | LogicalFontInstance* pFontInstance = mpFontInstance.get(); | ||||
1018 | |||||
1019 | if (!pFontInstance) | ||||
1020 | { | ||||
1021 | SAL_WARN("vcl.gdi", "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1021" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1021" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1021" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "OutputDevice::ImplNewFont(): no LogicalFontInstance, no Font" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1021" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
1022 | return false; | ||||
1023 | } | ||||
1024 | |||||
1025 | // mark when lower layers need to get involved | ||||
1026 | mbNewFont = false; | ||||
1027 | if( bNewFontInstance ) | ||||
1028 | mbInitFont = true; | ||||
1029 | |||||
1030 | // select font when it has not been initialized yet | ||||
1031 | if (!pFontInstance->mbInit && InitFont()) | ||||
1032 | { | ||||
1033 | // get metric data from device layers | ||||
1034 | pFontInstance->mbInit = true; | ||||
1035 | |||||
1036 | pFontInstance->mxFontMetric->SetOrientation( sal::static_int_cast<short>(mpFontInstance->GetFontSelectPattern().mnOrientation) ); | ||||
1037 | mpGraphics->GetFontMetric( pFontInstance->mxFontMetric, 0 ); | ||||
1038 | |||||
1039 | pFontInstance->mxFontMetric->ImplInitTextLineSize( this ); | ||||
1040 | pFontInstance->mxFontMetric->ImplInitAboveTextLineSize(); | ||||
1041 | pFontInstance->mxFontMetric->ImplInitFlags( this ); | ||||
1042 | |||||
1043 | pFontInstance->mnLineHeight = pFontInstance->mxFontMetric->GetAscent() + pFontInstance->mxFontMetric->GetDescent(); | ||||
1044 | |||||
1045 | SetFontOrientation( pFontInstance ); | ||||
1046 | } | ||||
1047 | |||||
1048 | // calculate EmphasisArea | ||||
1049 | mnEmphasisAscent = 0; | ||||
1050 | mnEmphasisDescent = 0; | ||||
1051 | if ( maFont.GetEmphasisMark() & FontEmphasisMark::Style ) | ||||
1052 | { | ||||
1053 | FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont ); | ||||
1054 | long nEmphasisHeight = (pFontInstance->mnLineHeight*250)/1000; | ||||
1055 | if ( nEmphasisHeight < 1 ) | ||||
1056 | nEmphasisHeight = 1; | ||||
1057 | if ( nEmphasisMark & FontEmphasisMark::PosBelow ) | ||||
1058 | mnEmphasisDescent = nEmphasisHeight; | ||||
1059 | else | ||||
1060 | mnEmphasisAscent = nEmphasisHeight; | ||||
1061 | } | ||||
1062 | |||||
1063 | // calculate text offset depending on TextAlignment | ||||
1064 | TextAlign eAlign = maFont.GetAlignment(); | ||||
1065 | if ( eAlign == ALIGN_BASELINE ) | ||||
1066 | { | ||||
1067 | mnTextOffX = 0; | ||||
1068 | mnTextOffY = 0; | ||||
1069 | } | ||||
1070 | else if ( eAlign == ALIGN_TOP ) | ||||
1071 | { | ||||
1072 | mnTextOffX = 0; | ||||
1073 | mnTextOffY = +pFontInstance->mxFontMetric->GetAscent() + mnEmphasisAscent; | ||||
1074 | if ( pFontInstance->mnOrientation ) | ||||
1075 | { | ||||
1076 | Point aOriginPt(0, 0); | ||||
1077 | aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontInstance->mnOrientation ); | ||||
1078 | } | ||||
1079 | } | ||||
1080 | else // eAlign == ALIGN_BOTTOM | ||||
1081 | { | ||||
1082 | mnTextOffX = 0; | ||||
1083 | mnTextOffY = -pFontInstance->mxFontMetric->GetDescent() + mnEmphasisDescent; | ||||
1084 | if ( pFontInstance->mnOrientation ) | ||||
1085 | { | ||||
1086 | Point aOriginPt(0, 0); | ||||
1087 | aOriginPt.RotateAround( mnTextOffX, mnTextOffY, pFontInstance->mnOrientation ); | ||||
1088 | } | ||||
1089 | } | ||||
1090 | |||||
1091 | mbTextLines = ((maFont.GetUnderline() != LINESTYLE_NONE) && (maFont.GetUnderline() != LINESTYLE_DONTKNOW)) || | ||||
1092 | ((maFont.GetOverline() != LINESTYLE_NONE) && (maFont.GetOverline() != LINESTYLE_DONTKNOW)) || | ||||
1093 | ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW)); | ||||
1094 | mbTextSpecial = maFont.IsShadow() || maFont.IsOutline() || | ||||
1095 | (maFont.GetRelief() != FontRelief::NONE); | ||||
1096 | |||||
1097 | |||||
1098 | bool bRet = true; | ||||
1099 | |||||
1100 | // #95414# fix for OLE objects which use scale factors very creatively | ||||
1101 | if( mbMap && !aSize.Width() ) | ||||
1102 | { | ||||
1103 | int nOrigWidth = pFontInstance->mxFontMetric->GetWidth(); | ||||
1104 | float fStretch = static_cast<float>(maMapRes.mnMapScNumX) * maMapRes.mnMapScDenomY; | ||||
1105 | fStretch /= static_cast<float>(maMapRes.mnMapScNumY) * maMapRes.mnMapScDenomX; | ||||
1106 | int nNewWidth = static_cast<int>(nOrigWidth * fStretch + 0.5); | ||||
1107 | if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) ) | ||||
1108 | { | ||||
1109 | Size aOrigSize = maFont.GetFontSize(); | ||||
1110 | const_cast<vcl::Font&>(maFont).SetFontSize( Size( nNewWidth, aSize.Height() ) ); | ||||
1111 | mbMap = false; | ||||
1112 | mbNewFont = true; | ||||
1113 | bRet = ImplNewFont(); // recurse once using stretched width | ||||
1114 | mbMap = true; | ||||
1115 | const_cast<vcl::Font&>(maFont).SetFontSize( aOrigSize ); | ||||
1116 | } | ||||
1117 | } | ||||
1118 | |||||
1119 | return bRet; | ||||
1120 | } | ||||
1121 | |||||
1122 | void OutputDevice::SetFontOrientation( LogicalFontInstance* const pFontInstance ) const | ||||
1123 | { | ||||
1124 | if( pFontInstance->GetFontSelectPattern().mnOrientation && !pFontInstance->mxFontMetric->GetOrientation() ) | ||||
1125 | { | ||||
1126 | pFontInstance->mnOwnOrientation = sal::static_int_cast<short>(pFontInstance->GetFontSelectPattern().mnOrientation); | ||||
1127 | pFontInstance->mnOrientation = pFontInstance->mnOwnOrientation; | ||||
1128 | } | ||||
1129 | else | ||||
1130 | { | ||||
1131 | pFontInstance->mnOrientation = pFontInstance->mxFontMetric->GetOrientation(); | ||||
1132 | } | ||||
1133 | } | ||||
1134 | |||||
1135 | void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY, | ||||
1136 | const tools::PolyPolygon& rPolyPoly, bool bPolyLine, | ||||
1137 | const tools::Rectangle& rRect1, const tools::Rectangle& rRect2 ) | ||||
1138 | { | ||||
1139 | if( IsRTLEnabled() ) | ||||
1140 | nX = nBaseX - (nX - nBaseX - 1); | ||||
1141 | |||||
1142 | nX -= mnOutOffX; | ||||
1143 | nY -= mnOutOffY; | ||||
1144 | |||||
1145 | if ( rPolyPoly.Count() ) | ||||
1146 | { | ||||
1147 | if ( bPolyLine ) | ||||
1148 | { | ||||
1149 | tools::Polygon aPoly = rPolyPoly.GetObject( 0 ); | ||||
1150 | aPoly.Move( nX, nY ); | ||||
1151 | DrawPolyLine( aPoly ); | ||||
1152 | } | ||||
1153 | else | ||||
1154 | { | ||||
1155 | tools::PolyPolygon aPolyPoly = rPolyPoly; | ||||
1156 | aPolyPoly.Move( nX, nY ); | ||||
1157 | DrawPolyPolygon( aPolyPoly ); | ||||
1158 | } | ||||
1159 | } | ||||
1160 | |||||
1161 | if ( !rRect1.IsEmpty() ) | ||||
1162 | { | ||||
1163 | tools::Rectangle aRect( Point( nX+rRect1.Left(), | ||||
1164 | nY+rRect1.Top() ), rRect1.GetSize() ); | ||||
1165 | DrawRect( aRect ); | ||||
1166 | } | ||||
1167 | |||||
1168 | if ( !rRect2.IsEmpty() ) | ||||
1169 | { | ||||
1170 | tools::Rectangle aRect( Point( nX+rRect2.Left(), | ||||
1171 | nY+rRect2.Top() ), rRect2.GetSize() ); | ||||
1172 | |||||
1173 | DrawRect( aRect ); | ||||
1174 | } | ||||
1175 | } | ||||
1176 | |||||
1177 | void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) | ||||
1178 | { | ||||
1179 | Color aOldLineColor = GetLineColor(); | ||||
1180 | Color aOldFillColor = GetFillColor(); | ||||
1181 | bool bOldMap = mbMap; | ||||
1182 | GDIMetaFile* pOldMetaFile = mpMetaFile; | ||||
1183 | mpMetaFile = nullptr; | ||||
1184 | EnableMapMode( false ); | ||||
1185 | |||||
1186 | FontEmphasisMark nEmphasisMark = ImplGetEmphasisMarkStyle( maFont ); | ||||
1187 | tools::PolyPolygon aPolyPoly; | ||||
1188 | tools::Rectangle aRect1; | ||||
1189 | tools::Rectangle aRect2; | ||||
1190 | long nEmphasisYOff; | ||||
1191 | long nEmphasisWidth; | ||||
1192 | long nEmphasisHeight; | ||||
1193 | bool bPolyLine; | ||||
1194 | |||||
1195 | if ( nEmphasisMark & FontEmphasisMark::PosBelow ) | ||||
1196 | nEmphasisHeight = mnEmphasisDescent; | ||||
1197 | else | ||||
1198 | nEmphasisHeight = mnEmphasisAscent; | ||||
1199 | |||||
1200 | ImplGetEmphasisMark( aPolyPoly, bPolyLine, | ||||
1201 | aRect1, aRect2, | ||||
1202 | nEmphasisYOff, nEmphasisWidth, | ||||
1203 | nEmphasisMark, | ||||
1204 | nEmphasisHeight ); | ||||
1205 | |||||
1206 | if ( bPolyLine ) | ||||
1207 | { | ||||
1208 | SetLineColor( GetTextColor() ); | ||||
1209 | SetFillColor(); | ||||
1210 | } | ||||
1211 | else | ||||
1212 | { | ||||
1213 | SetLineColor(); | ||||
1214 | SetFillColor( GetTextColor() ); | ||||
1215 | } | ||||
1216 | |||||
1217 | Point aOffset(0,0); | ||||
1218 | |||||
1219 | if ( nEmphasisMark & FontEmphasisMark::PosBelow ) | ||||
1220 | aOffset.AdjustY(mpFontInstance->mxFontMetric->GetDescent() + nEmphasisYOff ); | ||||
1221 | else | ||||
1222 | aOffset.AdjustY( -(mpFontInstance->mxFontMetric->GetAscent() + nEmphasisYOff) ); | ||||
1223 | |||||
1224 | long nEmphasisWidth2 = nEmphasisWidth / 2; | ||||
1225 | long nEmphasisHeight2 = nEmphasisHeight / 2; | ||||
1226 | aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 ); | ||||
1227 | |||||
1228 | Point aOutPoint; | ||||
1229 | tools::Rectangle aRectangle; | ||||
1230 | const GlyphItem* pGlyph; | ||||
1231 | int nStart = 0; | ||||
1232 | while (rSalLayout.GetNextGlyph(&pGlyph, aOutPoint, nStart)) | ||||
1233 | { | ||||
1234 | if (!pGlyph->GetGlyphBoundRect(aRectangle)) | ||||
1235 | continue; | ||||
1236 | |||||
1237 | if (!pGlyph->IsSpacing()) | ||||
1238 | { | ||||
1239 | Point aAdjPoint = aOffset; | ||||
1240 | aAdjPoint.AdjustX(aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2 ); | ||||
1241 | if ( mpFontInstance->mnOrientation ) | ||||
1242 | { | ||||
1243 | Point aOriginPt(0, 0); | ||||
1244 | aOriginPt.RotateAround( aAdjPoint, mpFontInstance->mnOrientation ); | ||||
1245 | } | ||||
1246 | aOutPoint += aAdjPoint; | ||||
1247 | aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 ); | ||||
1248 | ImplDrawEmphasisMark( rSalLayout.DrawBase().X(), | ||||
1249 | aOutPoint.X(), aOutPoint.Y(), | ||||
1250 | aPolyPoly, bPolyLine, aRect1, aRect2 ); | ||||
1251 | } | ||||
1252 | } | ||||
1253 | |||||
1254 | SetLineColor( aOldLineColor ); | ||||
1255 | SetFillColor( aOldFillColor ); | ||||
1256 | EnableMapMode( bOldMap ); | ||||
1257 | mpMetaFile = pOldMetaFile; | ||||
1258 | } | ||||
1259 | |||||
1260 | std::unique_ptr<SalLayout> OutputDevice::getFallbackLayout( | ||||
1261 | LogicalFontInstance* pLogicalFont, int nFallbackLevel, | ||||
1262 | ImplLayoutArgs& rLayoutArgs) const | ||||
1263 | { | ||||
1264 | // we need a graphics | ||||
1265 | if (!mpGraphics && !AcquireGraphics()) | ||||
1266 | return nullptr; | ||||
1267 | |||||
1268 | assert(mpGraphics != nullptr)(static_cast <bool> (mpGraphics != nullptr) ? void (0) : __assert_fail ("mpGraphics != nullptr", "/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" , 1268, __extension__ __PRETTY_FUNCTION__)); | ||||
1269 | mpGraphics->SetFont( pLogicalFont, nFallbackLevel ); | ||||
1270 | |||||
1271 | rLayoutArgs.ResetPos(); | ||||
1272 | std::unique_ptr<GenericSalLayout> pFallback = mpGraphics->GetTextLayout(nFallbackLevel); | ||||
1273 | |||||
1274 | if (!pFallback) | ||||
1275 | return nullptr; | ||||
1276 | |||||
1277 | if (!pFallback->LayoutText(rLayoutArgs, nullptr)) | ||||
1278 | { | ||||
1279 | // there is no need for a font that couldn't resolve anything | ||||
1280 | return nullptr; | ||||
1281 | } | ||||
1282 | |||||
1283 | return pFallback; | ||||
1284 | } | ||||
1285 | |||||
1286 | std::unique_ptr<SalLayout> OutputDevice::ImplGlyphFallbackLayout( std::unique_ptr<SalLayout> pSalLayout, ImplLayoutArgs& rLayoutArgs ) const | ||||
1287 | { | ||||
1288 | // This function relies on a valid mpFontInstance, if it doesn't exist bail out | ||||
1289 | // - we'd have crashed later on anyway. At least here we can catch the error in debug | ||||
1290 | // mode. | ||||
1291 | if ( !mpFontInstance ) | ||||
1292 | { | ||||
1293 | SAL_WARN ("vcl.gdi", "No font entry set in OutputDevice")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "No font entry set in OutputDevice" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1293" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "No font entry set in OutputDevice") , 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "No font entry set in OutputDevice"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1293" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "No font entry set in OutputDevice") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1293" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "No font entry set in OutputDevice") , 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "No font entry set in OutputDevice"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1293" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
1294 | assert(mpFontInstance)(static_cast <bool> (mpFontInstance) ? void (0) : __assert_fail ("mpFontInstance", "/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" , 1294, __extension__ __PRETTY_FUNCTION__)); | ||||
1295 | return nullptr; | ||||
1296 | } | ||||
1297 | |||||
1298 | // prepare multi level glyph fallback | ||||
1299 | std::unique_ptr<MultiSalLayout> pMultiSalLayout; | ||||
1300 | ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns; | ||||
1301 | rLayoutArgs.PrepareFallback(); | ||||
1302 | rLayoutArgs.mnFlags |= SalLayoutFlags::ForFallback; | ||||
1303 | |||||
1304 | // get list of code units that need glyph fallback | ||||
1305 | int nCharPos = -1; | ||||
1306 | bool bRTL = false; | ||||
1307 | OUStringBuffer aMissingCodeBuf(512); | ||||
1308 | while (rLayoutArgs.GetNextPos( &nCharPos, &bRTL)) | ||||
1309 | aMissingCodeBuf.append(rLayoutArgs.mrStr[nCharPos]); | ||||
1310 | rLayoutArgs.ResetPos(); | ||||
1311 | OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear(); | ||||
1312 | |||||
1313 | FontSelectPattern aFontSelData(mpFontInstance->GetFontSelectPattern()); | ||||
1314 | |||||
1315 | // try if fallback fonts support the missing code units | ||||
1316 | for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK16; ++nFallbackLevel ) | ||||
1317 | { | ||||
1318 | // find a font family suited for glyph fallback | ||||
1319 | // GetGlyphFallbackFont() needs a valid FontInstance | ||||
1320 | // if the system-specific glyph fallback is active | ||||
1321 | rtl::Reference<LogicalFontInstance> pFallbackFont = mxFontCache->GetGlyphFallbackFont( mxFontCollection.get(), | ||||
1322 | aFontSelData, mpFontInstance.get(), nFallbackLevel, aMissingCodes ); | ||||
1323 | if( !pFallbackFont ) | ||||
1324 | break; | ||||
1325 | |||||
1326 | if( nFallbackLevel < MAX_FALLBACK16-1) | ||||
1327 | { | ||||
1328 | // ignore fallback font if it is the same as the original font | ||||
1329 | // unless we are looking for a substitution for 0x202F, in which | ||||
1330 | // case we'll just use a normal space | ||||
1331 | if( mpFontInstance->GetFontFace() == pFallbackFont->GetFontFace() && | ||||
1332 | aMissingCodes.indexOf(0x202F) == -1 ) | ||||
1333 | { | ||||
1334 | continue; | ||||
1335 | } | ||||
1336 | } | ||||
1337 | |||||
1338 | // create and add glyph fallback layout to multilayout | ||||
1339 | std::unique_ptr<SalLayout> pFallback = getFallbackLayout(pFallbackFont.get(), | ||||
1340 | nFallbackLevel, rLayoutArgs); | ||||
1341 | if (pFallback) | ||||
1342 | { | ||||
1343 | if( !pMultiSalLayout ) | ||||
1344 | pMultiSalLayout.reset( new MultiSalLayout( std::move(pSalLayout) ) ); | ||||
1345 | pMultiSalLayout->AddFallback(std::move(pFallback), rLayoutArgs.maRuns); | ||||
1346 | if (nFallbackLevel == MAX_FALLBACK16-1) | ||||
1347 | pMultiSalLayout->SetIncomplete(true); | ||||
1348 | } | ||||
1349 | |||||
1350 | // break when this fallback was sufficient | ||||
1351 | if( !rLayoutArgs.PrepareFallback() ) | ||||
1352 | break; | ||||
1353 | } | ||||
1354 | |||||
1355 | if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs, nullptr ) ) | ||||
1356 | pSalLayout = std::move(pMultiSalLayout); | ||||
1357 | |||||
1358 | // restore orig font settings | ||||
1359 | pSalLayout->InitFont(); | ||||
1360 | rLayoutArgs.maRuns = aLayoutRuns; | ||||
1361 | |||||
1362 | return pSalLayout; | ||||
1363 | } | ||||
1364 | |||||
1365 | long OutputDevice::GetMinKashida() const | ||||
1366 | { | ||||
1367 | if (!ImplNewFont()) | ||||
1368 | return 0; | ||||
1369 | |||||
1370 | return ImplDevicePixelToLogicWidth( mpFontInstance->mxFontMetric->GetMinKashida() ); | ||||
1371 | } | ||||
1372 | |||||
1373 | sal_Int32 OutputDevice::ValidateKashidas ( const OUString& rTxt, | ||||
1374 | sal_Int32 nIdx, sal_Int32 nLen, | ||||
1375 | sal_Int32 nKashCount, | ||||
1376 | const sal_Int32* pKashidaPos, | ||||
1377 | sal_Int32* pKashidaPosDropped ) const | ||||
1378 | { | ||||
1379 | // do layout | ||||
1380 | std::unique_ptr<SalLayout> pSalLayout = ImplLayout( rTxt, nIdx, nLen ); | ||||
1381 | if( !pSalLayout ) | ||||
1382 | return 0; | ||||
1383 | sal_Int32 nDropped = 0; | ||||
1384 | for( int i = 0; i < nKashCount; ++i ) | ||||
1385 | { | ||||
1386 | if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] )) | ||||
1387 | { | ||||
1388 | pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ]; | ||||
1389 | ++nDropped; | ||||
1390 | } | ||||
1391 | } | ||||
1392 | return nDropped; | ||||
1393 | } | ||||
1394 | |||||
1395 | bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const OUString& rStr, | ||||
1396 | int nIndex, int nLen, MetricVector& rVector ) | ||||
1397 | { | ||||
1398 | rVector.clear(); | ||||
1399 | |||||
1400 | if( nIndex >= rStr.getLength() ) | ||||
1401 | return false; | ||||
1402 | |||||
1403 | if( nLen < 0 || nIndex + nLen >= rStr.getLength() ) | ||||
1404 | { | ||||
1405 | nLen = rStr.getLength() - nIndex; | ||||
1406 | } | ||||
1407 | |||||
1408 | tools::Rectangle aRect; | ||||
1409 | for( int i = 0; i < nLen; i++ ) | ||||
1410 | { | ||||
1411 | if( !GetTextBoundRect( aRect, rStr, nIndex, nIndex + i, 1 ) ) | ||||
1412 | break; | ||||
1413 | aRect.Move( rOrigin.X(), rOrigin.Y() ); | ||||
1414 | rVector.push_back( aRect ); | ||||
1415 | } | ||||
1416 | |||||
1417 | return (nLen == static_cast<int>(rVector.size())); | ||||
1418 | } | ||||
1419 | |||||
1420 | sal_Int32 OutputDevice::HasGlyphs( const vcl::Font& rTempFont, const OUString& rStr, | ||||
1421 | sal_Int32 nIndex, sal_Int32 nLen ) const | ||||
1422 | { | ||||
1423 | if( nIndex >= rStr.getLength() ) | ||||
| |||||
1424 | return nIndex; | ||||
1425 | sal_Int32 nEnd; | ||||
1426 | if( nLen == -1 ) | ||||
1427 | nEnd = rStr.getLength(); | ||||
1428 | else | ||||
1429 | nEnd = std::min( rStr.getLength(), nIndex + nLen ); | ||||
1430 | |||||
1431 | SAL_WARN_IF( nIndex >= nEnd, "vcl.gdi", "StartPos >= EndPos?" )do { if (true && (nIndex >= nEnd)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "StartPos >= EndPos?" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi" ), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1431" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "StartPos >= EndPos?"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "StartPos >= EndPos?"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1431" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "StartPos >= EndPos?") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1431" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "StartPos >= EndPos?"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "StartPos >= EndPos?"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1431" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
1432 | SAL_WARN_IF( nEnd > rStr.getLength(), "vcl.gdi", "String too short" )do { if (true && (nEnd > rStr.getLength())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl.gdi" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "String too short") == 1) { ::sal_detail_log( (:: SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1432" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "String too short"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "String too short"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1432" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "String too short") == 1) { ::sal_detail_log( (:: SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1432" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "String too short"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "String too short"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/outdev/font.cxx" ":" "1432" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | ||||
1433 | |||||
1434 | // to get the map temporarily set font | ||||
1435 | const vcl::Font aOrigFont = GetFont(); | ||||
1436 | const_cast<OutputDevice&>(*this).SetFont( rTempFont ); | ||||
1437 | FontCharMapRef xFontCharMap; | ||||
1438 | bool bRet = GetFontCharMap( xFontCharMap ); | ||||
1439 | const_cast<OutputDevice&>(*this).SetFont( aOrigFont ); | ||||
1440 | |||||
1441 | // if fontmap is unknown assume it doesn't have the glyphs | ||||
1442 | if( !bRet
| ||||
1443 | return nIndex; | ||||
1444 | |||||
1445 | for( sal_Int32 i = nIndex; nIndex < nEnd; ++i, ++nIndex ) | ||||
1446 | if( ! xFontCharMap->HasChar( rStr[i] ) ) | ||||
1447 | return nIndex; | ||||
1448 | |||||
1449 | return -1; | ||||
1450 | } | ||||
1451 | |||||
1452 | void OutputDevice::ReleaseFontCache() { mxFontCache.reset(); } | ||||
1453 | |||||
1454 | void OutputDevice::ReleaseFontCollection() { mxFontCollection.reset(); } | ||||
1455 | |||||
1456 | void OutputDevice::SetFontCollectionFromSVData() | ||||
1457 | { | ||||
1458 | mxFontCollection = ImplGetSVData()->maGDIData.mxScreenFontList->Clone(); | ||||
1459 | } | ||||
1460 | |||||
1461 | void OutputDevice::ResetNewFontCache() | ||||
1462 | { | ||||
1463 | mxFontCache = std::make_shared<ImplFontCache>(); | ||||
1464 | } | ||||
1465 | |||||
1466 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | #ifndef INCLUDED_TOOLS_REF_HXX | |||
20 | #define INCLUDED_TOOLS_REF_HXX | |||
21 | ||||
22 | #include <sal/config.h> | |||
23 | #include <cassert> | |||
24 | #include <tools/toolsdllapi.h> | |||
25 | #include <utility> | |||
26 | ||||
27 | /** | |||
28 | This implements similar functionality to boost::intrusive_ptr | |||
29 | */ | |||
30 | ||||
31 | namespace tools { | |||
32 | ||||
33 | /** T must be a class that extends SvRefBase */ | |||
34 | template<typename T> class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SvRef final { | |||
35 | public: | |||
36 | SvRef(): pObj(nullptr) {} | |||
37 | ||||
38 | SvRef(SvRef&& rObj) noexcept | |||
39 | { | |||
40 | pObj = rObj.pObj; | |||
41 | rObj.pObj = nullptr; | |||
42 | } | |||
43 | ||||
44 | SvRef(SvRef const & rObj): pObj(rObj.pObj) | |||
45 | { | |||
46 | if (pObj != nullptr) pObj->AddNextRef(); | |||
47 | } | |||
48 | ||||
49 | SvRef(T * pObjP): pObj(pObjP) | |||
50 | { | |||
51 | if (pObj != nullptr) pObj->AddFirstRef(); | |||
52 | } | |||
53 | ||||
54 | ~SvRef() | |||
55 | { | |||
56 | if (pObj != nullptr) pObj->ReleaseRef(); | |||
| ||||
57 | } | |||
58 | ||||
59 | void clear() | |||
60 | { | |||
61 | if (pObj != nullptr) { | |||
62 | T * pRefObj = pObj; | |||
63 | pObj = nullptr; | |||
64 | pRefObj->ReleaseRef(); | |||
65 | } | |||
66 | } | |||
67 | ||||
68 | SvRef & operator =(SvRef const & rObj) | |||
69 | { | |||
70 | if (rObj.pObj != nullptr) { | |||
71 | rObj.pObj->AddNextRef(); | |||
72 | } | |||
73 | T * pRefObj = pObj; | |||
74 | pObj = rObj.pObj; | |||
75 | if (pRefObj != nullptr) { | |||
76 | pRefObj->ReleaseRef(); | |||
77 | } | |||
78 | return *this; | |||
79 | } | |||
80 | ||||
81 | SvRef & operator =(SvRef && rObj) | |||
82 | { | |||
83 | if (pObj != nullptr) { | |||
84 | pObj->ReleaseRef(); | |||
85 | } | |||
86 | pObj = rObj.pObj; | |||
87 | rObj.pObj = nullptr; | |||
88 | return *this; | |||
89 | } | |||
90 | ||||
91 | bool is() const { return pObj != nullptr; } | |||
92 | ||||
93 | explicit operator bool() const { return is(); } | |||
94 | ||||
95 | T * get() const { return pObj; } | |||
96 | ||||
97 | T * operator ->() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 97, __extension__ __PRETTY_FUNCTION__)); return pObj; } | |||
98 | ||||
99 | T & operator *() const { assert(pObj != nullptr)(static_cast <bool> (pObj != nullptr) ? void (0) : __assert_fail ("pObj != nullptr", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 99, __extension__ __PRETTY_FUNCTION__)); return *pObj; } | |||
100 | ||||
101 | bool operator ==(const SvRef<T> &rhs) const { return pObj == rhs.pObj; } | |||
102 | bool operator !=(const SvRef<T> &rhs) const { return !(*this == rhs); } | |||
103 | ||||
104 | private: | |||
105 | T * pObj; | |||
106 | }; | |||
107 | ||||
108 | /** | |||
109 | * This implements similar functionality to std::make_shared. | |||
110 | */ | |||
111 | template<typename T, typename... Args> | |||
112 | SvRef<T> make_ref(Args&& ... args) | |||
113 | { | |||
114 | return SvRef<T>(new T(std::forward<Args>(args)...)); | |||
115 | } | |||
116 | ||||
117 | } | |||
118 | ||||
119 | /** Classes that want to be referenced-counted via SvRef<T>, should extend this base class */ | |||
120 | class TOOLS_DLLPUBLIC__attribute__ ((visibility("default"))) SvRefBase | |||
121 | { | |||
122 | // work around a clang 3.5 optimization bug: if the bNoDelete is *first* | |||
123 | // it mis-compiles "if (--nRefCount == 0)" and never deletes any object | |||
124 | unsigned int nRefCount : 31; | |||
125 | // the only reason this is not bool is because MSVC cannot handle mixed type bitfields | |||
126 | unsigned int bNoDelete : 1; | |||
127 | ||||
128 | protected: | |||
129 | virtual ~SvRefBase() COVERITY_NOEXCEPT_FALSE; | |||
130 | ||||
131 | public: | |||
132 | SvRefBase() : nRefCount(0), bNoDelete(1) {} | |||
133 | SvRefBase(const SvRefBase &) : nRefCount(0), bNoDelete(1) {} | |||
134 | ||||
135 | SvRefBase & operator=(const SvRefBase &) { return *this; } | |||
136 | ||||
137 | void RestoreNoDelete() | |||
138 | { bNoDelete = 1; } | |||
139 | ||||
140 | void AddNextRef() | |||
141 | { | |||
142 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 142, __extension__ __PRETTY_FUNCTION__)); | |||
143 | ++nRefCount; | |||
144 | } | |||
145 | ||||
146 | void AddFirstRef() | |||
147 | { | |||
148 | assert( nRefCount < (1 << 30) && "Do not add refs to dead objects" )(static_cast <bool> (nRefCount < (1 << 30) && "Do not add refs to dead objects") ? void (0) : __assert_fail ("nRefCount < (1 << 30) && \"Do not add refs to dead objects\"" , "/home/maarten/src/libreoffice/core/include/tools/ref.hxx", 148, __extension__ __PRETTY_FUNCTION__)); | |||
149 | if( bNoDelete ) | |||
150 | bNoDelete = 0; | |||
151 | ++nRefCount; | |||
152 | } | |||
153 | ||||
154 | void ReleaseRef() | |||
155 | { | |||
156 | assert( nRefCount >= 1)(static_cast <bool> (nRefCount >= 1) ? void (0) : __assert_fail ("nRefCount >= 1", "/home/maarten/src/libreoffice/core/include/tools/ref.hxx" , 156, __extension__ __PRETTY_FUNCTION__)); | |||
157 | if( --nRefCount == 0 && !bNoDelete) | |||
158 | { | |||
159 | // I'm not sure about the original purpose of this line, but right now | |||
160 | // it serves the purpose that anything that attempts to do an AddRef() | |||
161 | // after an object is deleted will trip an assert. | |||
162 | nRefCount = 1 << 30; | |||
163 | delete this; | |||
164 | } | |||
165 | } | |||
166 | ||||
167 | unsigned int GetRefCount() const | |||
168 | { return nRefCount; } | |||
169 | }; | |||
170 | ||||
171 | template<typename T> | |||
172 | class SvCompatWeakBase; | |||
173 | ||||
174 | /** SvCompatWeakHdl acts as an intermediary between SvCompatWeakRef<T> and T. | |||
175 | */ | |||
176 | template<typename T> | |||
177 | class SvCompatWeakHdl final : public SvRefBase | |||
178 | { | |||
179 | friend class SvCompatWeakBase<T>; | |||
180 | T* _pObj; | |||
181 | ||||
182 | SvCompatWeakHdl( T* pObj ) : _pObj( pObj ) {} | |||
183 | ||||
184 | public: | |||
185 | void ResetWeakBase( ) { _pObj = nullptr; } | |||
186 | T* GetObj() { return _pObj; } | |||
187 | }; | |||
188 | ||||
189 | /** We only have one place that extends this, in include/sfx2/frame.hxx, class SfxFrame. | |||
190 | Its function is to notify the SvCompatWeakHdl when an SfxFrame object is deleted. | |||
191 | */ | |||
192 | template<typename T> | |||
193 | class SvCompatWeakBase | |||
194 | { | |||
195 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
196 | ||||
197 | public: | |||
198 | /** Does not use initializer due to compiler warnings, | |||
199 | because the lifetime of the _xHdl object can exceed the lifetime of this class. | |||
200 | */ | |||
201 | SvCompatWeakBase( T* pObj ) { _xHdl = new SvCompatWeakHdl<T>( pObj ); } | |||
202 | ||||
203 | ~SvCompatWeakBase() { _xHdl->ResetWeakBase(); } | |||
204 | ||||
205 | SvCompatWeakHdl<T>* GetHdl() { return _xHdl.get(); } | |||
206 | }; | |||
207 | ||||
208 | /** We only have one weak reference in LO, in include/sfx2/frame.hxx, class SfxFrameWeak. | |||
209 | */ | |||
210 | template<typename T> | |||
211 | class SAL_WARN_UNUSED__attribute__((warn_unused)) SvCompatWeakRef | |||
212 | { | |||
213 | tools::SvRef< SvCompatWeakHdl<T> > _xHdl; | |||
214 | public: | |||
215 | SvCompatWeakRef( ) {} | |||
216 | SvCompatWeakRef( T* pObj ) | |||
217 | { if( pObj ) _xHdl = pObj->GetHdl(); } | |||
218 | #if defined(__COVERITY__) | |||
219 | ~SvCompatWeakRef() COVERITY_NOEXCEPT_FALSE {} | |||
220 | #endif | |||
221 | SvCompatWeakRef& operator = ( T * pObj ) | |||
222 | { _xHdl = pObj ? pObj->GetHdl() : nullptr; return *this; } | |||
223 | bool is() const | |||
224 | { return _xHdl.is() && _xHdl->GetObj(); } | |||
225 | explicit operator bool() const { return is(); } | |||
226 | T* operator -> () const | |||
227 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
228 | operator T* () const | |||
229 | { return _xHdl.is() ? _xHdl->GetObj() : nullptr; } | |||
230 | }; | |||
231 | ||||
232 | #endif | |||
233 | ||||
234 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |