Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ctrlbox.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SVT_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/svtools/source/inc -I /home/maarten/src/libreoffice/core/svtools/inc -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx

/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx

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 <config_folders.h>
21
22#include <comphelper/lok.hxx>
23#include <i18nutil/unicode.hxx>
24#include <officecfg/Office/Common.hxx>
25#include <tools/stream.hxx>
26#include <vcl/customweld.hxx>
27#include <vcl/event.hxx>
28#include <vcl/svapp.hxx>
29#include <vcl/fieldvalues.hxx>
30#include <vcl/settings.hxx>
31#include <vcl/image.hxx>
32#include <vcl/virdev.hxx>
33#include <rtl/math.hxx>
34#include <sal/macros.h>
35#include <sal/log.hxx>
36#include <comphelper/processfactory.hxx>
37#include <comphelper/string.hxx>
38#include <unotools/charclass.hxx>
39#include <unotools/localedatawrapper.hxx>
40#include <unotools/syslocale.hxx>
41
42#include <svtools/borderline.hxx>
43#include <svtools/sampletext.hxx>
44#include <svtools/svtresid.hxx>
45#include <svtools/strings.hrc>
46#include <svtools/ctrlbox.hxx>
47#include <svtools/ctrltool.hxx>
48#include <svtools/borderhelper.hxx>
49#include <svtools/valueset.hxx>
50
51#include <basegfx/polygon/b2dpolygon.hxx>
52#include <basegfx/polygon/b2dpolygontools.hxx>
53#include <editeng/borderline.hxx>
54
55#include <rtl/bootstrap.hxx>
56
57#include <boost/property_tree/ptree.hpp>
58
59#include <borderline.hrc>
60
61#include <stdio.h>
62
63#define IMGOUTERTEXTSPACE5 5
64#define EXTRAFONTSIZE5 5
65#define GAPTOEXTRAPREVIEW10 10
66#define MINGAPWIDTH2 2
67
68#define FONTNAMEBOXMRUENTRIESFILE"/user/config/fontnameboxmruentries" "/user/config/fontnameboxmruentries"
69
70
71BorderWidthImpl::BorderWidthImpl( BorderWidthImplFlags nFlags, double nRate1, double nRate2, double nRateGap ):
72 m_nFlags( nFlags ),
73 m_nRate1( nRate1 ),
74 m_nRate2( nRate2 ),
75 m_nRateGap( nRateGap )
76{
77}
78
79bool BorderWidthImpl::operator== ( const BorderWidthImpl& r ) const
80{
81 return ( m_nFlags == r.m_nFlags ) &&
82 ( m_nRate1 == r.m_nRate1 ) &&
83 ( m_nRate2 == r.m_nRate2 ) &&
84 ( m_nRateGap == r.m_nRateGap );
85}
86
87long BorderWidthImpl::GetLine1( long nWidth ) const
88{
89 long result = static_cast<long>(m_nRate1);
90 if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 )
91 {
92 long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
93 long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
94 result = std::max<long>(0,
95 static_cast<long>((m_nRate1 * nWidth) + 0.5)
96 - (nConstant2 + nConstantD));
97 if (result == 0 && m_nRate1 > 0.0 && nWidth > 0)
98 { // fdo#51777: hack to essentially treat 1 twip DOUBLE border
99 result = 1; // as 1 twip SINGLE border
100 }
101 }
102 return result;
103}
104
105long BorderWidthImpl::GetLine2( long nWidth ) const
106{
107 long result = static_cast<long>(m_nRate2);
108 if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2)
109 {
110 long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
111 long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
112 result = std::max<long>(0,
113 static_cast<long>((m_nRate2 * nWidth) + 0.5)
114 - (nConstant1 + nConstantD));
115 }
116 return result;
117}
118
119long BorderWidthImpl::GetGap( long nWidth ) const
120{
121 long result = static_cast<long>(m_nRateGap);
122 if ( m_nFlags & BorderWidthImplFlags::CHANGE_DIST )
123 {
124 long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
125 long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
126 result = std::max<long>(0,
127 static_cast<long>((m_nRateGap * nWidth) + 0.5)
128 - (nConstant1 + nConstant2));
129 }
130
131 // Avoid having too small distances (less than 0.1pt)
132 if ( result < MINGAPWIDTH2 && m_nRate1 > 0 && m_nRate2 > 0 )
133 result = MINGAPWIDTH2;
134
135 return result;
136}
137
138static double lcl_getGuessedWidth( long nTested, double nRate, bool bChanging )
139{
140 double nWidth = -1.0;
141 if ( bChanging )
142 nWidth = double( nTested ) / nRate;
143 else
144 {
145 if ( rtl::math::approxEqual(double( nTested ), nRate) )
146 nWidth = nRate;
147 }
148
149 return nWidth;
150}
151
152long BorderWidthImpl::GuessWidth( long nLine1, long nLine2, long nGap )
153{
154 std::vector< double > aToCompare;
155 bool bInvalid = false;
156
157 bool bLine1Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 );
158 double nWidth1 = lcl_getGuessedWidth( nLine1, m_nRate1, bLine1Change );
159 if ( bLine1Change )
160 aToCompare.push_back( nWidth1 );
161 else if (nWidth1 < 0)
162 bInvalid = true;
163
164 bool bLine2Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2 );
165 double nWidth2 = lcl_getGuessedWidth( nLine2, m_nRate2, bLine2Change );
166 if ( bLine2Change )
167 aToCompare.push_back( nWidth2 );
168 else if (nWidth2 < 0)
169 bInvalid = true;
170
171 bool bGapChange = bool( m_nFlags & BorderWidthImplFlags::CHANGE_DIST );
172 double nWidthGap = lcl_getGuessedWidth( nGap, m_nRateGap, bGapChange );
173 if ( bGapChange && nGap >= MINGAPWIDTH2 )
174 aToCompare.push_back( nWidthGap );
175 else if ( !bGapChange && nWidthGap < 0 )
176 bInvalid = true;
177
178 // non-constant line width factors must sum to 1
179 assert((((bLine1Change) ? m_nRate1 : 0) +(static_cast <bool> ((((bLine1Change) ? m_nRate1 : 0) +
((bLine2Change) ? m_nRate2 : 0) + ((bGapChange) ? m_nRateGap
: 0)) - 1.0 < 0.00001) ? void (0) : __assert_fail ("(((bLine1Change) ? m_nRate1 : 0) + ((bLine2Change) ? m_nRate2 : 0) + ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001"
, "/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
, 181, __extension__ __PRETTY_FUNCTION__))
180 ((bLine2Change) ? m_nRate2 : 0) +(static_cast <bool> ((((bLine1Change) ? m_nRate1 : 0) +
((bLine2Change) ? m_nRate2 : 0) + ((bGapChange) ? m_nRateGap
: 0)) - 1.0 < 0.00001) ? void (0) : __assert_fail ("(((bLine1Change) ? m_nRate1 : 0) + ((bLine2Change) ? m_nRate2 : 0) + ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001"
, "/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
, 181, __extension__ __PRETTY_FUNCTION__))
181 ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001 )(static_cast <bool> ((((bLine1Change) ? m_nRate1 : 0) +
((bLine2Change) ? m_nRate2 : 0) + ((bGapChange) ? m_nRateGap
: 0)) - 1.0 < 0.00001) ? void (0) : __assert_fail ("(((bLine1Change) ? m_nRate1 : 0) + ((bLine2Change) ? m_nRate2 : 0) + ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001"
, "/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
, 181, __extension__ __PRETTY_FUNCTION__))
;
182
183 double nWidth = 0.0;
184 if ( (!bInvalid) && (!aToCompare.empty()) )
185 {
186 nWidth = *aToCompare.begin();
187 for (auto const& elem : aToCompare)
188 {
189 bInvalid = ( nWidth != elem );
190 if (bInvalid)
191 break;
192 }
193 nWidth = bInvalid ? 0.0 : nLine1 + nLine2 + nGap;
194 }
195
196 return nWidth;
197}
198
199static void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, long nWidth, SvxBorderLineStyle nDashing )
200{
201 AntialiasingFlags nOldAA = rDev.GetAntialiasing();
202 rDev.SetAntialiasing( nOldAA & ~AntialiasingFlags::Enable );
203
204 long nPix = rDev.PixelToLogic(Size(1, 1)).Width();
205 basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing(rPolygon, nDashing, nPix);
206
207 // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line
208 if (rDev.GetMapMode().GetMapUnit() == MapUnit::MapPixel && nWidth == nPix)
209 nWidth = 0;
210
211 for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ )
212 {
213 const basegfx::B2DPolygon& aDash = aPolygons.getB2DPolygon( i );
214 basegfx::B2DPoint aStart = aDash.getB2DPoint( 0 );
215 basegfx::B2DPoint aEnd = aDash.getB2DPoint( aDash.count() - 1 );
216
217 basegfx::B2DVector aVector( aEnd - aStart );
218 aVector.normalize( );
219 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
220
221 const basegfx::B2DVector aWidthOffset( double( nWidth ) / 2 * aPerpendicular);
222 basegfx::B2DPolygon aDashPolygon;
223 aDashPolygon.append( aStart + aWidthOffset );
224 aDashPolygon.append( aEnd + aWidthOffset );
225 aDashPolygon.append( aEnd - aWidthOffset );
226 aDashPolygon.append( aStart - aWidthOffset );
227 aDashPolygon.setClosed( true );
228
229 rDev.DrawPolygon( aDashPolygon );
230 }
231
232 rDev.SetAntialiasing( nOldAA );
233}
234
235namespace svtools {
236
237/**
238 * Dashing array must start with a line width and end with a blank width.
239 */
240static std::vector<double> GetDashing( SvxBorderLineStyle nDashing )
241{
242 std::vector<double> aPattern;
243 switch (nDashing)
244 {
245 case SvxBorderLineStyle::DOTTED:
246 aPattern.push_back( 1.0 ); // line
247 aPattern.push_back( 2.0 ); // blank
248 break;
249 case SvxBorderLineStyle::DASHED:
250 aPattern.push_back( 16.0 ); // line
251 aPattern.push_back( 5.0 ); // blank
252 break;
253 case SvxBorderLineStyle::FINE_DASHED:
254 aPattern.push_back( 6.0 ); // line
255 aPattern.push_back( 2.0 ); // blank
256 break;
257 case SvxBorderLineStyle::DASH_DOT:
258 aPattern.push_back( 16.0 ); // line
259 aPattern.push_back( 5.0 ); // blank
260 aPattern.push_back( 5.0 ); // line
261 aPattern.push_back( 5.0 ); // blank
262 break;
263 case SvxBorderLineStyle::DASH_DOT_DOT:
264 aPattern.push_back( 16.0 ); // line
265 aPattern.push_back( 5.0 ); // blank
266 aPattern.push_back( 5.0 ); // line
267 aPattern.push_back( 5.0 ); // blank
268 aPattern.push_back( 5.0 ); // line
269 aPattern.push_back( 5.0 ); // blank
270 break;
271 default:
272 ;
273 }
274
275 return aPattern;
276}
277
278namespace {
279
280class ApplyScale
281{
282 double mfScale;
283public:
284 explicit ApplyScale( double fScale ) : mfScale(fScale) {}
285 void operator() ( double& rVal )
286 {
287 rVal *= mfScale;
288 }
289};
290
291}
292
293std::vector<double> GetLineDashing( SvxBorderLineStyle nDashing, double fScale )
294{
295 std::vector<double> aPattern = GetDashing(nDashing);
296 std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
297 return aPattern;
298}
299
300basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, SvxBorderLineStyle nDashing, double fScale )
301{
302 std::vector<double> aPattern = GetDashing(nDashing);
303 std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
304
305 basegfx::B2DPolyPolygon aPolygons;
306
307 if (aPattern.empty())
308 aPolygons.append(rPolygon);
309 else
310 basegfx::utils::applyLineDashing(rPolygon, aPattern, &aPolygons);
311
312 return aPolygons;
313}
314
315void DrawLine( OutputDevice& rDev, const Point& rP1, const Point& rP2,
316 sal_uInt32 nWidth, SvxBorderLineStyle nDashing )
317{
318 DrawLine( rDev, basegfx::B2DPoint( rP1.X(), rP1.Y() ),
319 basegfx::B2DPoint( rP2.X(), rP2.Y( ) ), nWidth, nDashing );
320}
321
322void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rP1, const basegfx::B2DPoint& rP2,
323 sal_uInt32 nWidth, SvxBorderLineStyle nDashing )
324{
325 basegfx::B2DPolygon aPolygon;
326 aPolygon.append( rP1 );
327 aPolygon.append( rP2 );
328 lclDrawPolygon( rDev, aPolygon, nWidth, nDashing );
329}
330
331}
332
333static Size gUserItemSz;
334static int gFontNameBoxes;
335static size_t gPreviewsPerDevice;
336static std::vector<VclPtr<VirtualDevice>> gFontPreviewVirDevs;
337static std::vector<OUString> gRenderedFontNames;
338
339namespace
340{
341 void calcCustomItemSize(const weld::ComboBox& rComboBox)
342 {
343 gUserItemSz = Size(rComboBox.get_approximate_digit_width() * 52, rComboBox.get_text_height());
344 gUserItemSz.setHeight(gUserItemSz.Height() * 16);
345 gUserItemSz.setHeight(gUserItemSz.Height() / 10);
346
347 size_t nMaxDeviceHeight = SAL_MAX_INT16((sal_Int16) 0x7FFF) / 2; // see limitXCreatePixmap
348 gPreviewsPerDevice = nMaxDeviceHeight / gUserItemSz.Height();
349 }
350}
351
352IMPL_LINK(FontNameBox, SettingsChangedHdl, VclSimpleEvent&, rEvent, void)void FontNameBox::LinkStubSettingsChangedHdl(void * instance,
VclSimpleEvent& data) { return static_cast<FontNameBox
*>(instance)->SettingsChangedHdl(data); } void FontNameBox
::SettingsChangedHdl(VclSimpleEvent& rEvent)
353{
354 if (rEvent.GetId() != VclEventId::ApplicationDataChanged)
355 return;
356
357 DataChangedEvent* pData = static_cast<DataChangedEvent*>(static_cast<VclWindowEvent&>(rEvent).GetData());
358 if (pData->GetType() == DataChangedEventType::SETTINGS)
359 {
360 gFontPreviewVirDevs.clear();
361 gRenderedFontNames.clear();
362 calcCustomItemSize(*m_xComboBox);
363 if (mbWYSIWYG)
364 maUpdateIdle.Start();
365 }
366}
367
368FontNameBox::FontNameBox(std::unique_ptr<weld::ComboBox> p)
369 : m_xComboBox(std::move(p))
370 , mnPreviewProgress(0)
371 , mbWYSIWYG(false)
372 , maUpdateIdle("FontNameBox Preview Update")
373{
374 ++gFontNameBoxes;
375 InitFontMRUEntriesFile();
376
377 maUpdateIdle.SetPriority(TaskPriority::LOWEST);
378 maUpdateIdle.SetInvokeHandler(LINK(this, FontNameBox, UpdateHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontNameBox
*>(this), &FontNameBox::LinkStubUpdateHdl)
);
379
380 Application::AddEventListener(LINK(this, FontNameBox, SettingsChangedHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontNameBox
*>(this), &FontNameBox::LinkStubSettingsChangedHdl)
);
381}
382
383FontNameBox::~FontNameBox()
384{
385 Application::RemoveEventListener(LINK(this, FontNameBox, SettingsChangedHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontNameBox
*>(this), &FontNameBox::LinkStubSettingsChangedHdl)
);
386
387 if (mpFontList)
388 {
389 SaveMRUEntries (maFontMRUEntriesFile);
390 ImplDestroyFontList();
391 }
392 --gFontNameBoxes;
393 if (!gFontNameBoxes)
394 {
395 gFontPreviewVirDevs.clear();
396 gRenderedFontNames.clear();
397 }
398}
399
400void FontNameBox::SaveMRUEntries(const OUString& aFontMRUEntriesFile) const
401{
402 OString aEntries(OUStringToOString(m_xComboBox->get_mru_entries(),
403 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
404
405 if (aEntries.isEmpty() || aFontMRUEntriesFile.isEmpty())
406 return;
407
408 SvFileStream aStream;
409 aStream.Open( aFontMRUEntriesFile, StreamMode::WRITE | StreamMode::TRUNC );
410 if( ! (aStream.IsOpen() && aStream.IsWritable()) )
411 {
412 SAL_INFO("svtools.control", "FontNameBox::SaveMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "svtools.control")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "FontNameBox::SaveMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "412" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "FontNameBox::SaveMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"FontNameBox::SaveMRUEntries: opening mru entries file " <<
aFontMRUEntriesFile << " failed"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "412" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "FontNameBox::SaveMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "412" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "FontNameBox::SaveMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"FontNameBox::SaveMRUEntries: opening mru entries file " <<
aFontMRUEntriesFile << " failed"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "412" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
413 return;
414 }
415
416 aStream.SetLineDelimiter( LINEEND_LF );
417 aStream.WriteLine( aEntries );
418 aStream.WriteLine( OString() );
419}
420
421void FontNameBox::LoadMRUEntries( const OUString& aFontMRUEntriesFile )
422{
423 if (aFontMRUEntriesFile.isEmpty())
424 return;
425
426 if (!officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::get())
427 return;
428
429 SvFileStream aStream( aFontMRUEntriesFile, StreamMode::READ );
430 if( ! aStream.IsOpen() )
431 {
432 SAL_INFO("svtools.control", "FontNameBox::LoadMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_INFO
, "svtools.control")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break
; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "FontNameBox::LoadMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "432" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "FontNameBox::LoadMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"FontNameBox::LoadMRUEntries: opening mru entries file " <<
aFontMRUEntriesFile << " failed"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "432" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "FontNameBox::LoadMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed") == 1) { ::sal_detail_log
( (::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "432" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "FontNameBox::LoadMRUEntries: opening mru entries file "
<< aFontMRUEntriesFile << " failed"), 0); } else
{ ::std::ostringstream sal_detail_stream; sal_detail_stream <<
"FontNameBox::LoadMRUEntries: opening mru entries file " <<
aFontMRUEntriesFile << " failed"; ::sal::detail::log( (
::SAL_DETAIL_LOG_LEVEL_INFO), ("svtools.control"), ("/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
":" "432" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
433 return;
434 }
435
436 OString aLine;
437 aStream.ReadLine( aLine );
438 OUString aEntries = OStringToOUString(aLine,
439 RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76)));
440 m_xComboBox->set_mru_entries(aEntries);
441}
442
443void FontNameBox::InitFontMRUEntriesFile()
444{
445 OUString sUserConfigDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER"program" "/" SAL_CONFIGFILE( "bootstrap")"bootstrap" "rc" "::UserInstallation}");
446 rtl::Bootstrap::expandMacros(sUserConfigDir);
447
448 maFontMRUEntriesFile = sUserConfigDir;
449 if( !maFontMRUEntriesFile.isEmpty() )
450 {
451 maFontMRUEntriesFile += FONTNAMEBOXMRUENTRIESFILE"/user/config/fontnameboxmruentries";
452 }
453}
454
455void FontNameBox::ImplDestroyFontList()
456{
457 mpFontList.reset();
458 mnPreviewProgress = 0;
459 maUpdateIdle.Stop();
460}
461
462void FontNameBox::Fill( const FontList* pList )
463{
464 // store old text and clear box
465 OUString aOldText = m_xComboBox->get_active_text();
466 OUString rEntries = m_xComboBox->get_mru_entries();
467 bool bLoadFromFile = rEntries.isEmpty();
468 m_xComboBox->freeze();
469 m_xComboBox->clear();
470
471 ImplDestroyFontList();
472 mpFontList.reset(new ImplFontList);
473
474 // insert fonts
475 size_t nFontCount = pList->GetFontNameCount();
476 for (size_t i = 0; i < nFontCount; ++i)
477 {
478 const FontMetric& rFontMetric = pList->GetFontName(i);
479 m_xComboBox->append(OUString::number(i), rFontMetric.GetFamilyName());
480 mpFontList->push_back(rFontMetric);
481 }
482
483 if (bLoadFromFile)
484 LoadMRUEntries(maFontMRUEntriesFile);
485 else
486 m_xComboBox->set_mru_entries(rEntries);
487
488 m_xComboBox->thaw();
489
490 if (mbWYSIWYG && nFontCount)
491 {
492 assert(mnPreviewProgress == 0 && "ImplDestroyFontList wasn't called")(static_cast <bool> (mnPreviewProgress == 0 && "ImplDestroyFontList wasn't called"
) ? void (0) : __assert_fail ("mnPreviewProgress == 0 && \"ImplDestroyFontList wasn't called\""
, "/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
, 492, __extension__ __PRETTY_FUNCTION__))
;
493 maUpdateIdle.Start();
494 }
495
496 // restore text
497 if (!aOldText.isEmpty())
498 set_active_or_entry_text(aOldText);
499}
500
501void FontNameBox::EnableWYSIWYG(bool bEnable)
502{
503 if (comphelper::LibreOfficeKit::isActive())
504 return;
505 if (mbWYSIWYG == bEnable)
506 return;
507 mbWYSIWYG = bEnable;
508
509 if (mbWYSIWYG)
510 {
511 calcCustomItemSize(*m_xComboBox);
512 m_xComboBox->connect_custom_get_size(LINK(this, FontNameBox, CustomGetSizeHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontNameBox
*>(this), &FontNameBox::LinkStubCustomGetSizeHdl)
);
513 m_xComboBox->connect_custom_render(LINK(this, FontNameBox, CustomRenderHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontNameBox
*>(this), &FontNameBox::LinkStubCustomRenderHdl)
);
514 }
515 else
516 {
517 m_xComboBox->connect_custom_get_size(Link<OutputDevice&, Size>());
518 m_xComboBox->connect_custom_render(Link<weld::ComboBox::render_args, void>());
519 }
520 m_xComboBox->set_custom_renderer(mbWYSIWYG);
521}
522
523IMPL_LINK_NOARG(FontNameBox, CustomGetSizeHdl, OutputDevice&, Size)Size FontNameBox::LinkStubCustomGetSizeHdl(void * instance, OutputDevice
& data) { return static_cast<FontNameBox *>(instance
)->CustomGetSizeHdl(data); } Size FontNameBox::CustomGetSizeHdl
(__attribute__ ((unused)) OutputDevice&)
524{
525 return mbWYSIWYG ? gUserItemSz : Size();
526}
527
528namespace
529{
530 long shrinkFontToFit(OUString const &rSampleText, long nH, vcl::Font &rFont, OutputDevice &rDevice, tools::Rectangle &rTextRect)
531 {
532 long nWidth = 0;
533
534 Size aSize( rFont.GetFontSize() );
535
536 //Make sure it fits in the available height
537 while (aSize.Height() > 0)
538 {
539 if (!rDevice.GetTextBoundRect(rTextRect, rSampleText))
540 break;
541 if (rTextRect.GetHeight() <= nH)
542 {
543 nWidth = rTextRect.GetWidth();
544 break;
545 }
546
547 aSize.AdjustHeight( -(EXTRAFONTSIZE5) );
548 rFont.SetFontSize(aSize);
549 rDevice.SetFont(rFont);
550 }
551
552 return nWidth;
553 }
554}
555
556IMPL_LINK_NOARG(FontNameBox, UpdateHdl, Timer*, void)void FontNameBox::LinkStubUpdateHdl(void * instance, Timer* data
) { return static_cast<FontNameBox *>(instance)->UpdateHdl
(data); } void FontNameBox::UpdateHdl(__attribute__ ((unused)
) Timer*)
557{
558 CachePreview(mnPreviewProgress++, nullptr);
559 // tdf#132536 limit to ~25 pre-rendered for now. The font caches look
560 // b0rked, the massive charmaps are ~never swapped out, and don't count
561 // towards the size of a font in the font cache and if the freetype font
562 // cache size is set experimentally very low then we crash, so there's an
563 // awful lot to consider there.
564 if (mnPreviewProgress < std::min<size_t>(25, mpFontList->size()))
565 maUpdateIdle.Start();
566}
567
568static void DrawPreview(const FontMetric& rFontMetric, const Point& rTopLeft, OutputDevice& rDevice, bool bSelected)
569{
570 rDevice.Push(PushFlags::TEXTCOLOR);
571
572 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
573 if (bSelected)
574 rDevice.SetTextColor(rStyleSettings.GetHighlightTextColor());
575 else
576 rDevice.SetTextColor(rStyleSettings.GetDialogTextColor());
577
578 long nX = rTopLeft.X();
579 long nH = gUserItemSz.Height();
580
581 nX += IMGOUTERTEXTSPACE5;
582
583 const bool bSymbolFont = isSymbolFont(rFontMetric);
584
585 vcl::Font aOldFont(rDevice.GetFont());
586 Size aSize( aOldFont.GetFontSize() );
587 aSize.AdjustHeight(EXTRAFONTSIZE5 );
588 vcl::Font aFont( rFontMetric );
589 aFont.SetFontSize( aSize );
590 rDevice.SetFont(aFont);
591
592 bool bUsingCorrectFont = true;
593 tools::Rectangle aTextRect;
594
595 // Preview the font name
596 const OUString& sFontName = rFontMetric.GetFamilyName();
597
598 //If it shouldn't or can't draw its own name because it doesn't have the glyphs
599 if (!canRenderNameOfSelectedFont(rDevice))
600 bUsingCorrectFont = false;
601 else
602 {
603 //Make sure it fits in the available height, shrinking the font if necessary
604 bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, rDevice, aTextRect) != 0;
605 }
606
607 if (!bUsingCorrectFont)
608 {
609 rDevice.SetFont(aOldFont);
610 rDevice.GetTextBoundRect(aTextRect, sFontName);
611 }
612
613 long nTextHeight = aTextRect.GetHeight();
614 long nDesiredGap = (nH-nTextHeight)/2;
615 long nVertAdjust = nDesiredGap - aTextRect.Top();
616 Point aPos( nX, rTopLeft.Y() + nVertAdjust );
617 rDevice.DrawText(aPos, sFontName);
618 long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW10;
619
620 if (!bUsingCorrectFont)
621 rDevice.SetFont(aFont);
622
623 OUString sSampleText;
624
625 if (!bSymbolFont)
626 {
627 const bool bNameBeginsWithLatinText = rFontMetric.GetFamilyName()[0] <= 'z';
628
629 if (bNameBeginsWithLatinText || !bUsingCorrectFont)
630 sSampleText = makeShortRepresentativeTextForSelectedFont(rDevice);
631 }
632
633 //If we're not a symbol font, but could neither render our own name and
634 //we can't determine what script it would like to render, then try a
635 //few well known scripts
636 if (sSampleText.isEmpty() && !bUsingCorrectFont)
637 {
638 static const UScriptCode aScripts[] =
639 {
640 USCRIPT_ARABIC,
641 USCRIPT_HEBREW,
642
643 USCRIPT_BENGALI,
644 USCRIPT_GURMUKHI,
645 USCRIPT_GUJARATI,
646 USCRIPT_ORIYA,
647 USCRIPT_TAMIL,
648 USCRIPT_TELUGU,
649 USCRIPT_KANNADA,
650 USCRIPT_MALAYALAM,
651 USCRIPT_SINHALA,
652 USCRIPT_DEVANAGARI,
653
654 USCRIPT_THAI,
655 USCRIPT_LAO,
656 USCRIPT_GEORGIAN,
657 USCRIPT_TIBETAN,
658 USCRIPT_SYRIAC,
659 USCRIPT_MYANMAR,
660 USCRIPT_ETHIOPIC,
661 USCRIPT_KHMER,
662 USCRIPT_MONGOLIAN,
663
664 USCRIPT_KOREAN,
665 USCRIPT_JAPANESE,
666 USCRIPT_HAN,
667 USCRIPT_SIMPLIFIED_HAN,
668 USCRIPT_TRADITIONAL_HAN,
669
670 USCRIPT_GREEK
671 };
672
673 for (const UScriptCode& rScript : aScripts)
674 {
675 OUString sText = makeShortRepresentativeTextForScript(rScript);
676 if (!sText.isEmpty())
677 {
678 bool bHasSampleTextGlyphs = (-1 == rDevice.HasGlyphs(aFont, sText));
679 if (bHasSampleTextGlyphs)
680 {
681 sSampleText = sText;
682 break;
683 }
684 }
685 }
686
687 static const UScriptCode aMinimalScripts[] =
688 {
689 USCRIPT_HEBREW, //e.g. biblical hebrew
690 USCRIPT_GREEK
691 };
692
693 for (const UScriptCode& rMinimalScript : aMinimalScripts)
694 {
695 OUString sText = makeShortMinimalTextForScript(rMinimalScript);
696 if (!sText.isEmpty())
697 {
698 bool bHasSampleTextGlyphs = (-1 == rDevice.HasGlyphs(aFont, sText));
699 if (bHasSampleTextGlyphs)
700 {
701 sSampleText = sText;
702 break;
703 }
704 }
705 }
706 }
707
708 //If we're a symbol font, or for some reason the font still couldn't
709 //render something representative of what it would like to render then
710 //make up some semi-random text that it *can* display
711 if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
712 sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(rDevice);
713
714 if (!sSampleText.isEmpty())
715 {
716 const Size &rItemSize = gUserItemSz;
717
718 //leave a little border at the edge
719 long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE5;
720 if (nSpace >= 0)
721 {
722 //Make sure it fits in the available height, and get how wide that would be
723 long nWidth = shrinkFontToFit(sSampleText, nH, aFont, rDevice, aTextRect);
724 //Chop letters off until it fits in the available width
725 while (nWidth > nSpace || nWidth > gUserItemSz.Width())
726 {
727 sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
728 nWidth = rDevice.GetTextBoundRect(aTextRect, sSampleText) ?
729 aTextRect.GetWidth() : 0;
730 }
731
732 //center the text on the line
733 if (!sSampleText.isEmpty() && nWidth)
734 {
735 nTextHeight = aTextRect.GetHeight();
736 nDesiredGap = (nH-nTextHeight)/2;
737 nVertAdjust = nDesiredGap - aTextRect.Top();
738 aPos = Point(nTextX + nSpace - nWidth, rTopLeft.Y() + nVertAdjust);
739 rDevice.DrawText(aPos, sSampleText);
740 }
741 }
742 }
743
744 rDevice.SetFont(aOldFont);
745 rDevice.Pop();
746}
747
748OutputDevice& FontNameBox::CachePreview(size_t nIndex, Point* pTopLeft)
749{
750 SolarMutexGuard aGuard;
751 const FontMetric& rFontMetric = (*mpFontList)[nIndex];
752 const OUString& rFontName = rFontMetric.GetFamilyName();
753
754 size_t nPreviewIndex;
755 auto xFind = std::find(gRenderedFontNames.begin(), gRenderedFontNames.end(), rFontName);
756 bool bPreviewAvailable = xFind != gRenderedFontNames.end();
757 if (!bPreviewAvailable)
758 {
759 nPreviewIndex = gRenderedFontNames.size();
760 gRenderedFontNames.push_back(rFontName);
761 }
762 else
763 nPreviewIndex = std::distance(gRenderedFontNames.begin(), xFind);
764
765 size_t nPage = nPreviewIndex / gPreviewsPerDevice;
766 size_t nIndexInPage = nPreviewIndex - (nPage * gPreviewsPerDevice);
767
768 Point aTopLeft(0, gUserItemSz.Height() * nIndexInPage);
769
770 if (!bPreviewAvailable)
771 {
772 if (nPage >= gFontPreviewVirDevs.size())
773 {
774 gFontPreviewVirDevs.emplace_back(m_xComboBox->create_render_virtual_device());
775 VirtualDevice& rDevice = *gFontPreviewVirDevs.back();
776 rDevice.SetOutputSizePixel(Size(gUserItemSz.Width(), gUserItemSz.Height() * gPreviewsPerDevice));
777 if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
778 pDefaultDevice->SetPointFont(rDevice, m_xComboBox->get_font());
779 assert(gFontPreviewVirDevs.size() == nPage + 1)(static_cast <bool> (gFontPreviewVirDevs.size() == nPage
+ 1) ? void (0) : __assert_fail ("gFontPreviewVirDevs.size() == nPage + 1"
, "/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
, 779, __extension__ __PRETTY_FUNCTION__))
;
780 }
781
782 DrawPreview(rFontMetric, aTopLeft, *gFontPreviewVirDevs.back(), false);
783 }
784
785 if (pTopLeft)
786 *pTopLeft = aTopLeft;
787
788 return *gFontPreviewVirDevs[nPage];
789}
790
791IMPL_LINK(FontNameBox, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)void FontNameBox::LinkStubCustomRenderHdl(void * instance, weld
::ComboBox::render_args data) { return static_cast<FontNameBox
*>(instance)->CustomRenderHdl(data); } void FontNameBox
::CustomRenderHdl(weld::ComboBox::render_args aPayload)
792{
793 vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
794 const ::tools::Rectangle& rRect = std::get<1>(aPayload);
795 bool bSelected = std::get<2>(aPayload);
796 const OUString& rId = std::get<3>(aPayload);
797
798 sal_uInt32 nIndex = rId.toUInt32();
799
800 Point aDestPoint(rRect.TopLeft());
801 auto nMargin = (rRect.GetHeight() - gUserItemSz.Height()) / 2;
802 aDestPoint.AdjustY(nMargin);
803
804 if (bSelected)
805 {
806 const FontMetric& rFontMetric = (*mpFontList)[nIndex];
807 DrawPreview(rFontMetric, aDestPoint, rRenderContext, true);
808 }
809 else
810 {
811 // use cache of unselected entries
812 Point aTopLeft;
813 OutputDevice& rDevice = CachePreview(nIndex, &aTopLeft);
814
815 rRenderContext.DrawOutDev(aDestPoint, gUserItemSz,
816 aTopLeft, gUserItemSz,
817 rDevice);
818 }
819}
820
821void FontNameBox::set_active_or_entry_text(const OUString& rText)
822{
823 const int nFound = m_xComboBox->find_text(rText);
824 if (nFound != -1)
825 m_xComboBox->set_active(nFound);
826 m_xComboBox->set_entry_text(rText);
827}
828
829FontStyleBox::FontStyleBox(std::unique_ptr<weld::ComboBox> p)
830 : m_xComboBox(std::move(p))
831{
832 //Use the standard texts to get an optimal size and stick to that size.
833 //That should stop the character dialog dancing around.
834 auto nMaxLen = m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHTreinterpret_cast<char const *>("STR_SVT_STYLE_LIGHT" "\004"
u8"Light")
)).Width();
835 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT_ITALICreinterpret_cast<char const *>("STR_SVT_STYLE_LIGHT_ITALIC"
"\004" u8"Light Italic")
)).Width());
836 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMALreinterpret_cast<char const *>("STR_SVT_STYLE_NORMAL" "\004"
u8"Regular")
)).Width());
837 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL_ITALICreinterpret_cast<char const *>("STR_SVT_STYLE_NORMAL_ITALIC"
"\004" u8"Italic")
)).Width());
838 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLDreinterpret_cast<char const *>("STR_SVT_STYLE_BOLD" "\004"
u8"Bold")
)).Width());
839 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD_ITALICreinterpret_cast<char const *>("STR_SVT_STYLE_BOLD_ITALIC"
"\004" u8"Bold Italic")
)).Width());
840 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACKreinterpret_cast<char const *>("STR_SVT_STYLE_BLACK" "\004"
u8"Black")
)).Width());
841 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK_ITALICreinterpret_cast<char const *>("STR_SVT_STYLE_BLACK_ITALIC"
"\004" u8"Black Italic")
)).Width());
842 m_xComboBox->set_entry_width_chars(std::ceil(nMaxLen / m_xComboBox->get_approximate_digit_width()));
843}
844
845void FontStyleBox::Fill( const OUString& rName, const FontList* pList )
846{
847 m_xComboBox->freeze();
848 OUString aOldText = m_xComboBox->get_active_text();
849 int nPos = m_xComboBox->get_active();
850 m_xComboBox->clear();
851
852 // does a font with this name already exist?
853 sal_Handle hFontMetric = pList->GetFirstFontMetric( rName );
854 if ( hFontMetric )
855 {
856 OUString aStyleText;
857 FontWeight eLastWeight = WEIGHT_DONTKNOW;
858 FontItalic eLastItalic = ITALIC_NONE;
859 FontWidth eLastWidth = WIDTH_DONTKNOW;
860 bool bNormal = false;
861 bool bItalic = false;
862 bool bBold = false;
863 bool bBoldItalic = false;
864 bool bInsert = false;
865 FontMetric aFontMetric;
866 while ( hFontMetric )
867 {
868 aFontMetric = FontList::GetFontMetric( hFontMetric );
869
870 FontWeight eWeight = aFontMetric.GetWeight();
871 FontItalic eItalic = aFontMetric.GetItalic();
872 FontWidth eWidth = aFontMetric.GetWidthType();
873 // Only if the attributes are different, we insert the
874 // Font to avoid double Entries in different languages
875 if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) ||
876 (eWidth != eLastWidth) )
877 {
878 if ( bInsert )
879 m_xComboBox->append_text(aStyleText);
880
881 if ( eWeight <= WEIGHT_NORMAL )
882 {
883 if ( eItalic != ITALIC_NONE )
884 bItalic = true;
885 else
886 bNormal = true;
887 }
888 else
889 {
890 if ( eItalic != ITALIC_NONE )
891 bBoldItalic = true;
892 else
893 bBold = true;
894 }
895
896 // For wrong StyleNames we replace this with the correct once
897 aStyleText = pList->GetStyleName( aFontMetric );
898 bInsert = m_xComboBox->find_text(aStyleText) == -1;
899 if ( !bInsert )
900 {
901 aStyleText = pList->GetStyleName( eWeight, eItalic );
902 bInsert = m_xComboBox->find_text(aStyleText) == -1;
903 }
904
905 eLastWeight = eWeight;
906 eLastItalic = eItalic;
907 eLastWidth = eWidth;
908 }
909 else
910 {
911 if ( bInsert )
912 {
913 // If we have two names for the same attributes
914 // we prefer the translated standard names
915 const OUString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic );
916 if (rAttrStyleText != aStyleText)
917 {
918 OUString aTempStyleText = pList->GetStyleName( aFontMetric );
919 if (rAttrStyleText == aTempStyleText)
920 aStyleText = rAttrStyleText;
921 bInsert = m_xComboBox->find_text(aStyleText) == -1;
922 }
923 }
924 }
925
926 if ( !bItalic && (aStyleText == pList->GetItalicStr()) )
927 bItalic = true;
928 else if ( !bBold && (aStyleText == pList->GetBoldStr()) )
929 bBold = true;
930 else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) )
931 bBoldItalic = true;
932
933 hFontMetric = FontList::GetNextFontMetric( hFontMetric );
934 }
935
936 if ( bInsert )
937 m_xComboBox->append_text(aStyleText);
938
939 // certain style as copy
940 if ( bNormal )
941 {
942 if ( !bItalic )
943 m_xComboBox->append_text(pList->GetItalicStr());
944 if ( !bBold )
945 m_xComboBox->append_text(pList->GetBoldStr());
946 }
947 if ( !bBoldItalic )
948 {
949 if ( bNormal || bItalic || bBold )
950 m_xComboBox->append_text(pList->GetBoldItalicStr());
951 }
952 if (!aOldText.isEmpty())
953 {
954 int nFound = m_xComboBox->find_text(aOldText);
955 if (nFound != -1)
956 m_xComboBox->set_active(nFound);
957 else
958 {
959 if (nPos >= m_xComboBox->get_count())
960 m_xComboBox->set_active(0);
961 else
962 m_xComboBox->set_active(nPos);
963 }
964 }
965 }
966 else
967 {
968 // insert standard styles if no font
969 m_xComboBox->append_text(pList->GetNormalStr());
970 m_xComboBox->append_text(pList->GetItalicStr());
971 m_xComboBox->append_text(pList->GetBoldStr());
972 m_xComboBox->append_text(pList->GetBoldItalicStr());
973 if (!aOldText.isEmpty())
974 {
975 if (nPos >= m_xComboBox->get_count())
976 m_xComboBox->set_active(0);
977 else
978 m_xComboBox->set_active(nPos);
979 }
980 }
981 m_xComboBox->thaw();
982}
983
984FontSizeBox::FontSizeBox(std::unique_ptr<weld::ComboBox> p)
985 : pFontList(nullptr)
986 , nSavedValue(0)
987 , nMin(20)
988 , nMax(9999)
989 , eUnit(FieldUnit::POINT)
990 , nDecimalDigits(1)
991 , nRelMin(0)
992 , nRelMax(0)
993 , nRelStep(0)
994 , nPtRelMin(0)
995 , nPtRelMax(0)
996 , nPtRelStep(0)
997 , bRelativeMode(false)
998 , bRelative(false)
999 , bPtRelative(false)
1000 , bStdSize(false)
1001 , m_xComboBox(std::move(p))
1002{
1003 m_xComboBox->set_entry_width_chars(std::ceil(m_xComboBox->get_pixel_size(format_number(105)).Width() /
1004 m_xComboBox->get_approximate_digit_width()));
1005 m_xComboBox->connect_focus_out(LINK(this, FontSizeBox, ReformatHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontSizeBox
*>(this), &FontSizeBox::LinkStubReformatHdl)
);
1006 m_xComboBox->connect_changed(LINK(this, FontSizeBox, ModifyHdl)::tools::detail::makeLink( ::tools::detail::castTo<FontSizeBox
*>(this), &FontSizeBox::LinkStubModifyHdl)
);
1007}
1008
1009void FontSizeBox::set_active_or_entry_text(const OUString& rText)
1010{
1011 const int nFound = m_xComboBox->find_text(rText);
1012 if (nFound != -1)
1013 m_xComboBox->set_active(nFound);
1014 m_xComboBox->set_entry_text(rText);
1015}
1016
1017IMPL_LINK(FontSizeBox, ReformatHdl, weld::Widget&, rWidget, void)void FontSizeBox::LinkStubReformatHdl(void * instance, weld::
Widget& data) { return static_cast<FontSizeBox *>(instance
)->ReformatHdl(data); } void FontSizeBox::ReformatHdl(weld
::Widget& rWidget)
1018{
1019 FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1020 if (!bRelativeMode || !aFontSizeNames.IsEmpty())
1021 {
1022 if (aFontSizeNames.Name2Size(m_xComboBox->get_active_text()) != 0)
1023 return;
1024 }
1025
1026 set_value(get_value());
1027
1028 m_aFocusOutHdl.Call(rWidget);
1029}
1030
1031IMPL_LINK(FontSizeBox, ModifyHdl, weld::ComboBox&, rBox, void)void FontSizeBox::LinkStubModifyHdl(void * instance, weld::ComboBox
& data) { return static_cast<FontSizeBox *>(instance
)->ModifyHdl(data); } void FontSizeBox::ModifyHdl(weld::ComboBox
& rBox)
1032{
1033 if (bRelativeMode)
1034 {
1035 OUString aStr = comphelper::string::stripStart(rBox.get_active_text(), ' ');
1036
1037 bool bNewMode = bRelative;
1038 bool bOldPtRelMode = bPtRelative;
1039
1040 if ( bRelative )
1041 {
1042 bPtRelative = false;
1043 const sal_Unicode* pStr = aStr.getStr();
1044 while ( *pStr )
1045 {
1046 if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') && !unicode::isSpace(*pStr) )
1047 {
1048 if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative )
1049 bPtRelative = true;
1050 else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr )
1051 ;
1052 else
1053 {
1054 bNewMode = false;
1055 break;
1056 }
1057 }
1058 pStr++;
1059 }
1060 }
1061 else if (!aStr.isEmpty())
1062 {
1063 if ( -1 != aStr.indexOf('%') )
1064 {
1065 bNewMode = true;
1066 bPtRelative = false;
1067 }
1068
1069 if ( '-' == aStr[0] || '+' == aStr[0] )
1070 {
1071 bNewMode = true;
1072 bPtRelative = true;
1073 }
1074 }
1075
1076 if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode )
1077 SetRelative( bNewMode );
1078 }
1079 m_aChangeHdl.Call(rBox);
1080}
1081
1082void FontSizeBox::Fill( const FontMetric* pFontMetric, const FontList* pList )
1083{
1084 // remember for relative mode
1085 pFontList = pList;
1086
1087 // no font sizes need to be set for relative mode
1088 if ( bRelative )
1089 return;
1090
1091 // query font sizes
1092 const int* pTempAry;
1093 const int* pAry = nullptr;
1094
1095 if( pFontMetric )
1096 {
1097 aFontMetric = *pFontMetric;
1098 pAry = pList->GetSizeAry( *pFontMetric );
1099 }
1100 else
1101 {
1102 pAry = FontList::GetStdSizeAry();
1103 }
1104
1105 // first insert font size names (for simplified/traditional chinese)
1106 FontSizeNames aFontSizeNames( Application::GetSettings().GetUILanguageTag().getLanguageType() );
1107 if ( pAry == FontList::GetStdSizeAry() )
1108 {
1109 // for standard sizes we don't need to bother
1110 if (bStdSize && m_xComboBox->get_count() && aFontSizeNames.IsEmpty())
1111 return;
1112 bStdSize = true;
1113 }
1114 else
1115 bStdSize = false;
1116
1117 int nSelectionStart, nSelectionEnd;
1118 m_xComboBox->get_entry_selection_bounds(nSelectionStart, nSelectionEnd);
1119 OUString aStr = m_xComboBox->get_active_text();
1120
1121 m_xComboBox->freeze();
1122 m_xComboBox->clear();
1123 int nPos = 0;
1124
1125 if ( !aFontSizeNames.IsEmpty() )
1126 {
1127 if ( pAry == FontList::GetStdSizeAry() )
1128 {
1129 // for scalable fonts all font size names
1130 sal_uLong nCount = aFontSizeNames.Count();
1131 for( sal_uLong i = 0; i < nCount; i++ )
1132 {
1133 OUString aSizeName = aFontSizeNames.GetIndexName( i );
1134 int nSize = aFontSizeNames.GetIndexSize( i );
1135 OUString sId(OUString::number(-nSize)); // mark as special
1136 m_xComboBox->insert(nPos, aSizeName, &sId, nullptr, nullptr);
1137 nPos++;
1138 }
1139 }
1140 else
1141 {
1142 // for fixed size fonts only selectable font size names
1143 pTempAry = pAry;
1144 while ( *pTempAry )
1145 {
1146 OUString aSizeName = aFontSizeNames.Size2Name( *pTempAry );
1147 if ( !aSizeName.isEmpty() )
1148 {
1149 OUString sId(OUString::number(-(*pTempAry))); // mark as special
1150 m_xComboBox->insert(nPos, aSizeName, &sId, nullptr, nullptr);
1151 nPos++;
1152 }
1153 pTempAry++;
1154 }
1155 }
1156 }
1157
1158 // then insert numerical font size values
1159 pTempAry = pAry;
1160 while (*pTempAry)
1161 {
1162 InsertValue(*pTempAry);
1163 ++pTempAry;
1164 }
1165
1166 set_active_or_entry_text(aStr);
1167 m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
1168 m_xComboBox->thaw();
1169}
1170
1171void FontSizeBox::EnableRelativeMode( sal_uInt16 nNewMin, sal_uInt16 nNewMax, sal_uInt16 nStep )
1172{
1173 bRelativeMode = true;
1174 nRelMin = nNewMin;
1175 nRelMax = nNewMax;
1176 nRelStep = nStep;
1177 SetUnit(FieldUnit::POINT);
1178}
1179
1180void FontSizeBox::EnablePtRelativeMode( short nNewMin, short nNewMax, short nStep )
1181{
1182 bRelativeMode = true;
1183 nPtRelMin = nNewMin;
1184 nPtRelMax = nNewMax;
1185 nPtRelStep = nStep;
1186 SetUnit(FieldUnit::POINT);
1187}
1188
1189void FontSizeBox::InsertValue(int i)
1190{
1191 OUString sNumber(OUString::number(i));
1192 m_xComboBox->append(sNumber, format_number(i));
1193}
1194
1195void FontSizeBox::SetRelative( bool bNewRelative )
1196{
1197 if ( !bRelativeMode )
1198 return;
1199
1200 int nSelectionStart, nSelectionEnd;
1201 m_xComboBox->get_entry_selection_bounds(nSelectionStart, nSelectionEnd);
1202 OUString aStr = comphelper::string::stripStart(m_xComboBox->get_active_text(), ' ');
1203
1204 if (bNewRelative)
1205 {
1206 bRelative = true;
1207 bStdSize = false;
1208
1209 m_xComboBox->clear();
1210
1211 if (bPtRelative)
1212 {
1213 SetDecimalDigits( 1 );
1214 SetRange(nPtRelMin, nPtRelMax);
1215 SetUnit(FieldUnit::POINT);
1216
1217 short i = nPtRelMin, n = 0;
1218 // JP 30.06.98: more than 100 values are not useful
1219 while ( i <= nPtRelMax && n++ < 100 )
1220 {
1221 InsertValue( i );
1222 i = i + nPtRelStep;
1223 }
1224 }
1225 else
1226 {
1227 SetDecimalDigits(0);
1228 SetRange(nRelMin, nRelMax);
1229 SetUnit(FieldUnit::PERCENT);
1230
1231 sal_uInt16 i = nRelMin;
1232 while ( i <= nRelMax )
1233 {
1234 InsertValue( i );
1235 i = i + nRelStep;
1236 }
1237 }
1238 }
1239 else
1240 {
1241 if (pFontList)
1242 m_xComboBox->clear();
1243 bRelative = bPtRelative = false;
1244 SetDecimalDigits(1);
1245 SetRange(20, 9999);
1246 SetUnit(FieldUnit::POINT);
1247 if ( pFontList)
1248 Fill( &aFontMetric, pFontList );
1249 }
1250
1251 set_active_or_entry_text(aStr);
1252 m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
1253}
1254
1255OUString FontSizeBox::format_number(int nValue) const
1256{
1257 OUString sRet;
1258
1259 //pawn percent off to icu to decide whether percent is separated from its number for this locale
1260 if (eUnit == FieldUnit::PERCENT)
1261 {
1262 double fValue = nValue;
1263 fValue /= weld::SpinButton::Power10(nDecimalDigits);
1264 sRet = unicode::formatPercent(fValue, Application::GetSettings().GetUILanguageTag());
1265 }
1266 else
1267 {
1268 const SvtSysLocale aSysLocale;
1269 const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
1270 sRet = rLocaleData.getNum(nValue, nDecimalDigits, true, false);
1271 if (eUnit != FieldUnit::NONE && eUnit != FieldUnit::DEGREE)
1272 sRet += " ";
1273 assert(eUnit != FieldUnit::PERCENT)(static_cast <bool> (eUnit != FieldUnit::PERCENT) ? void
(0) : __assert_fail ("eUnit != FieldUnit::PERCENT", "/home/maarten/src/libreoffice/core/svtools/source/control/ctrlbox.cxx"
, 1273, __extension__ __PRETTY_FUNCTION__))
;
1274 sRet += weld::MetricSpinButton::MetricToString(eUnit);
1275 }
1276
1277 if (bRelativeMode && bPtRelative && (0 <= nValue) && !sRet.isEmpty())
1278 sRet = "+" + sRet;
1279
1280 return sRet;
1281}
1282
1283void FontSizeBox::SetValue(int nNewValue, FieldUnit eInUnit)
1284{
1285 auto nTempValue = vcl::ConvertValue(nNewValue, 0, GetDecimalDigits(), eInUnit, GetUnit());
1286 if (nTempValue < nMin)
1287 nTempValue = nMin;
1288 else if (nTempValue > nMax)
1289 nTempValue = nMax;
1290 if (!bRelative)
1291 {
1292 FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1293 // conversion loses precision; however font sizes should
1294 // never have a problem with that
1295 OUString aName = aFontSizeNames.Size2Name(nTempValue);
1296 if (!aName.isEmpty() && m_xComboBox->find_text(aName) != -1)
1297 {
1298 m_xComboBox->set_active_text(aName);
1299 return;
1300 }
1301 }
1302 OUString aResult = format_number(nTempValue);
1303 set_active_or_entry_text(aResult);
1304}
1305
1306void FontSizeBox::set_value(int nNewValue)
1307{
1308 SetValue(nNewValue, eUnit);
1309}
1310
1311int FontSizeBox::get_value() const
1312{
1313 OUString aStr = m_xComboBox->get_active_text();
1314 if (!bRelative)
1315 {
1316 FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1317 auto nValue = aFontSizeNames.Name2Size(aStr);
1318 if (nValue)
1319 return vcl::ConvertValue(nValue, 0, GetDecimalDigits(), GetUnit(), GetUnit());
1320 }
1321
1322 const SvtSysLocale aSysLocale;
1323 const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
1324 double fResult(0.0);
1325 (void)vcl::TextToValue(aStr, fResult, 0, GetDecimalDigits(), rLocaleData, GetUnit());
1326 if (!aStr.isEmpty())
1327 {
1328 if (fResult < nMin)
1329 fResult = nMin;
1330 else if (fResult > nMax)
1331 fResult = nMax;
1332 }
1333 return fResult;
1334}
1335
1336SvxBorderLineStyle SvtLineListBox::GetSelectEntryStyle() const
1337{
1338 if (m_xLineSet->IsNoSelection())
1339 return SvxBorderLineStyle::NONE;
1340 auto nId = m_xLineSet->GetSelectedItemId();
1341 return static_cast<SvxBorderLineStyle>(nId - 1);
1342}
1343
1344namespace
1345{
1346 Size getPreviewSize(const weld::Widget& rControl)
1347 {
1348 return Size(rControl.get_approximate_digit_width() * 15, rControl.get_text_height());
1349 }
1350}
1351
1352void SvtLineListBox::ImpGetLine( long nLine1, long nLine2, long nDistance,
1353 Color aColor1, Color aColor2, Color aColorDist,
1354 SvxBorderLineStyle nStyle, BitmapEx& rBmp )
1355{
1356 Size aSize(getPreviewSize(*m_xControl));
1357
1358 // SourceUnit to Twips
1359 if ( eSourceUnit == FieldUnit::POINT )
1360 {
1361 nLine1 /= 5;
1362 nLine2 /= 5;
1363 nDistance /= 5;
1364 }
1365
1366 // Paint the lines
1367 aSize = aVirDev->PixelToLogic( aSize );
1368 long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
1369 sal_uInt32 n1 = nLine1;
1370 sal_uInt32 n2 = nLine2;
1371 long nDist = nDistance;
1372 n1 += nPix-1;
1373 n1 -= n1%nPix;
1374 if ( n2 )
1375 {
1376 nDist += nPix-1;
1377 nDist -= nDist%nPix;
1378 n2 += nPix-1;
1379 n2 -= n2%nPix;
1380 }
1381 long nVirHeight = n1+nDist+n2;
1382 if ( nVirHeight > aSize.Height() )
1383 aSize.setHeight( nVirHeight );
1384 // negative width should not be drawn
1385 if ( aSize.Width() <= 0 )
1386 return;
1387
1388 Size aVirSize = aVirDev->LogicToPixel( aSize );
1389 if ( aVirDev->GetOutputSizePixel() != aVirSize )
1390 aVirDev->SetOutputSizePixel( aVirSize );
1391 aVirDev->SetFillColor( aColorDist );
1392 aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
1393
1394 aVirDev->SetFillColor( aColor1 );
1395
1396 double y1 = double( n1 ) / 2;
1397 svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
1398
1399 if ( n2 )
1400 {
1401 double y2 = n1 + nDist + double( n2 ) / 2;
1402 aVirDev->SetFillColor( aColor2 );
1403 svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
1404 }
1405 rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
1406}
1407
1408namespace
1409{
1410 OUString GetLineStyleName(SvxBorderLineStyle eStyle)
1411 {
1412 OUString sRet;
1413 for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE)(sizeof(sal_n_array_size(RID_SVXSTR_BORDERLINE))); ++i)
1414 {
1415 if (eStyle == RID_SVXSTR_BORDERLINE[i].second)
1416 {
1417 sRet = SvtResId(RID_SVXSTR_BORDERLINE[i].first);
1418 break;
1419 }
1420 }
1421 return sRet;
1422 }
1423}
1424
1425SvtLineListBox::SvtLineListBox(std::unique_ptr<weld::MenuButton> pControl)
1426 : m_xControl(std::move(pControl))
1427 , m_xBuilder(Application::CreateBuilder(m_xControl.get(), "svt/ui/linewindow.ui"))
1428 , m_xTopLevel(m_xBuilder->weld_widget("line_popup_window"))
1429 , m_xNoneButton(m_xBuilder->weld_button("none_line_button"))
1430 , m_xLineSet(new ValueSet(nullptr))
1431 , m_xLineSetWin(new weld::CustomWeld(*m_xBuilder, "lineset", *m_xLineSet))
1432 , m_nWidth( 5 )
1433 , aVirDev(VclPtr<VirtualDevice>::Create())
1434 , aColor(COL_BLACK)
1435 , maPaintCol(COL_BLACK)
1436{
1437 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1438 m_xLineSet->SetStyle(WinBits(WB_FLATVALUESET(WinBits(0x02000000)) | WB_NO_DIRECTSELECT(WinBits(0x04000000)) | WB_TABSTOP));
1439 m_xLineSet->SetItemHeight(rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1);
1440 m_xLineSet->SetColCount(1);
1441 m_xLineSet->SetSelectHdl(LINK(this, SvtLineListBox, ValueSelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<SvtLineListBox
*>(this), &SvtLineListBox::LinkStubValueSelectHdl)
);
1442
1443 m_xNoneButton->connect_clicked(LINK(this, SvtLineListBox, NoneHdl)::tools::detail::makeLink( ::tools::detail::castTo<SvtLineListBox
*>(this), &SvtLineListBox::LinkStubNoneHdl)
);
1444
1445 m_xTopLevel->connect_focus_in(LINK(this, SvtLineListBox, FocusHdl)::tools::detail::makeLink( ::tools::detail::castTo<SvtLineListBox
*>(this), &SvtLineListBox::LinkStubFocusHdl)
);
1446 m_xControl->set_popover(m_xTopLevel.get());
1447 m_xControl->connect_toggled(LINK(this, SvtLineListBox, ToggleHdl)::tools::detail::makeLink( ::tools::detail::castTo<SvtLineListBox
*>(this), &SvtLineListBox::LinkStubToggleHdl)
);
1448
1449 // lock size to these maxes height/width so it doesn't jump around in size
1450 m_xControl->set_label(GetLineStyleName(SvxBorderLineStyle::NONE));
1451 Size aNonePrefSize = m_xControl->get_preferred_size();
1452 m_xControl->set_label("");
1453 aVirDev->SetOutputSizePixel(getPreviewSize(*m_xControl));
1454 m_xControl->set_image(aVirDev);
1455 Size aSolidPrefSize = m_xControl->get_preferred_size();
1456 m_xControl->set_size_request(std::max(aNonePrefSize.Width(), aSolidPrefSize.Width()),
1457 std::max(aNonePrefSize.Height(), aSolidPrefSize.Height()));
1458
1459 eSourceUnit = FieldUnit::POINT;
1460
1461 aVirDev->SetLineColor();
1462 aVirDev->SetMapMode(MapMode(MapUnit::MapTwip));
1463
1464 UpdatePaintLineColor();
1465}
1466
1467IMPL_LINK_NOARG(SvtLineListBox, FocusHdl, weld::Widget&, void)void SvtLineListBox::LinkStubFocusHdl(void * instance, weld::
Widget& data) { return static_cast<SvtLineListBox *>
(instance)->FocusHdl(data); } void SvtLineListBox::FocusHdl
(__attribute__ ((unused)) weld::Widget&)
1468{
1469 if (GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
1470 m_xNoneButton->grab_focus();
1471 else
1472 m_xLineSet->GrabFocus();
1473}
1474
1475IMPL_LINK(SvtLineListBox, ToggleHdl, weld::ToggleButton&, rButton, void)void SvtLineListBox::LinkStubToggleHdl(void * instance, weld::
ToggleButton& data) { return static_cast<SvtLineListBox
*>(instance)->ToggleHdl(data); } void SvtLineListBox::
ToggleHdl(weld::ToggleButton& rButton)
1476{
1477 if (rButton.get_active())
1478 FocusHdl(*m_xTopLevel);
1479}
1480
1481IMPL_LINK_NOARG(SvtLineListBox, NoneHdl, weld::Button&, void)void SvtLineListBox::LinkStubNoneHdl(void * instance, weld::Button
& data) { return static_cast<SvtLineListBox *>(instance
)->NoneHdl(data); } void SvtLineListBox::NoneHdl(__attribute__
((unused)) weld::Button&)
1482{
1483 SelectEntry(SvxBorderLineStyle::NONE);
1484 ValueSelectHdl(nullptr);
1485}
1486
1487SvtLineListBox::~SvtLineListBox()
1488{
1489}
1
Calling '~ScopedVclPtr'
1490
1491sal_Int32 SvtLineListBox::GetStylePos( sal_Int32 nListPos )
1492{
1493 sal_Int32 nPos = -1;
1494 --nListPos;
1495
1496 sal_Int32 n = 0;
1497 size_t i = 0;
1498 size_t nCount = m_vLineList.size();
1499 while ( nPos == -1 && i < nCount )
1500 {
1501 if ( nListPos == n )
1502 nPos = static_cast<sal_Int32>(i);
1503 n++;
1504 i++;
1505 }
1506
1507 return nPos;
1508}
1509
1510void SvtLineListBox::SelectEntry(SvxBorderLineStyle nStyle)
1511{
1512 if (nStyle == SvxBorderLineStyle::NONE)
1513 m_xLineSet->SetNoSelection();
1514 else
1515 m_xLineSet->SelectItem(static_cast<sal_Int16>(nStyle) + 1);
1516 UpdatePreview();
1517}
1518
1519void SvtLineListBox::InsertEntry(
1520 const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, long nMinWidth,
1521 ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
1522{
1523 m_vLineList.emplace_back(new ImpLineListData(
1524 rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
1525}
1526
1527void SvtLineListBox::UpdatePaintLineColor()
1528{
1529 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
1530 Color aNewCol(rSettings.GetWindowColor().IsDark() ? rSettings.GetLabelTextColor() : aColor);
1531
1532 bool bRet = aNewCol != maPaintCol;
1533
1534 if( bRet )
1535 maPaintCol = aNewCol;
1536}
1537
1538void SvtLineListBox::UpdateEntries()
1539{
1540 UpdatePaintLineColor( );
1541
1542 SvxBorderLineStyle eSelected = GetSelectEntryStyle();
1543
1544 // Remove the old entries
1545 m_xLineSet->Clear();
1546
1547 // Add the new entries based on the defined width
1548
1549 sal_uInt16 n = 0;
1550 sal_uInt16 nCount = m_vLineList.size( );
1551 while ( n < nCount )
1552 {
1553 auto& pData = m_vLineList[ n ];
1554 BitmapEx aBmp;
1555 ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
1556 pData->GetLine2ForWidth( m_nWidth ),
1557 pData->GetDistForWidth( m_nWidth ),
1558 GetColorLine1(m_xLineSet->GetItemCount()),
1559 GetColorLine2(m_xLineSet->GetItemCount()),
1560 GetColorDist(m_xLineSet->GetItemCount()),
1561 pData->GetStyle(), aBmp );
1562 sal_Int16 nItemId = static_cast<sal_Int16>(pData->GetStyle()) + 1;
1563 m_xLineSet->InsertItem(nItemId, Image(aBmp), GetLineStyleName(pData->GetStyle()));
1564 if (pData->GetStyle() == eSelected)
1565 m_xLineSet->SelectItem(nItemId);
1566 n++;
1567 }
1568
1569 m_xLineSet->SetOptimalSize();
1570}
1571
1572Color SvtLineListBox::GetColorLine1( sal_Int32 nPos )
1573{
1574 sal_Int32 nStyle = GetStylePos( nPos );
1575 if (nStyle == -1)
1576 return GetPaintColor( );
1577 auto& pData = m_vLineList[ nStyle ];
1578 return pData->GetColorLine1( GetColor( ) );
1579}
1580
1581Color SvtLineListBox::GetColorLine2( sal_Int32 nPos )
1582{
1583 sal_Int32 nStyle = GetStylePos(nPos);
1584 if (nStyle == -1)
1585 return GetPaintColor( );
1586 auto& pData = m_vLineList[ nStyle ];
1587 return pData->GetColorLine2( GetColor( ) );
1588}
1589
1590Color SvtLineListBox::GetColorDist( sal_Int32 nPos )
1591{
1592 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
1593 Color rResult = rSettings.GetFieldColor();
1594
1595 sal_Int32 nStyle = GetStylePos( nPos );
1596 if (nStyle == -1)
1597 return rResult;
1598 auto& pData = m_vLineList[ nStyle ];
1599 return pData->GetColorDist( GetColor( ), rResult );
1600}
1601
1602IMPL_LINK_NOARG(SvtLineListBox, ValueSelectHdl, ValueSet*, void)void SvtLineListBox::LinkStubValueSelectHdl(void * instance, ValueSet
* data) { return static_cast<SvtLineListBox *>(instance
)->ValueSelectHdl(data); } void SvtLineListBox::ValueSelectHdl
(__attribute__ ((unused)) ValueSet*)
1603{
1604 maSelectHdl.Call(*this);
1605 UpdatePreview();
1606 if (m_xControl->get_active())
1607 m_xControl->set_active(false);
1608}
1609
1610void SvtLineListBox::UpdatePreview()
1611{
1612 SvxBorderLineStyle eStyle = GetSelectEntryStyle();
1613 for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE)(sizeof(sal_n_array_size(RID_SVXSTR_BORDERLINE))); ++i)
1614 {
1615 if (eStyle == RID_SVXSTR_BORDERLINE[i].second)
1616 {
1617 m_xControl->set_label(SvtResId(RID_SVXSTR_BORDERLINE[i].first));
1618 break;
1619 }
1620 }
1621
1622 if (eStyle == SvxBorderLineStyle::NONE)
1623 {
1624 m_xControl->set_image(nullptr);
1625 m_xControl->set_label(GetLineStyleName(SvxBorderLineStyle::NONE));
1626 }
1627 else
1628 {
1629 Image aImage(m_xLineSet->GetItemImage(m_xLineSet->GetSelectedItemId()));
1630 m_xControl->set_label("");
1631 const auto nPos = (aVirDev->GetOutputSizePixel().Height() - aImage.GetSizePixel().Height()) / 2;
1632 aVirDev->Push(PushFlags::MAPMODE);
1633 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1634 aVirDev->Erase();
1635 aVirDev->DrawImage(Point(0, nPos), aImage);
1636 m_xControl->set_image(aVirDev.get());
1637 aVirDev->Pop();
1638 }
1639}
1640
1641SvtCalendarBox::SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl)
1642 : m_xControl(std::move(pControl))
1643 , m_xBuilder(Application::CreateBuilder(m_xControl.get(), "svt/ui/datewindow.ui"))
1644 , m_xTopLevel(m_xBuilder->weld_widget("date_popup_window"))
1645 , m_xCalendar(m_xBuilder->weld_calendar("date"))
1646{
1647 m_xControl->set_popover(m_xTopLevel.get());
1648 m_xCalendar->connect_selected(LINK(this, SvtCalendarBox, SelectHdl)::tools::detail::makeLink( ::tools::detail::castTo<SvtCalendarBox
*>(this), &SvtCalendarBox::LinkStubSelectHdl)
);
1649 m_xCalendar->connect_activated(LINK(this, SvtCalendarBox, ActivateHdl)::tools::detail::makeLink( ::tools::detail::castTo<SvtCalendarBox
*>(this), &SvtCalendarBox::LinkStubActivateHdl)
);
1650}
1651
1652void SvtCalendarBox::set_date(const Date& rDate)
1653{
1654 m_xCalendar->set_date(rDate);
1655 set_label_from_date();
1656}
1657
1658void SvtCalendarBox::set_label_from_date()
1659{
1660 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
1661 m_xControl->set_label(rLocaleData.getDate(m_xCalendar->get_date()));
1662}
1663
1664IMPL_LINK_NOARG(SvtCalendarBox, SelectHdl, weld::Calendar&, void)void SvtCalendarBox::LinkStubSelectHdl(void * instance, weld::
Calendar& data) { return static_cast<SvtCalendarBox *>
(instance)->SelectHdl(data); } void SvtCalendarBox::SelectHdl
(__attribute__ ((unused)) weld::Calendar&)
1665{
1666 set_label_from_date();
1667 m_aSelectHdl.Call(*this);
1668}
1669
1670IMPL_LINK_NOARG(SvtCalendarBox, ActivateHdl, weld::Calendar&, void)void SvtCalendarBox::LinkStubActivateHdl(void * instance, weld
::Calendar& data) { return static_cast<SvtCalendarBox *
>(instance)->ActivateHdl(data); } void SvtCalendarBox::
ActivateHdl(__attribute__ ((unused)) weld::Calendar&)
1671{
1672 if (m_xControl->get_active())
1673 m_xControl->set_active(false);
1674 m_aActivatedHdl.Call(*this);
1675}
1676
1677SvtCalendarBox::~SvtCalendarBox()
1678{
1679}
1680
1681/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
3
Calling copy constructor for 'Reference<VirtualDevice>'
6
Returning from copy constructor for 'Reference<VirtualDevice>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
7
Calling 'Reference::clear'
14
Returning; memory was released
205 if (aTmp.get()) {
15
Calling 'Reference::get'
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
2
Calling 'VclPtr::disposeAndClear'
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
4
Assuming field 'm_pBody' is non-null
5
Taking true branch
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody)
113 m_pBody->release();
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld)
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
7.1
Field 'm_pBody' is non-null
)
8
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
9
Calling 'VclReferenceBase::release'
13
Returning; memory was released
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
16
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
10
Assuming the condition is true
11
Taking true branch
40 delete this;
12
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif