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 svgwriter.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 -isystem /usr/include/libxml2 -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 BOOST_ALL_NO_LIB -D USE_MODERN_SPIRIT -D FILTER_DLLIMPLEMENTATION -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -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/filter/source/svg -I /home/maarten/src/libreoffice/core/filter/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -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/filter/source/svg/svgwriter.cxx

/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.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 "svgfilter.hxx"
21#include "svgfontexport.hxx"
22#include "svgwriter.hxx"
23
24#include <comphelper/base64.hxx>
25#include <cppuhelper/supportsservice.hxx>
26#include <sal/log.hxx>
27#include <vcl/unohelp.hxx>
28#include <vcl/cvtgrf.hxx>
29#include <vcl/metric.hxx>
30#include <vcl/outdev.hxx>
31#include <vcl/settings.hxx>
32#include <tools/fract.hxx>
33#include <tools/helpers.hxx>
34#include <tools/stream.hxx>
35#include <xmloff/namespacemap.hxx>
36#include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
37#include <i18nlangtag/languagetag.hxx>
38#include <svx/unoshape.hxx>
39#include <svx/svdograf.hxx>
40
41#include <com/sun/star/container/XEnumerationAccess.hpp>
42#include <com/sun/star/container/XIndexReplace.hpp>
43#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
44#include <com/sun/star/i18n/XBreakIterator.hpp>
45#include <com/sun/star/style/NumberingType.hpp>
46#include <com/sun/star/text/XTextField.hpp>
47
48#include <memory>
49
50
51const char aPrefixClipPathId[] = "clip_path_";
52
53const char aXMLElemG[] = "g";
54const char aXMLElemDefs[] = "defs";
55const char aXMLElemText[] = "text";
56const char aXMLElemTspan[] = "tspan";
57const char aXMLElemLinearGradient[] = "linearGradient";
58const char aXMLElemStop[] = "stop";
59
60const char aXMLAttrTransform[] = "transform";
61const char aXMLAttrStyle[] = "style";
62const char aXMLAttrId[] = "id";
63const char aXMLAttrX[] = "x";
64const char aXMLAttrY[] = "y";
65const char aXMLAttrX1[] = "x1";
66const char aXMLAttrY1[] = "y1";
67const char aXMLAttrX2[] = "x2";
68const char aXMLAttrY2[] = "y2";
69const char aXMLAttrCX[] = "cx";
70const char aXMLAttrCY[] = "cy";
71const char aXMLAttrRX[] = "rx";
72const char aXMLAttrRY[] = "ry";
73const char aXMLAttrWidth[] = "width";
74const char aXMLAttrHeight[] = "height";
75const char aXMLAttrStrokeWidth[] = "stroke-width";
76const char aXMLAttrFill[] = "fill";
77const char aXMLAttrFontFamily[] = "font-family";
78const char aXMLAttrFontSize[] = "font-size";
79const char aXMLAttrFontStyle[] = "font-style";
80const char aXMLAttrFontWeight[] = "font-weight";
81const char aXMLAttrTextDecoration[] = "text-decoration";
82const char aXMLAttrXLinkHRef[] = "xlink:href";
83const char aXMLAttrGradientUnits[] = "gradientUnits";
84const char aXMLAttrOffset[] = "offset";
85const char aXMLAttrStopColor[] = "stop-color";
86const char aXMLAttrStrokeLinejoin[] = "stroke-linejoin";
87const char aXMLAttrStrokeLinecap[] = "stroke-linecap";
88
89
90PushFlags SVGContextHandler::getPushFlags() const
91{
92 if (maStateStack.empty())
93 return PushFlags::NONE;
94
95 const PartialState& rPartialState = maStateStack.top();
96 return rPartialState.meFlags;
97}
98
99SVGState& SVGContextHandler::getCurrentState()
100{
101 return maCurrentState;
102}
103
104void SVGContextHandler::pushState( PushFlags eFlags )
105{
106 PartialState aPartialState;
107 aPartialState.meFlags = eFlags;
108
109 if (eFlags & PushFlags::FONT)
110 {
111 aPartialState.setFont( maCurrentState.aFont );
112 }
113
114 if (eFlags & PushFlags::CLIPREGION)
115 {
116 aPartialState.mnRegionClipPathId = maCurrentState.nRegionClipPathId;
117 }
118
119 maStateStack.push( std::move(aPartialState) );
120}
121
122void SVGContextHandler::popState()
123{
124 if (maStateStack.empty())
125 return;
126
127 const PartialState& rPartialState = maStateStack.top();
128 PushFlags eFlags = rPartialState.meFlags;
129
130 if (eFlags & PushFlags::FONT)
131 {
132 maCurrentState.aFont = rPartialState.getFont( vcl::Font() );
133 }
134
135 if (eFlags & PushFlags::CLIPREGION)
136 {
137 maCurrentState.nRegionClipPathId = rPartialState.mnRegionClipPathId;
138 }
139
140 maStateStack.pop();
141}
142
143SVGAttributeWriter::SVGAttributeWriter( SVGExport& rExport, SVGFontExport& rFontExport, SVGState& rCurState )
144 : mrExport( rExport )
145 , mrFontExport( rFontExport )
146 , mrCurrentState( rCurState )
147{
148}
149
150
151SVGAttributeWriter::~SVGAttributeWriter()
152{
153}
154
155
156double SVGAttributeWriter::ImplRound( double fValue )
157{
158 return floor( fValue * pow( 10.0, 3 ) + 0.5 ) / pow( 10.0, 3 );
159}
160
161
162void SVGAttributeWriter::ImplGetColorStr( const Color& rColor, OUString& rColorStr )
163{
164 if( rColor.GetTransparency() == 255 )
165 rColorStr = "none";
166 else
167 {
168 rColorStr = "rgb(" + OUString::number(rColor.GetRed()) + "," + OUString::number(rColor.GetGreen()) +
169 "," + OUString::number(rColor.GetBlue()) + ")";
170 }
171}
172
173
174void SVGAttributeWriter::AddColorAttr( const char* pColorAttrName,
175 const char* pColorOpacityAttrName,
176 const Color& rColor )
177{
178 OUString aColor, aColorOpacity;
179
180 ImplGetColorStr( rColor, aColor );
181
182 if( rColor.GetTransparency() > 0 && rColor.GetTransparency() < 255 )
183 aColorOpacity = OUString::number( ImplRound( ( 255.0 - rColor.GetTransparency() ) / 255.0 ) );
184
185 mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorAttrName, aColor );
186
187 if( !aColorOpacity.isEmpty() && mrExport.IsUseOpacity() )
188 mrExport.AddAttribute( XML_NAMESPACE_NONE, pColorOpacityAttrName, aColorOpacity );
189}
190
191
192void SVGAttributeWriter::AddPaintAttr( const Color& rLineColor, const Color& rFillColor,
193 const tools::Rectangle* pObjBoundRect, const Gradient* pFillGradient )
194{
195 // Fill
196 if( pObjBoundRect && pFillGradient )
197 {
198 OUString aGradientId;
199
200 AddGradientDef( *pObjBoundRect, *pFillGradient, aGradientId );
201
202 if( !aGradientId.isEmpty() )
203 {
204 OUString aGradientURL = "url(#" + aGradientId + ")";
205 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFill, aGradientURL );
206 }
207 }
208 else
209 AddColorAttr( aXMLAttrFill, "fill-opacity", rFillColor );
210
211 // Stroke
212 AddColorAttr( "stroke", "stroke-opacity", rLineColor );
213}
214
215
216void SVGAttributeWriter::AddGradientDef( const tools::Rectangle& rObjRect, const Gradient& rGradient, OUString& rGradientId )
217{
218 if( rObjRect.GetWidth() && rObjRect.GetHeight() &&
219 ( rGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial ||
220 rGradient.GetStyle() == GradientStyle::Radial || rGradient.GetStyle() == GradientStyle::Elliptical ) )
221 {
222 SvXMLElementExport aDesc( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true );
223 Color aStartColor( rGradient.GetStartColor() ), aEndColor( rGradient.GetEndColor() );
224 sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
225 Point aObjRectCenter( rObjRect.Center() );
226 tools::Polygon aPoly( rObjRect );
227 static sal_Int32 nCurGradientId = 1;
228
229 aPoly.Rotate( aObjRectCenter, nAngle );
230 tools::Rectangle aRect( aPoly.GetBoundRect() );
231
232 // adjust start/end colors with intensities
233 aStartColor.SetRed( static_cast<sal_uInt8>( ( aStartColor.GetRed() * rGradient.GetStartIntensity() ) / 100 ) );
234 aStartColor.SetGreen( static_cast<sal_uInt8>( ( aStartColor.GetGreen() * rGradient.GetStartIntensity() ) / 100 ) );
235 aStartColor.SetBlue( static_cast<sal_uInt8>( ( aStartColor.GetBlue() * rGradient.GetStartIntensity() ) / 100 ) );
236
237 aEndColor.SetRed( static_cast<sal_uInt8>( ( aEndColor.GetRed() * rGradient.GetEndIntensity() ) / 100 ) );
238 aEndColor.SetGreen( static_cast<sal_uInt8>( ( aEndColor.GetGreen() * rGradient.GetEndIntensity() ) / 100 ) );
239 aEndColor.SetBlue( static_cast<sal_uInt8>( ( aEndColor.GetBlue() * rGradient.GetEndIntensity() ) / 100 ) );
240
241 rGradientId = "Gradient_" + OUString::number( nCurGradientId++ );
242 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, rGradientId );
243
244 {
245 std::unique_ptr< SvXMLElementExport > apGradient;
246 OUString aColorStr;
247
248 if( rGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() == GradientStyle::Axial )
249 {
250 tools::Polygon aLinePoly( 2 );
251
252 aLinePoly[ 0 ] = Point( aObjRectCenter.X(), aRect.Top() );
253 aLinePoly[ 1 ] = Point( aObjRectCenter.X(), aRect.Bottom() );
254
255 aLinePoly.Rotate( aObjRectCenter, nAngle );
256
257 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, "userSpaceOnUse" );
258 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::number( aLinePoly[ 0 ].X() ) );
259 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::number( aLinePoly[ 0 ].Y() ) );
260 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::number( aLinePoly[ 1 ].X() ) );
261 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::number( aLinePoly[ 1 ].Y() ) );
262
263 apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, true, true ) );
264
265 // write stop values
266 double fBorder = static_cast< double >( rGradient.GetBorder() ) *
267 ( ( rGradient.GetStyle() == GradientStyle::Axial ) ? 0.005 : 0.01 );
268
269 ImplGetColorStr( ( rGradient.GetStyle() == GradientStyle::Axial ) ? aEndColor : aStartColor, aColorStr );
270 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::number( fBorder ) );
271 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
272
273 {
274 SvXMLElementExport aDesc2( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, true, true );
275 }
276
277 if( rGradient.GetStyle() == GradientStyle::Axial )
278 {
279 ImplGetColorStr( aStartColor, aColorStr );
280 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::number( 0.5 ) );
281 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
282
283 {
284 SvXMLElementExport aDesc3( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, true, true );
285 }
286 }
287
288 if( rGradient.GetStyle() != GradientStyle::Axial )
289 fBorder = 0.0;
290
291 ImplGetColorStr( aEndColor, aColorStr );
292 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::number( ImplRound( 1.0 - fBorder ) ) );
293 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
294
295 {
296 SvXMLElementExport aDesc4( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, true, true );
297 }
298 }
299 else
300 {
301 const double fCenterX = rObjRect.Left() + rObjRect.GetWidth() * rGradient.GetOfsX() * 0.01;
302 const double fCenterY = rObjRect.Top() + rObjRect.GetHeight() * rGradient.GetOfsY() * 0.01;
303 const double fRadius = sqrt( static_cast< double >( rObjRect.GetWidth() ) * rObjRect.GetWidth() +
304 rObjRect.GetHeight() * rObjRect.GetHeight() ) * 0.5;
305
306 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits, "userSpaceOnUse" );
307 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, OUString::number( ImplRound( fCenterX ) ) );
308 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, OUString::number( ImplRound( fCenterY ) ) );
309 mrExport.AddAttribute( XML_NAMESPACE_NONE, "r", OUString::number( ImplRound( fRadius ) ) );
310
311 apGradient.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, "radialGradient", true, true ) );
312
313 // write stop values
314 ImplGetColorStr( aEndColor, aColorStr );
315 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::number( 0.0 ) );
316 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
317
318 {
319 SvXMLElementExport aDesc5( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, true, true );
320 }
321
322 ImplGetColorStr( aStartColor, aColorStr );
323 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset,
324 OUString::number( ImplRound( 1.0 - rGradient.GetBorder() * 0.01 ) ) );
325 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStopColor, aColorStr );
326
327 {
328 SvXMLElementExport aDesc6( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, true, true );
329 }
330 }
331 }
332 }
333 else
334 rGradientId.clear();
335}
336
337
338void SVGAttributeWriter::SetFontAttr( const vcl::Font& rFont )
339{
340 vcl::Font& rCurFont = mrCurrentState.aFont;
341
342 if( rFont == rCurFont )
343 return;
344
345 OUString aFontStyle;
346 sal_Int32 nFontWeight;
347
348 rCurFont = rFont;
349
350 // Font Family
351 setFontFamily();
352
353 // Font Size
354 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize,
355 OUString::number( rFont.GetFontHeight() ) + "px" );
356
357 // Font Style
358 if( rFont.GetItalic() != ITALIC_NONE )
359 {
360 if( rFont.GetItalic() == ITALIC_OBLIQUE )
361 aFontStyle = "oblique";
362 else
363 aFontStyle = "italic";
364 }
365 else
366 aFontStyle = "normal";
367
368 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, aFontStyle );
369
370 // Font Weight
371 switch( rFont.GetWeight() )
372 {
373 case WEIGHT_THIN: nFontWeight = 100; break;
374 case WEIGHT_ULTRALIGHT: nFontWeight = 200; break;
375 case WEIGHT_LIGHT: nFontWeight = 300; break;
376 case WEIGHT_SEMILIGHT: nFontWeight = 400; break;
377 case WEIGHT_NORMAL: nFontWeight = 400; break;
378 case WEIGHT_MEDIUM: nFontWeight = 500; break;
379 case WEIGHT_SEMIBOLD: nFontWeight = 600; break;
380 case WEIGHT_BOLD: nFontWeight = 700; break;
381 case WEIGHT_ULTRABOLD: nFontWeight = 800; break;
382 case WEIGHT_BLACK: nFontWeight = 900; break;
383 default: nFontWeight = 400; break;
384 }
385
386 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, OUString::number( nFontWeight ) );
387
388 if( mrExport.IsUseNativeTextDecoration() )
389 {
390 OUString aTextDecoration;
391 if( rFont.GetUnderline() != LINESTYLE_NONE || rFont.GetStrikeout() != STRIKEOUT_NONE )
392 {
393 if( rFont.GetUnderline() != LINESTYLE_NONE )
394 aTextDecoration = "underline ";
395
396 if( rFont.GetStrikeout() != STRIKEOUT_NONE )
397 aTextDecoration += "line-through ";
398 }
399 else
400 aTextDecoration = "none";
401
402 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, aTextDecoration );
403 }
404
405 startFontSettings();
406}
407
408
409void SVGAttributeWriter::startFontSettings()
410{
411 endFontSettings();
412 if( mrExport.IsUsePositionedCharacters() )
413 {
414 mpElemFont.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true ) );
415 }
416 else
417 {
418 mpElemFont.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, true, true ) );
419 }
420}
421
422
423void SVGAttributeWriter::endFontSettings()
424{
425 mpElemFont.reset();
426}
427
428
429void SVGAttributeWriter::setFontFamily()
430{
431 vcl::Font& rCurFont = mrCurrentState.aFont;
432
433 if( mrExport.IsUsePositionedCharacters() )
434 {
435 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, mrFontExport.GetMappedFontName( rCurFont.GetFamilyName() ) );
436 }
437 else
438 {
439 const OUString& rsFontName = rCurFont.GetFamilyName();
440 OUString sFontFamily( rsFontName.getToken( 0, ';' ) );
441 FontPitch ePitch = rCurFont.GetPitch();
442 if( ePitch == PITCH_FIXED )
443 {
444 sFontFamily += ", monospace";
445 }
446 else
447 {
448 FontFamily eFamily = rCurFont.GetFamilyType();
449 if( eFamily == FAMILY_ROMAN )
450 sFontFamily += ", serif";
451 else if( eFamily == FAMILY_SWISS )
452 sFontFamily += ", sans-serif";
453 }
454 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, sFontFamily );
455 }
456}
457
458SVGTextWriter::SVGTextWriter(SVGExport& rExport, SVGAttributeWriter& rAttributeWriter,
459 SVGActionWriter& rActionWriter)
460: mrExport( rExport ),
461 mrAttributeWriter( rAttributeWriter ),
462 mrActionWriter(rActionWriter),
463 mpVDev( nullptr ),
464 mbIsTextShapeStarted( false ),
465 mrTextShape(),
466 msShapeId(),
467 mrParagraphEnumeration(),
468 mrCurrentTextParagraph(),
469 mrTextPortionEnumeration(),
470 mrCurrentTextPortion(),
471 mpTextEmbeddedBitmapMtf( nullptr ),
472 mpTargetMapMode( nullptr ),
473 mnLeftTextPortionLength( 0 ),
474 maTextPos(0,0),
475 mnTextWidth(0),
476 mbPositioningNeeded( false ),
477 mbIsNewListItem( false ),
478 meNumberingType(0),
479 mcBulletChar(0),
480 maBulletListItemMap(),
481 mbIsListLevelStyleImage( false ),
482 mbLineBreak( false ),
483 mbIsURLField( false ),
484 msUrl(),
485 mbIsPlaceholderShape( false ),
486 maCurrentFont(),
487 maParentFont()
488{
489}
490
491
492SVGTextWriter::~SVGTextWriter()
493{
494 endTextParagraph();
495}
496
497
498void SVGTextWriter::implRegisterInterface( const Reference< XInterface >& rxIf )
499{
500 if( rxIf.is() )
501 mrExport.getInterfaceToIdentifierMapper().registerReference( rxIf );
502}
503
504
505const OUString & SVGTextWriter::implGetValidIDFromInterface( const Reference< XInterface >& rxIf )
506{
507 return mrExport.getInterfaceToIdentifierMapper().getIdentifier( rxIf );
508}
509
510
511void SVGTextWriter::implMap( const Size& rSz, Size& rDstSz ) const
512{
513 if( mpVDev && mpTargetMapMode )
514 rDstSz = OutputDevice::LogicToLogic( rSz, mpVDev->GetMapMode(), *mpTargetMapMode );
515 else
516 OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "516" ": "), "%s", "SVGTextWriter::implMap: invalid virtual device or map mode."
); } } while (false)
;
517}
518
519
520void SVGTextWriter::implMap( const Point& rPt, Point& rDstPt ) const
521{
522 if( mpVDev && mpTargetMapMode )
523 rDstPt = OutputDevice::LogicToLogic( rPt, mpVDev->GetMapMode(), *mpTargetMapMode );
524 else
525 OSL_FAIL( "SVGTextWriter::implMap: invalid virtual device or map mode." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "525" ": "), "%s", "SVGTextWriter::implMap: invalid virtual device or map mode."
); } } while (false)
;
526}
527
528
529void SVGTextWriter::implSetCurrentFont()
530{
531 if( mpVDev )
532 {
533 maCurrentFont = mpVDev->GetFont();
534 Size aSz;
535
536 implMap( Size( 0, maCurrentFont.GetFontHeight() ), aSz );
537
538 maCurrentFont.SetFontHeight( aSz.Height() );
539 }
540 else
541 {
542 OSL_FAIL( "SVGTextWriter::implSetCorrectFontHeight: invalid virtual device." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "542" ": "), "%s", "SVGTextWriter::implSetCorrectFontHeight: invalid virtual device."
); } } while (false)
;
543 }
544}
545
546
547template< typename SubType >
548bool SVGTextWriter::implGetTextPosition( const MetaAction* pAction, Point& raPos, bool& rbEmpty )
549{
550 const SubType* pA = static_cast<const SubType*>(pAction);
551 sal_uInt16 nLength = pA->GetLen();
552 rbEmpty = ( nLength == 0 );
553 if( !rbEmpty )
554 {
555 raPos = pA->GetPoint();
556 return true;
557 }
558 return false;
559}
560
561
562template<>
563bool SVGTextWriter::implGetTextPosition<MetaTextRectAction>( const MetaAction* pAction, Point& raPos, bool& rbEmpty )
564{
565 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
566 sal_uInt16 nLength = pA->GetText().getLength();
567 rbEmpty = ( nLength == 0 );
568 if( !rbEmpty )
569 {
570 raPos = pA->GetRect().TopLeft();
571 return true;
572 }
573 return false;
574}
575
576
577template< typename SubType >
578bool SVGTextWriter::implGetTextPositionFromBitmap( const MetaAction* pAction, Point& raPos, bool& rbEmpty )
579{
580 const SubType* pA = static_cast<const SubType*>(pAction);
581 raPos = pA->GetPoint();
582 rbEmpty = false;
583 return true;
584}
585
586
587/** setTextPosition
588 * Set the start position of the next line of text. In case no text is found
589 * the current action index is updated to the index value we reached while
590 * searching for text.
591 *
592 * @returns {sal_Int32}
593 * -2 if no text found and end of line is reached
594 * -1 if no text found and end of paragraph is reached
595 * 0 if no text found and end of text shape is reached
596 * 1 if text found!
597 */
598sal_Int32 SVGTextWriter::setTextPosition(const GDIMetaFile& rMtf, sal_uLong& nCurAction,
599 sal_uInt32 nWriteFlags)
600{
601 Point aPos;
602 sal_uLong nCount = rMtf.GetActionSize();
603 bool bEOL = false;
604 bool bEOP = false;
605 bool bETS = false;
606 bool bConfigured = false;
607 bool bEmpty = true;
608
609 sal_uLong nActionIndex = nCurAction + 1;
610 for( ; nActionIndex < nCount; ++nActionIndex )
611 {
612 const MetaAction* pAction = rMtf.GetAction( nActionIndex );
613 const MetaActionType nType = pAction->GetType();
614
615 switch( nType )
616 {
617 case MetaActionType::TEXT:
618 {
619 bConfigured = implGetTextPosition<MetaTextAction>( pAction, aPos, bEmpty );
620 }
621 break;
622
623 case MetaActionType::TEXTRECT:
624 {
625 bConfigured = implGetTextPosition<MetaTextRectAction>( pAction, aPos, bEmpty );
626 }
627 break;
628
629 case MetaActionType::TEXTARRAY:
630 {
631 bConfigured = implGetTextPosition<MetaTextArrayAction>( pAction, aPos, bEmpty );
632 }
633 break;
634
635 case MetaActionType::FLOATTRANSPARENT:
636 {
637 const MetaFloatTransparentAction* pA
638 = static_cast<const MetaFloatTransparentAction*>(pAction);
639 GDIMetaFile aTmpMtf(pA->GetGDIMetaFile());
640 sal_uLong nTmpAction = 0;
641 if (setTextPosition(aTmpMtf, nTmpAction, nWriteFlags) == 1)
642 {
643 // Text is found in the inner metafile.
644 bConfigured = true;
645 mrActionWriter.StartMask(pA->GetPoint(), pA->GetSize(), pA->GetGradient(),
646 nWriteFlags, &maTextOpacity);
647 }
648 }
649 break;
650
651 case MetaActionType::STRETCHTEXT:
652 {
653 bConfigured = implGetTextPosition<MetaStretchTextAction>( pAction, aPos, bEmpty );
654 }
655 break;
656
657 case MetaActionType::BMPSCALE:
658 {
659 bConfigured = implGetTextPositionFromBitmap<MetaBmpScaleAction>( pAction, aPos, bEmpty );
660 }
661 break;
662
663 case MetaActionType::BMPEXSCALE:
664 {
665 bConfigured = implGetTextPositionFromBitmap<MetaBmpExScaleAction>( pAction, aPos, bEmpty );
666 }
667 break;
668
669 // If we reach the end of the current line, paragraph or text shape
670 // without finding any text we stop searching
671 case MetaActionType::COMMENT:
672 {
673 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
674 const OString& rsComment = pA->GetComment();
675 if( rsComment.equalsIgnoreAsciiCase( "XTEXT_EOL" ) )
676 {
677 bEOL = true;
678 }
679 else if( rsComment.equalsIgnoreAsciiCase( "XTEXT_EOP" ) )
680 {
681 bEOP = true;
682
683 OUString sContent;
684 while( nextTextPortion() )
685 {
686 sContent = mrCurrentTextPortion->getString();
687 if( sContent.isEmpty() )
688 {
689 continue;
690 }
691 else
692 {
693 if( sContent == "\n" )
694 mbLineBreak = true;
695 }
696 }
697 if( nextParagraph() )
698 {
699 while( nextTextPortion() )
700 {
701 sContent = mrCurrentTextPortion->getString();
702 if( sContent.isEmpty() )
703 {
704 continue;
705 }
706 else
707 {
708 if( sContent == "\n" )
709 mbLineBreak = true;
710 }
711 }
712 }
713 }
714 else if( rsComment.equalsIgnoreAsciiCase( "XTEXT_PAINTSHAPE_END" ) )
715 {
716 bETS = true;
717 }
718 }
719 break;
720 default: break;
721 }
722 if( bConfigured || bEOL || bEOP || bETS ) break;
723 }
724 implMap( aPos, maTextPos );
725
726 if( bEmpty )
727 {
728 nCurAction = nActionIndex;
729 return ( bEOL ? -2 : ( bEOP ? -1 : 0 ) );
730 }
731 else
732 {
733 return 1;
734 }
735}
736
737
738void SVGTextWriter::setTextProperties( const GDIMetaFile& rMtf, sal_uLong nCurAction )
739{
740 sal_uLong nCount = rMtf.GetActionSize();
741 bool bEOP = false;
742 bool bConfigured = false;
743 for( sal_uLong nActionIndex = nCurAction + 1; nActionIndex < nCount; ++nActionIndex )
744 {
745 const MetaAction* pAction = rMtf.GetAction( nActionIndex );
746 const MetaActionType nType = pAction->GetType();
747 switch( nType )
748 {
749 case MetaActionType::TEXTLINECOLOR:
750 case MetaActionType::TEXTFILLCOLOR:
751 case MetaActionType::TEXTCOLOR:
752 case MetaActionType::TEXTALIGN:
753 case MetaActionType::FONT:
754 case MetaActionType::LAYOUTMODE:
755 {
756 const_cast<MetaAction*>(pAction)->Execute( mpVDev );
757 }
758 break;
759
760 case MetaActionType::TEXT:
761 {
762 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
763 if( pA->GetLen() > 2 )
764 bConfigured = true;
765 }
766 break;
767 case MetaActionType::TEXTRECT:
768 {
769 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
770 if( pA->GetText().getLength() > 2 )
771 bConfigured = true;
772 }
773 break;
774 case MetaActionType::TEXTARRAY:
775 {
776 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
777 if( pA->GetLen() > 2 )
778 bConfigured = true;
779 }
780 break;
781 case MetaActionType::STRETCHTEXT:
782 {
783 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
784 if( pA->GetLen() > 2 )
785 bConfigured = true;
786 }
787 break;
788 // If we reach the end of the paragraph without finding any text
789 // we stop searching
790 case MetaActionType::COMMENT:
791 {
792 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
793 const OString& rsComment = pA->GetComment();
794 if( rsComment.equalsIgnoreAsciiCase( "XTEXT_EOP" ) )
795 {
796 bEOP = true;
797 }
798 }
799 break;
800 default: break;
801 }
802 if( bConfigured || bEOP ) break;
803 }
804}
805
806
807void SVGTextWriter::addFontAttributes( bool bIsTextContainer )
808{
809 implSetCurrentFont();
810
811 if( maCurrentFont == maParentFont )
812 return;
813
814 const OUString& rsCurFontName = maCurrentFont.GetFamilyName();
815 long int nCurFontSize = maCurrentFont.GetFontHeight();
816 FontItalic eCurFontItalic = maCurrentFont.GetItalic();
817 FontWeight eCurFontWeight = maCurrentFont.GetWeight();
818
819 const OUString& rsParFontName = maParentFont.GetFamilyName();
820 long int nParFontSize = maParentFont.GetFontHeight();
821 FontItalic eParFontItalic = maParentFont.GetItalic();
822 FontWeight eParFontWeight = maParentFont.GetWeight();
823
824
825 // Font Family
826 if( rsCurFontName != rsParFontName )
827 {
828 implSetFontFamily();
829 }
830
831 // Font Size
832 if( nCurFontSize != nParFontSize )
833 {
834 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontSize,
835 OUString::number( nCurFontSize ) + "px" );
836 }
837
838 // Font Style
839 if( eCurFontItalic != eParFontItalic )
840 {
841 OUString sFontStyle;
842 if( eCurFontItalic != ITALIC_NONE )
843 {
844 if( eCurFontItalic == ITALIC_OBLIQUE )
845 sFontStyle = "oblique";
846 else
847 sFontStyle = "italic";
848 }
849 else
850 {
851 sFontStyle = "normal";
852 }
853 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontStyle, sFontStyle );
854 }
855
856 // Font Weight
857 if( eCurFontWeight != eParFontWeight )
858 {
859 sal_Int32 nFontWeight;
860 switch( eCurFontWeight )
861 {
862 case WEIGHT_THIN: nFontWeight = 100; break;
863 case WEIGHT_ULTRALIGHT: nFontWeight = 200; break;
864 case WEIGHT_LIGHT: nFontWeight = 300; break;
865 case WEIGHT_SEMILIGHT: nFontWeight = 400; break;
866 case WEIGHT_NORMAL: nFontWeight = 400; break;
867 case WEIGHT_MEDIUM: nFontWeight = 500; break;
868 case WEIGHT_SEMIBOLD: nFontWeight = 600; break;
869 case WEIGHT_BOLD: nFontWeight = 700; break;
870 case WEIGHT_ULTRABOLD: nFontWeight = 800; break;
871 case WEIGHT_BLACK: nFontWeight = 900; break;
872 default: nFontWeight = 400; break;
873 }
874 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontWeight, OUString::number( nFontWeight ) );
875 }
876
877
878 if( mrExport.IsUseNativeTextDecoration() )
879 {
880 FontLineStyle eCurFontLineStyle = maCurrentFont.GetUnderline();
881 FontStrikeout eCurFontStrikeout = maCurrentFont.GetStrikeout();
882
883 FontLineStyle eParFontLineStyle = maParentFont.GetUnderline();
884 FontStrikeout eParFontStrikeout = maParentFont.GetStrikeout();
885
886 OUString sTextDecoration;
887 bool bIsDecorationChanged = false;
888 if( eCurFontLineStyle != eParFontLineStyle )
889 {
890 if( eCurFontLineStyle != LINESTYLE_NONE )
891 sTextDecoration = "underline";
892 bIsDecorationChanged = true;
893 }
894 if( eCurFontStrikeout != eParFontStrikeout )
895 {
896 if( eCurFontStrikeout != STRIKEOUT_NONE )
897 {
898 if( !sTextDecoration.isEmpty() )
899 sTextDecoration += " ";
900 sTextDecoration += "line-through";
901 }
902 bIsDecorationChanged = true;
903 }
904
905 if( !sTextDecoration.isEmpty() )
906 {
907 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, sTextDecoration );
908 }
909 else if( bIsDecorationChanged )
910 {
911 sTextDecoration = "none";
912 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTextDecoration, sTextDecoration );
913 }
914 }
915
916 if( bIsTextContainer )
917 maParentFont = maCurrentFont;
918}
919
920
921void SVGTextWriter::implSetFontFamily()
922{
923 const OUString& rsFontName = maCurrentFont.GetFamilyName();
924 OUString sFontFamily( rsFontName.getToken( 0, ';' ) );
925 FontPitch ePitch = maCurrentFont.GetPitch();
926 if( ePitch == PITCH_FIXED )
927 {
928 sFontFamily += ", monospace";
929 }
930 else
931 {
932 FontFamily eFamily = maCurrentFont.GetFamilyType();
933 if( eFamily == FAMILY_ROMAN )
934 sFontFamily += ", serif";
935 else if( eFamily == FAMILY_SWISS )
936 sFontFamily += ", sans-serif";
937 }
938 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrFontFamily, sFontFamily );
939}
940
941
942void SVGTextWriter::createParagraphEnumeration()
943{
944 if( mrTextShape.is() )
945 {
946 msShapeId = implGetValidIDFromInterface( Reference<XInterface>(mrTextShape, UNO_QUERY) );
947
948 Reference< XEnumerationAccess > xEnumerationAccess( mrTextShape, UNO_QUERY_THROW );
949 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
950 if( xEnumeration.is() )
951 {
952 mrParagraphEnumeration.set( xEnumeration );
953 }
954 else
955 {
956 OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid xEnumeration interface found." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "956" ": "), "%s", "SVGTextWriter::createParagraphEnumeration: no valid xEnumeration interface found."
); } } while (false)
;
957 }
958 }
959 else
960 {
961 OSL_FAIL( "SVGTextWriter::createParagraphEnumeration: no valid XText interface found." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "961" ": "), "%s", "SVGTextWriter::createParagraphEnumeration: no valid XText interface found."
); } } while (false)
;
962 }
963}
964
965
966bool SVGTextWriter::nextParagraph()
967{
968 mrTextPortionEnumeration.clear();
969 mrCurrentTextParagraph.clear();
970 mbIsNewListItem = false;
971 mbIsListLevelStyleImage = false;
972
973 if( mrParagraphEnumeration.is() && mrParagraphEnumeration->hasMoreElements() )
974 {
975 Reference < XTextContent > xTextContent( mrParagraphEnumeration->nextElement(), UNO_QUERY_THROW );
976 if( xTextContent.is() )
977 {
978 Reference< XServiceInfo > xServiceInfo( xTextContent, UNO_QUERY_THROW );
979#if OSL_DEBUG_LEVEL1 > 0
980 OUString sInfo;
981#endif
982 if( xServiceInfo->supportsService( "com.sun.star.text.Paragraph" ) )
983 {
984 mrCurrentTextParagraph.set( xTextContent );
985 Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY_THROW );
986 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
987 if( xPropSetInfo->hasPropertyByName( "NumberingLevel" ) )
988 {
989 sal_Int16 nListLevel = 0;
990 if( xPropSet->getPropertyValue( "NumberingLevel" ) >>= nListLevel )
991 {
992 mbIsNewListItem = true;
993#if OSL_DEBUG_LEVEL1 > 0
994 sInfo = "NumberingLevel: " + OUString::number( nListLevel );
995 mrExport.AddAttribute( XML_NAMESPACE_NONE, "style", sInfo );
996#endif
997 Reference< XIndexReplace > xNumRules;
998 if( xPropSetInfo->hasPropertyByName( "NumberingRules" ) )
999 {
1000 xPropSet->getPropertyValue( "NumberingRules" ) >>= xNumRules;
1001 }
1002 if( xNumRules.is() && ( nListLevel < xNumRules->getCount() ) )
1003 {
1004 bool bIsNumbered = true;
1005 OUString sNumberingIsNumber("NumberingIsNumber");
1006 if( xPropSetInfo->hasPropertyByName( sNumberingIsNumber ) )
1007 {
1008 if( !(xPropSet->getPropertyValue( sNumberingIsNumber ) >>= bIsNumbered ) )
1009 {
1010 OSL_FAIL( "numbered paragraph without number info" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1010" ": "), "%s", "numbered paragraph without number info"
); } } while (false)
;
1011 bIsNumbered = false;
1012 }
1013#if OSL_DEBUG_LEVEL1 > 0
1014 if( bIsNumbered )
1015 {
1016 sInfo = "true";
1017 mrExport.AddAttribute( XML_NAMESPACE_NONE, "is-numbered", sInfo );
1018 }
1019#endif
1020 }
1021 mbIsNewListItem = bIsNumbered;
1022
1023 if( bIsNumbered )
1024 {
1025 Sequence<PropertyValue> aProps;
1026 if( xNumRules->getByIndex( nListLevel ) >>= aProps )
1027 {
1028 sal_Int16 eType = NumberingType::CHAR_SPECIAL;
1029 sal_Unicode cBullet = 0xf095;
1030 const sal_Int32 nCount = aProps.getLength();
1031 const PropertyValue* pPropArray = aProps.getConstArray();
1032 for( sal_Int32 i = 0; i < nCount; ++i )
1033 {
1034 const PropertyValue& rProp = pPropArray[i];
1035 if( rProp.Name == "NumberingType" )
1036 {
1037 rProp.Value >>= eType;
1038 }
1039 else if( rProp.Name == "BulletChar" )
1040 {
1041 OUString sValue;
1042 rProp.Value >>= sValue;
1043 if( !sValue.isEmpty() )
1044 {
1045 cBullet = sValue[0];
1046 }
1047 }
1048 }
1049 meNumberingType = eType;
1050 mbIsListLevelStyleImage = ( NumberingType::BITMAP == meNumberingType );
1051 if( NumberingType::CHAR_SPECIAL == meNumberingType )
1052 {
1053 if( cBullet )
1054 {
1055 if( cBullet < ' ' )
1056 {
1057 cBullet = 0xF000 + 149;
1058 }
1059 mcBulletChar = cBullet;
1060#if OSL_DEBUG_LEVEL1 > 0
1061 sInfo = OUString::number( static_cast<sal_Int32>(cBullet) );
1062 mrExport.AddAttribute( XML_NAMESPACE_NONE, "bullet-char", sInfo );
1063#endif
1064 }
1065
1066 }
1067 }
1068 }
1069 }
1070
1071 }
1072 }
1073
1074 Reference< XEnumerationAccess > xEnumerationAccess( xTextContent, UNO_QUERY_THROW );
1075 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW );
1076 if( xEnumeration.is() && xEnumeration->hasMoreElements() )
1077 {
1078 mrTextPortionEnumeration.set( xEnumeration );
1079 }
1080#if OSL_DEBUG_LEVEL1 > 0
1081 sInfo = "Paragraph";
1082#endif
1083 }
1084 else if( xServiceInfo->supportsService( "com.sun.star.text.Table" ) )
1085 {
1086 OSL_FAIL( "SVGTextWriter::nextParagraph: text tables are not handled." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1086" ": "), "%s", "SVGTextWriter::nextParagraph: text tables are not handled."
); } } while (false)
;
1087#if OSL_DEBUG_LEVEL1 > 0
1088 sInfo = "Table";
1089#endif
1090 }
1091 else
1092 {
1093 OSL_FAIL( "SVGTextWriter::nextParagraph: Unknown text content." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1093" ": "), "%s", "SVGTextWriter::nextParagraph: Unknown text content."
); } } while (false)
;
1094 return false;
1095 }
1096#if OSL_DEBUG_LEVEL1 > 0
1097 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", sInfo );
1098 SvXMLElementExport aParaElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
1099#endif
1100 }
1101 else
1102 {
1103 OSL_FAIL( "SVGTextWriter::nextParagraph: no XServiceInfo interface available for text content." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1103" ": "), "%s", "SVGTextWriter::nextParagraph: no XServiceInfo interface available for text content."
); } } while (false)
;
1104 return false;
1105 }
1106
1107 const OUString& rParagraphId = implGetValidIDFromInterface( Reference<XInterface>(xTextContent, UNO_QUERY) );
1108 if( !rParagraphId.isEmpty() )
1109 {
1110 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rParagraphId );
1111 }
1112 return true;
1113 }
1114
1115 return false;
1116}
1117
1118
1119bool SVGTextWriter::nextTextPortion()
1120{
1121 mrCurrentTextPortion.clear();
1122 mbIsURLField = false;
1123 mbIsPlaceholderShape = false;
1124 if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
1125 {
1126 Reference< XPropertySet > xPortionPropSet( mrTextPortionEnumeration->nextElement(), UNO_QUERY );
1127 Reference< XPropertySetInfo > xPortionPropInfo( xPortionPropSet->getPropertySetInfo() );
1128 Reference < XTextRange > xPortionTextRange( xPortionPropSet, UNO_QUERY);
1129 if( xPortionPropSet.is() && xPortionPropInfo.is()
1130 && xPortionPropInfo->hasPropertyByName( "TextPortionType" ) )
1131 {
1132#if OSL_DEBUG_LEVEL1 > 0
1133 OUString sInfo;
1134 OUString sPortionType;
1135 if( xPortionPropSet->getPropertyValue( "TextPortionType" ) >>= sPortionType )
1136 {
1137 sInfo = "type: " + sPortionType + "; ";
1138 }
1139#endif
1140 if( xPortionTextRange.is() )
1141 {
1142#if OSL_DEBUG_LEVEL1 > 0
1143 sInfo += "content: " + xPortionTextRange->getString() + "; ";
1144#endif
1145 mrCurrentTextPortion.set( xPortionTextRange );
1146
1147 Reference < XPropertySet > xRangePropSet( xPortionTextRange, UNO_QUERY );
1148 if( xRangePropSet.is() && xRangePropSet->getPropertySetInfo()->hasPropertyByName( "TextField" ) )
1149 {
1150 Reference < XTextField > xTextField( xRangePropSet->getPropertyValue( "TextField" ), UNO_QUERY );
1151 if( xTextField.is() )
1152 {
1153 const OUString sServicePrefix("com.sun.star.text.textfield.");
1154 const OUString sPresentationServicePrefix("com.sun.star.presentation.TextField.");
1155
1156 Reference< XServiceInfo > xService( xTextField, UNO_QUERY );
1157 const Sequence< OUString > aServices = xService->getSupportedServiceNames();
1158
1159 const OUString* pNames = aServices.getConstArray();
1160 sal_Int32 nCount = aServices.getLength();
1161
1162 OUString sFieldName; // service name postfix of current field
1163
1164 // search for TextField service name
1165 while( nCount-- )
1166 {
1167 if ( pNames->matchIgnoreAsciiCase( sServicePrefix ) )
1168 {
1169 // TextField found => postfix is field type!
1170 sFieldName = pNames->copy( sServicePrefix.getLength() );
1171 break;
1172 }
1173 else if( pNames->startsWith( sPresentationServicePrefix ) )
1174 {
1175 // TextField found => postfix is field type!
1176 sFieldName = pNames->copy( sPresentationServicePrefix.getLength() );
1177 break;
1178 }
1179
1180 ++pNames;
1181 }
1182
1183#if OSL_DEBUG_LEVEL1 > 0
1184 sInfo += "text field type: " + sFieldName + "; content: " + xTextField->getPresentation( /* show command: */ false ) + "; ";
1185#endif
1186 if( sFieldName == "DateTime" || sFieldName == "Header"
1187 || sFieldName == "Footer" || sFieldName == "PageNumber" )
1188 {
1189 mbIsPlaceholderShape = true;
1190 }
1191 else
1192 {
1193 mbIsURLField = sFieldName == "URL";
1194
1195 if( mbIsURLField )
1196 {
1197 Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
1198 if( xTextFieldPropSet.is() )
1199 {
1200 OUString sURL;
1201 if( ( xTextFieldPropSet->getPropertyValue( sFieldName ) ) >>= sURL )
1202 {
1203#if OSL_DEBUG_LEVEL1 > 0
1204 sInfo += "url: " + mrExport.GetRelativeReference( sURL );
1205#endif
1206 msUrl = mrExport.GetRelativeReference( sURL );
1207 if( !msUrl.isEmpty() )
1208 {
1209 implRegisterInterface( xPortionTextRange );
1210
1211 const OUString& rTextPortionId = implGetValidIDFromInterface( Reference<XInterface>(xPortionTextRange, UNO_QUERY) );
1212 if( !rTextPortionId.isEmpty() )
1213 {
1214 msHyperlinkIdList += rTextPortionId + " ";
1215 }
1216 }
1217 }
1218 }
1219 }
1220 }
1221 }
1222 }
1223 }
1224#if OSL_DEBUG_LEVEL1 > 0
1225 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextPortion" );
1226 SvXMLElementExport aPortionElem( mrExport, XML_NAMESPACE_NONE, "desc", mbIWS, mbIWS );
1227 mrExport.GetDocHandler()->characters( sInfo );
1228#endif
1229 return true;
1230 }
1231 }
1232
1233 return false;
1234}
1235
1236
1237void SVGTextWriter::startTextShape()
1238{
1239 if( mpTextShapeElem )
1240 {
1241 OSL_FAIL( "SVGTextWriter::startTextShape: text shape already defined." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1241" ": "), "%s", "SVGTextWriter::startTextShape: text shape already defined."
); } } while (false)
;
1242 }
1243
1244 {
1245 mbIsTextShapeStarted = true;
1246 maParentFont = vcl::Font();
1247 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextShape" );
1248
1249 // if text is rotated, set transform matrix at text element
1250 const vcl::Font& rFont = mpVDev->GetFont();
1251 if( rFont.GetOrientation() )
1252 {
1253 Point aRot( maTextPos );
1254 OUString aTransform = "rotate(" +
1255 OUString::number( rFont.GetOrientation() * -0.1 ) + " " +
1256 OUString::number( aRot.X() ) + " " +
1257 OUString::number( aRot.Y() ) + ")";
1258 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
1259 }
1260
1261 mpTextShapeElem.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemText, true, mbIWS ));
1262 startTextParagraph();
1263 }
1264}
1265
1266
1267void SVGTextWriter::endTextShape()
1268{
1269 endTextParagraph();
1270 mrTextShape.clear();
1271 mrParagraphEnumeration.clear();
1272 mrCurrentTextParagraph.clear();
1273 mpTextShapeElem.reset();
1274 maTextOpacity.clear();
1275 mbIsTextShapeStarted = false;
1276 // these need to be invoked after the <text> element has been closed
1277 implExportHyperlinkIds();
1278 implWriteBulletChars();
1279 implWriteEmbeddedBitmaps();
1280
1281}
1282
1283
1284void SVGTextWriter::startTextParagraph()
1285{
1286 endTextParagraph();
1287 nextParagraph();
1288 if( mbIsNewListItem )
1289 {
1290 OUString sNumberingType;
1291 switch( meNumberingType )
1292 {
1293 case NumberingType::CHAR_SPECIAL:
1294 sNumberingType = "bullet-style";
1295 break;
1296 case NumberingType::BITMAP:
1297 sNumberingType = "image-style";
1298 break;
1299 default:
1300 sNumberingType = "number-style";
1301 break;
1302 }
1303 mrExport.AddAttribute( XML_NAMESPACE_NONE, "ooo:numbering-type", sNumberingType );
1304 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "ListItem" );
1305 }
1306 else
1307 {
1308 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextParagraph" );
1309 }
1310 maParentFont = vcl::Font();
1311 addFontAttributes( /* isTexTContainer: */ true );
1312 mpTextParagraphElem.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS ));
1313
1314 if( !mbIsListLevelStyleImage )
1315 {
1316 mbPositioningNeeded = true;
1317 }
1318}
1319
1320
1321void SVGTextWriter::endTextParagraph()
1322{
1323 mrCurrentTextPortion.clear();
1324 endTextPosition();
1325 mbIsNewListItem = false;
1326 mbIsListLevelStyleImage = false;
1327 mbPositioningNeeded = false;
1328 mpTextParagraphElem.reset();
1329}
1330
1331
1332void SVGTextWriter::startTextPosition( bool bExportX, bool bExportY )
1333{
1334 endTextPosition();
1335 mnTextWidth = 0;
1336 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "TextPosition" );
1337 if( bExportX )
1338 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( maTextPos.X() ) );
1339 if( bExportY )
1340 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( maTextPos.Y() ) );
1341
1342 mpTextPositionElem.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS ) );
1343}
1344
1345
1346void SVGTextWriter::endTextPosition()
1347{
1348 mpTextPositionElem.reset();
1349}
1350
1351bool SVGTextWriter::hasTextOpacity() const { return !maTextOpacity.isEmpty(); }
1352
1353void SVGTextWriter::implExportHyperlinkIds()
1354{
1355 if( !msHyperlinkIdList.isEmpty() )
1356 {
1357 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "HyperlinkIdList" );
1358 SvXMLElementExport aDescElem( mrExport, XML_NAMESPACE_NONE, "desc", true, false );
1359 mrExport.GetDocHandler()->characters( msHyperlinkIdList.trim() );
1360 msHyperlinkIdList.clear();
1361 }
1362}
1363
1364
1365void SVGTextWriter::implWriteBulletChars()
1366{
1367 if( maBulletListItemMap.empty() )
1368 return;
1369
1370 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BulletChars" );
1371 SvXMLElementExport aGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
1372
1373 OUString sId, sPosition, sScaling, sRefId;
1374 for (auto const& bulletListItem : maBulletListItemMap)
1375 {
1376 // <g id="?" > (used by animations)
1377 // As id we use the id of the text portion placeholder with prefix
1378 // bullet-char-*
1379 sId = "bullet-char-" + bulletListItem.first;
1380 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1381 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BulletChar" );
1382 SvXMLElementExport aBulletCharElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
1383
1384 // <g transform="translate(x,y)" >
1385 {
1386 const BulletListItemInfo& rInfo = bulletListItem.second;
1387
1388 // Add positioning attribute through a translation
1389 sPosition = "translate(" +
1390 OUString::number( rInfo.aPos.X() ) +
1391 "," + OUString::number( rInfo.aPos.Y() ) + ")";
1392 mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sPosition );
1393
1394 mrAttributeWriter.AddPaintAttr( COL_TRANSPARENT, rInfo.aColor );
1395
1396 SvXMLElementExport aPositioningElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
1397
1398 // <use transform="scale(font-size)" xlink:ref="/" >
1399 {
1400 // Add size attribute through a scaling
1401 sScaling = "scale(" + OUString::number( rInfo.nFontSize ) +
1402 "," + OUString::number( rInfo.nFontSize )+ ")";
1403 mrExport.AddAttribute( XML_NAMESPACE_NONE, "transform", sScaling );
1404
1405 // Add ref attribute
1406 sRefId = "#bullet-char-template-" +
1407 OUString::number( ( rInfo.cBulletChar ) );
1408 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
1409
1410 SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", true, true );
1411 }
1412 } // close aPositioningElem
1413 }
1414
1415 // clear the map
1416 maBulletListItemMap.clear();
1417}
1418
1419
1420template< typename MetaBitmapActionType >
1421void SVGTextWriter::writeBitmapPlaceholder( const MetaBitmapActionType* pAction )
1422{
1423 // text position element
1424 const Point& rPos = pAction->GetPoint();
1425 implMap( rPos, maTextPos );
1426 startTextPosition();
1427 mbPositioningNeeded = true;
1428 if( mbIsNewListItem )
1429 {
1430 mbIsNewListItem = false;
1431 mbIsListLevelStyleImage = false;
1432 }
1433
1434 // bitmap placeholder element
1435 BitmapChecksum nId = SVGActionWriter::GetChecksum( pAction );
1436 OUString sId = "bitmap-placeholder(" + msShapeId + "." +
1437 OUString::number( nId ) + ")";
1438
1439 {
1440 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1441 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BitmapPlaceholder" );
1442 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1443 }
1444 endTextPosition();
1445}
1446
1447
1448void SVGTextWriter::implWriteEmbeddedBitmaps()
1449{
1450 if( !(mpTextEmbeddedBitmapMtf && mpTextEmbeddedBitmapMtf->GetActionSize()) )
1451 return;
1452
1453 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "EmbeddedBitmaps" );
1454 SvXMLElementExport aEmbBitmapGroupElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
1455
1456 const GDIMetaFile& rMtf = *mpTextEmbeddedBitmapMtf;
1457
1458 BitmapChecksum nId, nChecksum = 0;
1459 Point aPt;
1460 Size aSz;
1461 sal_uLong nCount = rMtf.GetActionSize();
1462 for( sal_uLong nCurAction = 0; nCurAction < nCount; nCurAction++ )
1463 {
1464
1465 const MetaAction* pAction = rMtf.GetAction( nCurAction );
1466 const MetaActionType nType = pAction->GetType();
1467
1468 switch( nType )
1469 {
1470 case MetaActionType::BMPSCALE:
1471 {
1472 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
1473 nChecksum = pA->GetBitmap().GetChecksum();
1474 aPt = pA->GetPoint();
1475 aSz = pA->GetSize();
1476 }
1477 break;
1478 case MetaActionType::BMPEXSCALE:
1479 {
1480 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
1481 nChecksum = pA->GetBitmapEx().GetChecksum();
1482 aPt = pA->GetPoint();
1483 aSz = pA->GetSize();
1484 }
1485 break;
1486 default: break;
1487 }
1488
1489 // <g id="?" > (used by animations)
1490 {
1491 // embedded bitmap id
1492 nId = SVGActionWriter::GetChecksum( pAction );
1493 OUString sId = "embedded-bitmap(" + msShapeId + "." + OUString::number( nId ) + ")";
1494 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1495 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "EmbeddedBitmap" );
1496
1497 SvXMLElementExport aEmbBitmapElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
1498
1499 // <use x="?" y="?" xlink:ref="?" >
1500 {
1501 // referenced bitmap template
1502 OUString sRefId = "#bitmap(" + OUString::number( nChecksum ) + ")";
1503
1504 Point aPoint;
1505 Size aSize;
1506 implMap( aPt, aPoint );
1507 implMap( aSz, aSize );
1508
1509 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( aPoint.X() ) );
1510 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aPoint.Y() ) );
1511 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, sRefId );
1512
1513 SvXMLElementExport aRefElem( mrExport, XML_NAMESPACE_NONE, "use", true, true );
1514 }
1515 } // close aEmbBitmapElem
1516 }
1517}
1518
1519
1520void SVGTextWriter::writeTextPortion( const Point& rPos,
1521 const OUString& rText )
1522{
1523 if( rText.isEmpty() )
1524 return;
1525
1526 bool bStandAloneTextPortion = false;
1527 if( !isTextShapeStarted() )
1528 {
1529 bStandAloneTextPortion = true;
1530 startTextShape();
1531 }
1532
1533 mbLineBreak = false;
1534
1535 if( !mbIsNewListItem || mbIsListLevelStyleImage )
1536 {
1537 bool bNotSync = true;
1538 OUString sContent;
1539 sal_Int32 nStartPos;
1540 while( bNotSync )
1541 {
1542 if( mnLeftTextPortionLength <= 0 || !mrCurrentTextPortion.is() )
1543 {
1544 if( !nextTextPortion() )
1545 break;
1546 else
1547 {
1548 sContent = mrCurrentTextPortion->getString();
1549 if( mbIsURLField && sContent.isEmpty() )
1550 {
1551 Reference < XPropertySet > xPropSet( mrCurrentTextPortion, UNO_QUERY );
1552 Reference < XTextField > xTextField( xPropSet->getPropertyValue( "TextField" ), UNO_QUERY );
1553 sContent = xTextField->getPresentation( /* show command: */ false );
1554 if( sContent.isEmpty() )
1555 OSL_FAIL( "SVGTextWriter::writeTextPortion: content of URL TextField is empty." )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1555" ": "), "%s", "SVGTextWriter::writeTextPortion: content of URL TextField is empty."
); } } while (false)
;
1556 }
1557 mnLeftTextPortionLength = sContent.getLength();
1558 }
1559 }
1560 else
1561 {
1562 sContent = mrCurrentTextPortion->getString();
1563 }
1564
1565 nStartPos = sContent.getLength() - mnLeftTextPortionLength;
1566 if( nStartPos < 0 ) nStartPos = 0;
1567 mnLeftTextPortionLength -= rText.getLength();
1568
1569 if( sContent.isEmpty() )
1570 continue;
1571 if( sContent == "\n" )
1572 mbLineBreak = true;
1573 if( sContent.match( rText, nStartPos ) )
1574 bNotSync = false;
1575 }
1576 }
1577
1578 assert(mpVDev)(static_cast <bool> (mpVDev) ? void (0) : __assert_fail
("mpVDev", "/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
, 1578, __extension__ __PRETTY_FUNCTION__))
; //invalid virtual device
1579
1580#if 0
1581 const FontMetric aMetric( mpVDev->GetFontMetric() );
1582
1583 bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != FontRelief::NONE);
1584
1585 if( true || !bTextSpecial )
1586 {
1587 implWriteTextPortion( rPos, rText, mpVDev->GetTextColor() );
1588 }
1589 else
1590 {
1591 // to be implemented
1592 }
1593#else
1594 implWriteTextPortion( rPos, rText, mpVDev->GetTextColor() );
1595#endif
1596
1597 if( bStandAloneTextPortion )
1598 {
1599 endTextShape();
1600 }
1601}
1602
1603
1604void SVGTextWriter::implWriteTextPortion( const Point& rPos,
1605 const OUString& rText,
1606 Color aTextColor )
1607{
1608 Point aPos;
1609 Point aBaseLinePos( rPos );
1610 const FontMetric aMetric( mpVDev->GetFontMetric() );
1611 const vcl::Font& rFont = mpVDev->GetFont();
1612
1613 if( rFont.GetAlignment() == ALIGN_TOP )
1614 aBaseLinePos.AdjustY(aMetric.GetAscent() );
1615 else if( rFont.GetAlignment() == ALIGN_BOTTOM )
1616 aBaseLinePos.AdjustY( -(aMetric.GetDescent()) );
1617
1618 implMap( rPos, aPos );
1619
1620 if( mbPositioningNeeded )
1621 {
1622 mbPositioningNeeded = false;
1623 maTextPos.setX( aPos.X() );
1624 maTextPos.setY( aPos.Y() );
1625 startTextPosition();
1626 }
1627 else if( maTextPos.Y() != aPos.Y() )
1628 {
1629 // In case the text position moved backward we could have a line break
1630 // so we end the current line and start a new one.
1631 if( mbLineBreak || ( ( maTextPos.X() + mnTextWidth ) > aPos.X() ) )
1632 {
1633 mbLineBreak = false;
1634 maTextPos.setX( aPos.X() );
1635 maTextPos.setY( aPos.Y() );
1636 startTextPosition();
1637 }
1638 else // superscript, subscript, list item numbering
1639 {
1640 maTextPos.setY( aPos.Y() );
1641 startTextPosition( false /* do not export x attribute */ );
1642 }
1643 }
1644 // we are dealing with a bullet, so set up this for the next text portion
1645 if( mbIsNewListItem )
1646 {
1647 mbIsNewListItem = false;
1648 mbPositioningNeeded = true;
1649
1650 if( meNumberingType == NumberingType::CHAR_SPECIAL )
1651 {
1652 // Create an id for the current text portion
1653 implRegisterInterface( mrCurrentTextParagraph );
1654
1655 // Add the needed info to the BulletListItemMap
1656 OUString sId = implGetValidIDFromInterface( Reference<XInterface>(mrCurrentTextParagraph, UNO_QUERY) );
1657 if( !sId.isEmpty() )
1658 {
1659 sId += ".bp";
1660 BulletListItemInfo& aBulletListItemInfo = maBulletListItemMap[ sId ];
1661 aBulletListItemInfo.nFontSize = rFont.GetFontHeight();
1662 aBulletListItemInfo.aColor = aTextColor;
1663 aBulletListItemInfo.aPos = maTextPos;
1664 aBulletListItemInfo.cBulletChar = mcBulletChar;
1665
1666 // Make this text portion a bullet placeholder
1667 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", sId );
1668 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "BulletPlaceholder" );
1669 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1670 return;
1671 }
1672 }
1673 }
1674
1675 const OUString& rTextPortionId = implGetValidIDFromInterface( Reference<XInterface>(mrCurrentTextPortion, UNO_QUERY) );
1676 if( !rTextPortionId.isEmpty() )
1677 {
1678 mrExport.AddAttribute( XML_NAMESPACE_NONE, "id", rTextPortionId );
1679 }
1680
1681 if( mbIsPlaceholderShape )
1682 {
1683 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "PlaceholderText" );
1684 mbIsPlaceholderShape = false;
1685 }
1686
1687 addFontAttributes( /* isTexTContainer: */ false );
1688
1689 if (!maTextOpacity.isEmpty())
1690 {
1691 mrExport.AddAttribute(XML_NAMESPACE_NONE, "fill-opacity", maTextOpacity);
1692 }
1693
1694 mrAttributeWriter.AddPaintAttr( COL_TRANSPARENT, aTextColor );
1695
1696 // <a> tag for link should be the innermost tag, inside <tspan>
1697 if( !mbIsPlaceholderShape && mbIsURLField && !msUrl.isEmpty() )
1698 {
1699 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "UrlField" );
1700 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, msUrl );
1701
1702 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1703 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, msUrl );
1704 {
1705 SvXMLElementExport aSVGAElem( mrExport, XML_NAMESPACE_NONE, "a", mbIWS, mbIWS );
1706 mrExport.GetDocHandler()->characters( rText );
1707 }
1708 }
1709 else
1710 {
1711 SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
1712 mrExport.GetDocHandler()->characters( rText );
1713 }
1714
1715 mnTextWidth += mpVDev->GetTextWidth( rText );
1716}
1717
1718
1719SVGActionWriter::SVGActionWriter( SVGExport& rExport, SVGFontExport& rFontExport ) :
1720 mnCurGradientId( 1 ),
1721 mnCurMaskId( 1 ),
1722 mnCurPatternId( 1 ),
1723 mnCurClipPathId( 1 ),
1724 mpCurrentClipRegionElem(),
1725 mrExport( rExport ),
1726 maContextHandler(),
1727 mrCurrentState( maContextHandler.getCurrentState() ),
1728 maAttributeWriter( rExport, rFontExport, mrCurrentState ),
1729 maTextWriter(rExport, maAttributeWriter, *this),
1730 mpVDev(VclPtr<VirtualDevice>::Create()),
1731 mbClipAttrChanged( false ),
1732 mbIsPlaceholderShape( false )
1733{
1734 mpVDev->EnableOutput( false );
1735 maTargetMapMode = MapMode(MapUnit::Map100thMM);
1736 maTextWriter.setVirtualDevice( mpVDev, maTargetMapMode );
1737}
1738
1739
1740SVGActionWriter::~SVGActionWriter()
1741{
1742 mpVDev.disposeAndClear();
1
Calling 'VclPtr::disposeAndClear'
1743}
1744
1745
1746long SVGActionWriter::ImplMap( sal_Int32 nVal ) const
1747{
1748 Size aSz( nVal, nVal );
1749
1750 return ImplMap( aSz, aSz ).Width();
1751}
1752
1753
1754Point& SVGActionWriter::ImplMap( const Point& rPt, Point& rDstPt ) const
1755{
1756 rDstPt = OutputDevice::LogicToLogic( rPt, mpVDev->GetMapMode(), maTargetMapMode );
1757 return rDstPt;
1758}
1759
1760
1761Size& SVGActionWriter::ImplMap( const Size& rSz, Size& rDstSz ) const
1762{
1763 rDstSz = OutputDevice::LogicToLogic( rSz, mpVDev->GetMapMode(), maTargetMapMode );
1764 return rDstSz;
1765}
1766
1767
1768void SVGActionWriter::ImplMap( const tools::Rectangle& rRect, tools::Rectangle& rDstRect ) const
1769{
1770 Point aTL( rRect.TopLeft() );
1771 Size aSz( rRect.GetSize() );
1772
1773 rDstRect = tools::Rectangle( ImplMap( aTL, aTL ), ImplMap( aSz, aSz ) );
1774}
1775
1776
1777tools::Polygon& SVGActionWriter::ImplMap( const tools::Polygon& rPoly, tools::Polygon& rDstPoly ) const
1778{
1779 rDstPoly = tools::Polygon( rPoly.GetSize() );
1780
1781 for( sal_uInt16 i = 0, nSize = rPoly.GetSize(); i < nSize; ++i )
1782 {
1783 ImplMap( rPoly[ i ], rDstPoly[ i ] );
1784 rDstPoly.SetFlags( i, rPoly.GetFlags( i ) );
1785 }
1786
1787 return rDstPoly;
1788}
1789
1790
1791tools::PolyPolygon& SVGActionWriter::ImplMap( const tools::PolyPolygon& rPolyPoly, tools::PolyPolygon& rDstPolyPoly ) const
1792{
1793 tools::Polygon aPoly;
1794
1795 rDstPolyPoly = tools::PolyPolygon();
1796
1797 for( sal_uInt16 i = 0, nCount = rPolyPoly.Count(); i < nCount; ++i )
1798 {
1799 rDstPolyPoly.Insert( ImplMap( rPolyPoly[ i ], aPoly ) );
1800 }
1801
1802 return rDstPolyPoly;
1803}
1804
1805
1806OUString SVGActionWriter::GetPathString( const tools::PolyPolygon& rPolyPoly, bool bLine )
1807{
1808 OUStringBuffer aPathData;
1809 const OUString aBlank( " " );
1810 const OUString aComma( "," );
1811 Point aPolyPoint;
1812
1813 for( long i = 0, nCount = rPolyPoly.Count(); i < nCount; i++ )
1814 {
1815 const tools::Polygon& rPoly = rPolyPoly[ static_cast<sal_uInt16>(i) ];
1816 sal_uInt16 n = 1, nSize = rPoly.GetSize();
1817
1818 if( nSize > 1 )
1819 {
1820 aPolyPoint = rPoly[ 0 ];
1821 aPathData.append("M ")
1822 .append(OUString::number( aPolyPoint.X() ))
1823 .append(aComma)
1824 .append(OUString::number( aPolyPoint.Y() ));
1825
1826 char nCurrentMode = 0;
1827 const bool bClose(!bLine || rPoly[0] == rPoly[nSize - 1]);
1828 while( n < nSize )
1829 {
1830 aPathData.append(aBlank);
1831
1832 if ( ( rPoly.GetFlags( n ) == PolyFlags::Control ) && ( ( n + 2 ) < nSize ) )
1833 {
1834 if ( nCurrentMode != 'C' )
1835 {
1836 nCurrentMode = 'C';
1837 aPathData.append("C ");
1838 }
1839 for ( int j = 0; j < 3; j++ )
1840 {
1841 if ( j )
1842 aPathData.append(aBlank);
1843
1844 aPolyPoint = rPoly[ n++ ];
1845 aPathData.append(OUString::number( aPolyPoint.X() ))
1846 .append(aComma)
1847 .append(OUString::number( aPolyPoint.Y() ));
1848 }
1849 }
1850 else
1851 {
1852 if ( nCurrentMode != 'L' )
1853 {
1854 nCurrentMode = 'L';
1855 aPathData.append("L ");
1856 }
1857
1858 aPolyPoint = rPoly[ n++ ];
1859 aPathData.append(OUString::number( aPolyPoint.X() ))
1860 .append(aComma)
1861 .append(OUString::number( aPolyPoint.Y() ));
1862 }
1863 }
1864
1865 if(bClose)
1866 aPathData.append(" Z");
1867
1868 if( i < ( nCount - 1 ) )
1869 aPathData.append(aBlank);
1870 }
1871 }
1872
1873 return aPathData.makeStringAndClear();
1874}
1875
1876
1877BitmapChecksum SVGActionWriter::GetChecksum( const MetaAction* pAction )
1878{
1879 GDIMetaFile aMtf;
1880 MetaAction* pA = const_cast<MetaAction*>(pAction);
1881 aMtf.AddAction( pA );
1882 return aMtf.GetChecksum();
1883}
1884
1885
1886void SVGActionWriter::ImplWriteLine( const Point& rPt1, const Point& rPt2,
1887 const Color* pLineColor )
1888{
1889 Point aPt1, aPt2;
1890
1891 ImplMap( rPt1, aPt1 );
1892 ImplMap( rPt2, aPt2 );
1893
1894 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::number( aPt1.X() ) );
1895 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::number( aPt1.Y() ) );
1896 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::number( aPt2.X() ) );
1897 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::number( aPt2.Y() ) );
1898
1899 if( pLineColor )
1900 {
1901 // !!! mrExport.AddAttribute( XML_NAMESPACE_NONE, ... )
1902 OSL_FAIL( "SVGActionWriter::ImplWriteLine: Line color not implemented" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "1902" ": "), "%s", "SVGActionWriter::ImplWriteLine: Line color not implemented"
); } } while (false)
;
1903 }
1904
1905 {
1906 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, "line", true, true );
1907 }
1908}
1909
1910
1911void SVGActionWriter::ImplWriteRect( const tools::Rectangle& rRect, long nRadX, long nRadY )
1912{
1913 tools::Rectangle aRect;
1914
1915 ImplMap( rRect, aRect );
1916
1917 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( aRect.Left() ) );
1918 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aRect.Top() ) );
1919 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::number( aRect.GetWidth() ) );
1920 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::number( aRect.GetHeight() ) );
1921
1922 if( nRadX )
1923 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, OUString::number( ImplMap( nRadX ) ) );
1924
1925 if( nRadY )
1926 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, OUString::number( ImplMap( nRadY ) ) );
1927
1928 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, "rect", true, true );
1929}
1930
1931
1932void SVGActionWriter::ImplWriteEllipse( const Point& rCenter, long nRadX, long nRadY )
1933{
1934 Point aCenter;
1935
1936 ImplMap( rCenter, aCenter );
1937
1938 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCX, OUString::number( aCenter.X() ) );
1939 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrCY, OUString::number( aCenter.Y() ) );
1940 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRX, OUString::number( ImplMap( nRadX ) ) );
1941 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrRY, OUString::number( ImplMap( nRadY ) ) );
1942
1943 {
1944 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, "ellipse", true, true );
1945 }
1946}
1947
1948
1949void SVGActionWriter::ImplAddLineAttr( const LineInfo &rAttrs )
1950{
1951 if ( rAttrs.IsDefault() )
1952 return;
1953
1954 sal_Int32 nStrokeWidth = ImplMap( rAttrs.GetWidth() );
1955 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth,
1956 OUString::number( nStrokeWidth ) );
1957 // support for LineJoint
1958 switch(rAttrs.GetLineJoin())
1959 {
1960 case basegfx::B2DLineJoin::NONE:
1961 case basegfx::B2DLineJoin::Miter:
1962 {
1963 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, "miter");
1964 break;
1965 }
1966 case basegfx::B2DLineJoin::Bevel:
1967 {
1968 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, "bevel");
1969 break;
1970 }
1971 case basegfx::B2DLineJoin::Round:
1972 {
1973 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, "round");
1974 break;
1975 }
1976 }
1977
1978 // support for LineCap
1979 switch(rAttrs.GetLineCap())
1980 {
1981 default: /* css::drawing::LineCap_BUTT */
1982 {
1983 // butt is Svg default, so no need to write until the exporter might write styles.
1984 // If this happens, activate here
1985 // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, "butt");
1986 break;
1987 }
1988 case css::drawing::LineCap_ROUND:
1989 {
1990 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, "round");
1991 break;
1992 }
1993 case css::drawing::LineCap_SQUARE:
1994 {
1995 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, "square");
1996 break;
1997 }
1998 }
1999
2000}
2001
2002
2003void SVGActionWriter::ImplWritePolyPolygon( const tools::PolyPolygon& rPolyPoly, bool bLineOnly,
2004 bool bApplyMapping )
2005{
2006 tools::PolyPolygon aPolyPoly;
2007
2008 if( bApplyMapping )
2009 ImplMap( rPolyPoly, aPolyPoly );
2010 else
2011 aPolyPoly = rPolyPoly;
2012
2013 // add path data attribute
2014 mrExport.AddAttribute( XML_NAMESPACE_NONE, "d", GetPathString( aPolyPoly, bLineOnly ) );
2015
2016 {
2017 // write polyline/polygon element
2018 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, "path", true, true );
2019 }
2020}
2021
2022
2023void SVGActionWriter::ImplWriteShape( const SVGShapeDescriptor& rShape )
2024{
2025 tools::PolyPolygon aPolyPoly;
2026
2027 ImplMap( rShape.maShapePolyPoly, aPolyPoly );
2028
2029 const bool bLineOnly
2030 = (rShape.maShapeFillColor == COL_TRANSPARENT) && (!rShape.mapShapeGradient);
2031 tools::Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
2032
2033 maAttributeWriter.AddPaintAttr( rShape.maShapeLineColor, rShape.maShapeFillColor, &aBoundRect, rShape.mapShapeGradient.get() );
2034
2035 if( !rShape.maId.isEmpty() )
2036 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, rShape.maId );
2037
2038 if( rShape.mnStrokeWidth )
2039 {
2040 sal_Int32 nStrokeWidth = ImplMap( rShape.mnStrokeWidth );
2041 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStrokeWidth, OUString::number( nStrokeWidth ) );
2042 }
2043
2044 // support for LineJoin
2045 switch(rShape.maLineJoin)
2046 {
2047 case basegfx::B2DLineJoin::NONE:
2048 case basegfx::B2DLineJoin::Miter:
2049 {
2050 // miter is Svg default, so no need to write until the exporter might write styles.
2051 // If this happens, activate here
2052 // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, "miter");
2053 break;
2054 }
2055 case basegfx::B2DLineJoin::Bevel:
2056 {
2057 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, "bevel");
2058 break;
2059 }
2060 case basegfx::B2DLineJoin::Round:
2061 {
2062 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinejoin, "round");
2063 break;
2064 }
2065 }
2066
2067 // support for LineCap
2068 switch(rShape.maLineCap)
2069 {
2070 default: /* css::drawing::LineCap_BUTT */
2071 {
2072 // butt is Svg default, so no need to write until the exporter might write styles.
2073 // If this happens, activate here
2074 // mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, "butt");
2075 break;
2076 }
2077 case css::drawing::LineCap_ROUND:
2078 {
2079 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, "round");
2080 break;
2081 }
2082 case css::drawing::LineCap_SQUARE:
2083 {
2084 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStrokeLinecap, "square");
2085 break;
2086 }
2087 }
2088
2089 if( !rShape.maDashArray.empty() )
2090 {
2091 OUStringBuffer aDashArrayStr;
2092
2093 for( size_t k = 0; k < rShape.maDashArray.size(); ++k )
2094 {
2095 const sal_Int32 nDash = ImplMap( FRound( rShape.maDashArray[ k ] ) );
2096
2097 if( k )
2098 aDashArrayStr.append(",");
2099
2100 aDashArrayStr.append(OUString::number( nDash ));
2101 }
2102
2103 mrExport.AddAttribute( XML_NAMESPACE_NONE, "stroke-dasharray", aDashArrayStr.makeStringAndClear() );
2104 }
2105
2106 ImplWritePolyPolygon( aPolyPoly, bLineOnly, false );
2107}
2108
2109
2110
2111void SVGActionWriter::ImplCreateClipPathDef( const tools::PolyPolygon& rPolyPoly )
2112{
2113 OUString aClipPathId = aPrefixClipPathId + OUString::number( mnCurClipPathId++ );
2114
2115 SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true );
2116
2117 {
2118 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aClipPathId );
2119 mrExport.AddAttribute( XML_NAMESPACE_NONE, "clipPathUnits", "userSpaceOnUse" );
2120 SvXMLElementExport aElemClipPath( mrExport, XML_NAMESPACE_NONE, "clipPath", true, true );
2121
2122 ImplWritePolyPolygon(rPolyPoly, false);
2123 }
2124}
2125
2126void SVGActionWriter::ImplStartClipRegion(sal_Int32 nClipPathId)
2127{
2128 assert(!mpCurrentClipRegionElem)(static_cast <bool> (!mpCurrentClipRegionElem) ? void (
0) : __assert_fail ("!mpCurrentClipRegionElem", "/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
, 2128, __extension__ __PRETTY_FUNCTION__))
;
2129
2130 if (nClipPathId == 0)
2131 return;
2132
2133 OUString aUrl = OUStringLiteral(u"url(#") + aPrefixClipPathId + OUString::number( nClipPathId ) + ")";
2134 mrExport.AddAttribute( XML_NAMESPACE_NONE, "clip-path", aUrl );
2135 mpCurrentClipRegionElem.reset( new SvXMLElementExport( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true ) );
2136}
2137
2138void SVGActionWriter::ImplEndClipRegion()
2139{
2140 if (mpCurrentClipRegionElem)
2141 {
2142 mpCurrentClipRegionElem.reset();
2143 }
2144}
2145
2146void SVGActionWriter::ImplWriteClipPath( const tools::PolyPolygon& rPolyPoly )
2147{
2148 ImplEndClipRegion();
2149
2150 if( rPolyPoly.Count() == 0 )
2151 return;
2152
2153 ImplCreateClipPathDef(rPolyPoly);
2154 mrCurrentState.nRegionClipPathId = mnCurClipPathId - 1;
2155 ImplStartClipRegion( mrCurrentState.nRegionClipPathId );
2156}
2157
2158void SVGActionWriter::ImplWritePattern( const tools::PolyPolygon& rPolyPoly,
2159 const Hatch* pHatch,
2160 const Gradient* pGradient,
2161 sal_uInt32 nWriteFlags )
2162{
2163 if( !rPolyPoly.Count() )
2164 return;
2165
2166 SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
2167
2168 OUString aPatternId = "pattern" + OUString::number( mnCurPatternId++ );
2169
2170 {
2171 SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true );
2172
2173 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aPatternId );
2174
2175 tools::Rectangle aRect;
2176 ImplMap( rPolyPoly.GetBoundRect(), aRect );
2177
2178 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( aRect.Left() ) );
2179 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aRect.Top() ) );
2180 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::number( aRect.GetWidth() ) );
2181 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::number( aRect.GetHeight() ) );
2182
2183 mrExport.AddAttribute( XML_NAMESPACE_NONE, "patternUnits", OUString( "userSpaceOnUse") );
2184
2185 {
2186 SvXMLElementExport aElemPattern( mrExport, XML_NAMESPACE_NONE, "pattern", true, true );
2187
2188 // The origin of a pattern is positioned at (aRect.Left(), aRect.Top()).
2189 // So we need to adjust the pattern coordinate.
2190 OUString aTransform = "translate(" +
2191 OUString::number( -aRect.Left() ) +
2192 "," + OUString::number( -aRect.Top() ) +
2193 ")";
2194 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
2195
2196 {
2197 SvXMLElementExport aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
2198
2199 GDIMetaFile aTmpMtf;
2200 if( pHatch )
2201 mpVDev->AddHatchActions( rPolyPoly, *pHatch, aTmpMtf );
2202 else if ( pGradient )
2203 mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), *pGradient, aTmpMtf );
2204 ImplWriteActions( aTmpMtf, nWriteFlags, nullptr );
2205 }
2206 }
2207 }
2208
2209 OUString aPatternStyle = "fill:url(#" + aPatternId + ")";
2210
2211 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aPatternStyle );
2212 ImplWritePolyPolygon( rPolyPoly, false );
2213}
2214
2215
2216void SVGActionWriter::ImplWriteGradientEx( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient,
2217 sal_uInt32 nWriteFlags)
2218{
2219 if ( rGradient.GetStyle() == GradientStyle::Linear ||
2220 rGradient.GetStyle() == GradientStyle::Axial )
2221 {
2222 ImplWriteGradientLinear( rPolyPoly, rGradient );
2223 }
2224 else
2225 {
2226 ImplWritePattern( rPolyPoly, nullptr, &rGradient, nWriteFlags );
2227 }
2228}
2229
2230
2231void SVGActionWriter::ImplWriteGradientLinear( const tools::PolyPolygon& rPolyPoly,
2232 const Gradient& rGradient )
2233{
2234 if( !rPolyPoly.Count() )
2235 return;
2236
2237 SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true );
2238
2239 OUString aGradientId = "gradient" + OUString::number( mnCurGradientId++ );
2240
2241 {
2242 SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true );
2243
2244 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aGradientId );
2245 {
2246 tools::Rectangle aTmpRect, aRect;
2247 Point aTmpCenter, aCenter;
2248
2249 rGradient.GetBoundRect( rPolyPoly.GetBoundRect(), aTmpRect, aTmpCenter );
2250 ImplMap( aTmpRect, aRect );
2251 ImplMap( aTmpCenter, aCenter );
2252 const sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
2253
2254 tools::Polygon aPoly( 2 );
2255 // Setting x value of a gradient vector to rotation center to
2256 // place a gradient vector in a target polygon.
2257 // This would help editing it in SVG editors like inkscape.
2258 aPoly[ 0 ].setX( aCenter.X() );
2259 aPoly[ 1 ].setX( aCenter.X() );
2260 aPoly[ 0 ].setY( aRect.Top() );
2261 aPoly[ 1 ].setY( aRect.Bottom() );
2262 aPoly.Rotate( aCenter, nAngle );
2263
2264 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, OUString::number( aPoly[ 0 ].X() ) );
2265 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, OUString::number( aPoly[ 0 ].Y() ) );
2266 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, OUString::number( aPoly[ 1 ].X() ) );
2267 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, OUString::number( aPoly[ 1 ].Y() ) );
2268
2269 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits,
2270 OUString( "userSpaceOnUse" ) );
2271 }
2272
2273 {
2274 SvXMLElementExport aElemLinearGradient( mrExport, XML_NAMESPACE_NONE, aXMLElemLinearGradient, true, true );
2275
2276 const Color aStartColor = ImplGetColorWithIntensity( rGradient.GetStartColor(), rGradient.GetStartIntensity() );
2277 const Color aEndColor = ImplGetColorWithIntensity( rGradient.GetEndColor(), rGradient.GetEndIntensity() );
2278 double fBorderOffset = rGradient.GetBorder() / 100.0;
2279 const sal_uInt16 nSteps = rGradient.GetSteps();
2280 if( rGradient.GetStyle() == GradientStyle::Linear )
2281 {
2282 // Emulate non-smooth gradient
2283 if( 0 < nSteps && nSteps < 100 )
2284 {
2285 double fOffsetStep = ( 1.0 - fBorderOffset ) / static_cast<double>(nSteps);
2286 for( sal_uInt16 i = 0; i < nSteps; i++ ) {
2287 Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / static_cast<double>(nSteps) );
2288 ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep );
2289 aColor = ImplGetGradientColor( aStartColor, aEndColor, ( i + 1 ) / static_cast<double>(nSteps) );
2290 ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep );
2291 }
2292 }
2293 else
2294 {
2295 ImplWriteGradientStop( aStartColor, fBorderOffset );
2296 ImplWriteGradientStop( aEndColor, 1.0 );
2297 }
2298 }
2299 else
2300 {
2301 fBorderOffset /= 2;
2302 // Emulate non-smooth gradient
2303 if( 0 < nSteps && nSteps < 100 )
2304 {
2305 double fOffsetStep = ( 0.5 - fBorderOffset ) / static_cast<double>(nSteps);
2306 // Upper half
2307 for( sal_uInt16 i = 0; i < nSteps; i++ )
2308 {
2309 Color aColor = ImplGetGradientColor( aEndColor, aStartColor, i / static_cast<double>(nSteps) );
2310 ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
2311 aColor = ImplGetGradientColor( aEndColor, aStartColor, (i + 1 ) / static_cast<double>(nSteps) );
2312 ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
2313 }
2314 // Lower half
2315 for( sal_uInt16 i = 0; i < nSteps; i++ )
2316 {
2317 Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i / static_cast<double>(nSteps) );
2318 ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
2319 aColor = ImplGetGradientColor( aStartColor, aEndColor, (i + 1 ) / static_cast<double>(nSteps) );
2320 ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
2321 }
2322 }
2323 else
2324 {
2325 ImplWriteGradientStop( aEndColor, fBorderOffset );
2326 ImplWriteGradientStop( aStartColor, 0.5 );
2327 ImplWriteGradientStop( aEndColor, 1.0 - fBorderOffset );
2328 }
2329 }
2330 }
2331 }
2332
2333 OUString aGradientStyle = "fill:url(#" + aGradientId + ")";
2334
2335 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aGradientStyle );
2336 ImplWritePolyPolygon( rPolyPoly, false );
2337}
2338
2339
2340void SVGActionWriter::ImplWriteGradientStop( const Color& rColor, double fOffset )
2341{
2342 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, OUString::number( fOffset ) );
2343
2344 OUString aStyle, aColor;
2345 aStyle += "stop-color:";
2346 SVGAttributeWriter::ImplGetColorStr ( rColor, aColor );
2347 aStyle += aColor;
2348
2349 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle );
2350 {
2351 SvXMLElementExport aElemStartStop( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, true, true );
2352 }
2353}
2354
2355
2356Color SVGActionWriter::ImplGetColorWithIntensity( const Color& rColor,
2357 sal_uInt16 nIntensity )
2358{
2359 sal_uInt8 nNewRed = static_cast<sal_uInt8>( static_cast<long>(rColor.GetRed()) * nIntensity / 100 );
2360 sal_uInt8 nNewGreen = static_cast<sal_uInt8>( static_cast<long>(rColor.GetGreen()) * nIntensity / 100 );
2361 sal_uInt8 nNewBlue = static_cast<sal_uInt8>( static_cast<long>(rColor.GetBlue()) * nIntensity / 100 );
2362 return Color( nNewRed, nNewGreen, nNewBlue);
2363}
2364
2365
2366Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
2367 const Color& rEndColor,
2368 double fOffset )
2369{
2370 long nRedStep = rEndColor.GetRed() - rStartColor.GetRed();
2371 long nNewRed = rStartColor.GetRed() + static_cast<long>( nRedStep * fOffset );
2372 nNewRed = ( nNewRed < 0 ) ? 0 : ( nNewRed > 0xFF) ? 0xFF : nNewRed;
2373
2374 long nGreenStep = rEndColor.GetGreen() - rStartColor.GetGreen();
2375 long nNewGreen = rStartColor.GetGreen() + static_cast<long>( nGreenStep * fOffset );
2376 nNewGreen = ( nNewGreen < 0 ) ? 0 : ( nNewGreen > 0xFF) ? 0xFF : nNewGreen;
2377
2378 long nBlueStep = rEndColor.GetBlue() - rStartColor.GetBlue();
2379 long nNewBlue = rStartColor.GetBlue() + static_cast<long>( nBlueStep * fOffset );
2380 nNewBlue = ( nNewBlue < 0 ) ? 0 : ( nNewBlue > 0xFF) ? 0xFF : nNewBlue;
2381
2382 return Color( static_cast<sal_uInt8>(nNewRed), static_cast<sal_uInt8>(nNewGreen), static_cast<sal_uInt8>(nNewBlue) );
2383}
2384
2385void SVGActionWriter::StartMask(const Point& rDestPt, const Size& rDestSize,
2386 const Gradient& rGradient, sal_uInt32 nWriteFlags,
2387 OUString* pTextFillOpacity)
2388{
2389 OUString aStyle;
2390 if (rGradient.GetStartColor() == rGradient.GetEndColor())
2391 {
2392 // Special case: constant alpha value.
2393 const Color& rColor = rGradient.GetStartColor();
2394 const double fOpacity = 1.0 - static_cast<double>(rColor.GetLuminance()) / 255;
2395 if (pTextFillOpacity)
2396 {
2397 // Don't write anything, return what is a value suitable for <tspan fill-opacity="...">.
2398 *pTextFillOpacity = OUString::number(fOpacity);
2399 return;
2400 }
2401 else
2402 {
2403 aStyle = "opacity: " + OUString::number(fOpacity);
2404 }
2405 }
2406 else
2407 {
2408 OUString aMaskId = "mask" + OUString::number(mnCurMaskId++);
2409
2410 {
2411 SvXMLElementExport aElemDefs(mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, true, true);
2412
2413 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrId, aMaskId);
2414 {
2415 SvXMLElementExport aElemMask(mrExport, XML_NAMESPACE_NONE, "mask", true, true);
2416
2417 const tools::PolyPolygon aPolyPolygon(tools::PolyPolygon(tools::Rectangle(rDestPt, rDestSize)));
2418 Gradient aGradient(rGradient);
2419
2420 // swap gradient stops to adopt SVG mask
2421 Color aTmpColor(aGradient.GetStartColor());
2422 sal_uInt16 nTmpIntensity(aGradient.GetStartIntensity());
2423 aGradient.SetStartColor(aGradient.GetEndColor());
2424 aGradient.SetStartIntensity(aGradient.GetEndIntensity());
2425 aGradient.SetEndColor(aTmpColor);
2426 aGradient.SetEndIntensity(nTmpIntensity);
2427
2428 ImplWriteGradientEx(aPolyPolygon, aGradient, nWriteFlags);
2429 }
2430 }
2431
2432 aStyle = "mask:url(#" + aMaskId + ")";
2433 }
2434 mrExport.AddAttribute(XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle);
2435}
2436
2437void SVGActionWriter::ImplWriteMask(GDIMetaFile& rMtf, const Point& rDestPt, const Size& rDestSize,
2438 const Gradient& rGradient, sal_uInt32 nWriteFlags)
2439{
2440 Point aSrcPt(rMtf.GetPrefMapMode().GetOrigin());
2441 const Size aSrcSize(rMtf.GetPrefSize());
2442 const double fScaleX
2443 = aSrcSize.Width() ? static_cast<double>(rDestSize.Width()) / aSrcSize.Width() : 1.0;
2444 const double fScaleY
2445 = aSrcSize.Height() ? static_cast<double>(rDestSize.Height()) / aSrcSize.Height() : 1.0;
2446 long nMoveX, nMoveY;
2447
2448 if (fScaleX != 1.0 || fScaleY != 1.0)
2449 {
2450 rMtf.Scale(fScaleX, fScaleY);
2451 aSrcPt.setX(FRound(aSrcPt.X() * fScaleX));
2452 aSrcPt.setY(FRound(aSrcPt.Y() * fScaleY));
2453 }
2454
2455 nMoveX = rDestPt.X() - aSrcPt.X();
2456 nMoveY = rDestPt.Y() - aSrcPt.Y();
2457
2458 if (nMoveX || nMoveY)
2459 rMtf.Move(nMoveX, nMoveY);
2460
2461 {
2462 std::unique_ptr<SvXMLElementExport> pElemG;
2463 if (!maTextWriter.hasTextOpacity())
2464 {
2465 StartMask(rDestPt, rDestSize, rGradient, nWriteFlags);
2466 pElemG.reset(
2467 new SvXMLElementExport(mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, true));
2468 }
2469
2470 mpVDev->Push();
2471 ImplWriteActions( rMtf, nWriteFlags, nullptr );
2472 mpVDev->Pop();
2473 }
2474}
2475
2476
2477void SVGActionWriter::ImplWriteText( const Point& rPos, const OUString& rText,
2478 const long* pDXArray, long nWidth )
2479{
2480 const FontMetric aMetric( mpVDev->GetFontMetric() );
2481
2482 bool bTextSpecial = aMetric.IsShadow() || aMetric.IsOutline() || (aMetric.GetRelief() != FontRelief::NONE);
2483
2484 if( !bTextSpecial )
2485 {
2486 ImplWriteText( rPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2487 }
2488 else
2489 {
2490 if( aMetric.GetRelief() != FontRelief::NONE )
2491 {
2492 Color aReliefColor( COL_LIGHTGRAY );
2493 Color aTextColor( mpVDev->GetTextColor() );
2494
2495 if ( aTextColor == COL_BLACK )
2496 aTextColor = COL_WHITE;
2497
2498 // coverity[copy_paste_error : FALSE] - aReliefColor depending on aTextColor is correct
2499 if (aTextColor == COL_WHITE)
2500 aReliefColor = COL_BLACK;
2501
2502
2503 Point aPos( rPos );
2504 Point aOffset( 6, 6 );
2505
2506 if ( aMetric.GetRelief() == FontRelief::Engraved )
2507 {
2508 aPos -= aOffset;
2509 }
2510 else
2511 {
2512 aPos += aOffset;
2513 }
2514
2515 ImplWriteText( aPos, rText, pDXArray, nWidth, aReliefColor );
2516 ImplWriteText( rPos, rText, pDXArray, nWidth, aTextColor );
2517 }
2518 else
2519 {
2520 if( aMetric.IsShadow() )
2521 {
2522 long nOff = 1 + ((aMetric.GetLineHeight()-24)/24);
2523 if ( aMetric.IsOutline() )
2524 nOff += 6;
2525
2526 Color aTextColor( mpVDev->GetTextColor() );
2527 Color aShadowColor( COL_BLACK );
2528
2529 if ( (aTextColor == COL_BLACK) || (aTextColor.GetLuminance() < 8) )
2530 aShadowColor = COL_LIGHTGRAY;
2531
2532 Point aPos( rPos );
2533 aPos += Point( nOff, nOff );
2534 ImplWriteText( aPos, rText, pDXArray, nWidth, aShadowColor );
2535
2536 if( !aMetric.IsOutline() )
2537 {
2538 ImplWriteText( rPos, rText, pDXArray, nWidth, aTextColor );
2539 }
2540 }
2541
2542 if( aMetric.IsOutline() )
2543 {
2544 Point aPos = rPos + Point( -6, -6 );
2545 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2546 aPos = rPos + Point( +6, +6);
2547 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2548 aPos = rPos + Point( -6, +0);
2549 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2550 aPos = rPos + Point( -6, +6);
2551 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2552 aPos = rPos + Point( +0, +6);
2553 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2554 aPos = rPos + Point( +0, -6);
2555 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2556 aPos = rPos + Point( +6, -1);
2557 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2558 aPos = rPos + Point( +6, +0);
2559 ImplWriteText( aPos, rText, pDXArray, nWidth, mpVDev->GetTextColor() );
2560
2561 ImplWriteText( rPos, rText, pDXArray, nWidth, COL_WHITE );
2562 }
2563 }
2564 }
2565}
2566
2567
2568void SVGActionWriter::ImplWriteText( const Point& rPos, const OUString& rText,
2569 const long* pDXArray, long nWidth,
2570 Color aTextColor )
2571{
2572 sal_Int32 nLen = rText.getLength();
2573 Size aNormSize;
2574 Point aPos;
2575 Point aBaseLinePos( rPos );
2576 const FontMetric aMetric( mpVDev->GetFontMetric() );
2577 const vcl::Font& rFont = mpVDev->GetFont();
2578
2579 if( rFont.GetAlignment() == ALIGN_TOP )
2580 aBaseLinePos.AdjustY(aMetric.GetAscent() );
2581 else if( rFont.GetAlignment() == ALIGN_BOTTOM )
2582 aBaseLinePos.AdjustY( -(aMetric.GetDescent()) );
2583
2584 ImplMap( rPos, aPos );
2585
2586 std::unique_ptr<long[]> xTmpArray(new long[nLen]);
2587 // get text sizes
2588 if( pDXArray )
2589 {
2590 aNormSize = Size( mpVDev->GetTextWidth( rText ), 0 );
2591 memcpy(xTmpArray.get(), pDXArray, nLen * sizeof(long));
2592 }
2593 else
2594 {
2595 aNormSize = Size( mpVDev->GetTextArray( rText, xTmpArray.get() ), 0 );
2596 }
2597 long* pDX = xTmpArray.get();
2598
2599 // if text is rotated, set transform matrix at new g element
2600 if( rFont.GetOrientation() )
2601 {
2602 Point aRot( aPos );
2603 OUString aTransform = "rotate(" +
2604 OUString::number( rFont.GetOrientation() * -0.1 ) + " " +
2605 OUString::number( aRot.X() ) + " " +
2606 OUString::number( aRot.Y() ) + ")";
2607 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform, aTransform );
2608 }
2609
2610
2611 maAttributeWriter.AddPaintAttr( COL_TRANSPARENT, aTextColor );
2612
2613 // for each line of text there should be at least one group element
2614 SvXMLElementExport aSVGGElem( mrExport, XML_NAMESPACE_NONE, aXMLElemG, true, false );
2615
2616 bool bIsPlaceholderField = false;
2617
2618 if( mbIsPlaceholderShape )
2619 {
2620 bIsPlaceholderField = rText.match( sPlaceholderTag );
2621 // for a placeholder text field we export only one <text> svg element
2622 if( bIsPlaceholderField )
2623 {
2624 OUString sCleanTextContent;
2625 static const sal_Int32 nFrom = sPlaceholderTag.getLength();
2626 if( rText.getLength() > nFrom )
2627 {
2628 sCleanTextContent = rText.copy( nFrom );
2629 }
2630 mrExport.AddAttribute( XML_NAMESPACE_NONE, "class", "PlaceholderText" );
2631 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( aPos.X() ) );
2632 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aPos.Y() ) );
2633 {
2634 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, true, false );
2635 // At least for the single slide case we need really to export placeholder text
2636 mrExport.GetDocHandler()->characters( sCleanTextContent );
2637 }
2638 }
2639 }
2640
2641 if( !bIsPlaceholderField )
2642 {
2643 if( nLen > 1 )
2644 {
2645 aNormSize.setWidth( pDX[ nLen - 2 ] + mpVDev->GetTextWidth( OUString(rText[nLen - 1]) ) );
2646
2647 if( nWidth && aNormSize.Width() && ( nWidth != aNormSize.Width() ) )
2648 {
2649 long i;
2650 const double fFactor = static_cast<double>(nWidth) / aNormSize.Width();
2651
2652 for( i = 0; i < ( nLen - 1 ); i++ )
2653 pDX[ i ] = FRound( pDX[ i ] * fFactor );
2654 }
2655 else
2656 {
2657 css::uno::Reference< css::i18n::XBreakIterator > xBI( vcl::unohelper::CreateBreakIterator() );
2658 const css::lang::Locale& rLocale = Application::GetSettings().GetLanguageTag().getLocale();
2659 sal_Int32 nCurPos = 0, nLastPos = 0, nX = aPos.X();
2660
2661 // write single glyphs at absolute text positions
2662 for( bool bCont = true; bCont; )
2663 {
2664 sal_Int32 nCount = 1;
2665
2666 nLastPos = nCurPos;
2667 nCurPos = xBI->nextCharacters( rText, nCurPos, rLocale,
2668 css::i18n::CharacterIteratorMode::SKIPCELL,
2669 nCount, nCount );
2670
2671 nCount = nCurPos - nLastPos;
2672 bCont = ( nCurPos < rText.getLength() ) && nCount;
2673
2674 if( nCount )
2675 {
2676 const OUString aGlyph( rText.copy( nLastPos, nCount ) );
2677
2678 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( nX ) );
2679 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aPos.Y() ) );
2680
2681 {
2682 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, true, false );
2683 mrExport.GetDocHandler()->characters( aGlyph );
2684 }
2685
2686 if( bCont )
2687 {
2688 // #118796# do NOT access pDXArray, it may be zero (!)
2689 sal_Int32 nDXWidth = pDX[ nCurPos - 1 ];
2690 nDXWidth = ImplMap( nDXWidth );
2691 nX = aPos.X() + nDXWidth;
2692 }
2693 }
2694 }
2695 }
2696 }
2697 else
2698 {
2699 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( aPos.X() ) );
2700 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aPos.Y() ) );
2701
2702 {
2703 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, aXMLElemText, true, false );
2704 mrExport.GetDocHandler()->characters( rText );
2705 }
2706 }
2707 }
2708
2709
2710 if( mrExport.IsUseNativeTextDecoration() )
2711 return;
2712
2713 if( rFont.GetStrikeout() == STRIKEOUT_NONE && rFont.GetUnderline() == LINESTYLE_NONE )
2714 return;
2715
2716 tools::Polygon aPoly( 4 );
2717 const long nLineHeight = std::max<long>( FRound( aMetric.GetLineHeight() * 0.05 ), 1 );
2718
2719 if( rFont.GetStrikeout() )
2720 {
2721 const long nYLinePos = aBaseLinePos.Y() - FRound( aMetric.GetAscent() * 0.26 );
2722
2723 aPoly[ 0 ].setX( aBaseLinePos.X() ); aPoly[ 0 ].setY( nYLinePos - ( nLineHeight >> 1 ) );
2724 aPoly[ 1 ].setX( aBaseLinePos.X() + aNormSize.Width() - 1 ); aPoly[ 1 ].setY( aPoly[ 0 ].Y() );
2725 aPoly[ 2 ].setX( aPoly[ 1 ].X() ); aPoly[ 2 ].setY( aPoly[ 0 ].Y() + nLineHeight - 1 );
2726 aPoly[ 3 ].setX( aPoly[ 0 ].X() ); aPoly[ 3 ].setY( aPoly[ 2 ].Y() );
2727
2728 ImplWritePolyPolygon( aPoly, false );
2729 }
2730
2731 if( rFont.GetUnderline() )
2732 {
2733 const long nYLinePos = aBaseLinePos.Y() + ( nLineHeight << 1 );
2734
2735 aPoly[ 0 ].setX( aBaseLinePos.X() ); aPoly[ 0 ].setY( nYLinePos - ( nLineHeight >> 1 ) );
2736 aPoly[ 1 ].setX( aBaseLinePos.X() + aNormSize.Width() - 1 ); aPoly[ 1 ].setY( aPoly[ 0 ].Y() );
2737 aPoly[ 2 ].setX( aPoly[ 1 ].X() ); aPoly[ 2 ].setY( aPoly[ 0 ].Y() + nLineHeight - 1 );
2738 aPoly[ 3 ].setX( aPoly[ 0 ].X() ); aPoly[ 3 ].setY( aPoly[ 2 ].Y() );
2739
2740 ImplWritePolyPolygon( aPoly, false );
2741 }
2742}
2743
2744namespace
2745{
2746void GetGraphicFromXShape(const css::uno::Reference<css::drawing::XShape>* pShape, Graphic& rGraphic)
2747{
2748 if (!pShape)
2749 {
2750 return;
2751 }
2752
2753 uno::Reference<beans::XPropertySet> xPropertySet(*pShape, uno::UNO_QUERY);
2754 if (!xPropertySet.is())
2755 {
2756 return;
2757 }
2758
2759 uno::Reference<graphic::XGraphic> xGraphic;
2760 if (xPropertySet->getPropertySetInfo()->hasPropertyByName("Graphic"))
2761 {
2762 xPropertySet->getPropertyValue("Graphic") >>= xGraphic;
2763 }
2764 rGraphic= Graphic(xGraphic);
2765}
2766}
2767
2768void SVGActionWriter::ImplWriteBmp( const BitmapEx& rBmpEx,
2769 const Point& rPt, const Size& rSz,
2770 const Point& rSrcPt, const Size& rSrcSz,
2771 const css::uno::Reference<css::drawing::XShape>* pShape )
2772{
2773 if( !rBmpEx )
2774 return;
2775
2776 BitmapEx aBmpEx( rBmpEx );
2777 const tools::Rectangle aBmpRect( Point(), rBmpEx.GetSizePixel() );
2778 const tools::Rectangle aSrcRect( rSrcPt, rSrcSz );
2779
2780 if( aSrcRect != aBmpRect )
2781 aBmpEx.Crop( aSrcRect );
2782
2783 if( !aBmpEx )
2784 return;
2785
2786 SvMemoryStream aOStm( 65535, 65535 );
2787
2788 bool bCached = false;
2789 Graphic aGraphic;
2790 bool bJPG = false;
2791 if (pShape)
2792 {
2793 GetGraphicFromXShape(pShape, aGraphic);
2794 if (aGraphic.GetType() == GraphicType::Bitmap)
2795 {
2796 const BitmapEx& rGraphicBitmap = aGraphic.GetBitmapExRef();
2797 if (rGraphicBitmap.GetChecksum() == rBmpEx.GetChecksum())
2798 {
2799 bool bPNG = false;
2800 GfxLink aGfxLink = aGraphic.GetGfxLink();
2801 if (aGfxLink.GetType() == GfxLinkType::NativePng)
2802 {
2803 bPNG = true;
2804 }
2805 else if (aGfxLink.GetType() == GfxLinkType::NativeJpg)
2806 {
2807 bJPG = true;
2808 }
2809 if (bPNG || bJPG)
2810 {
2811 aOStm.WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
2812 bCached = true;
2813 }
2814 }
2815 }
2816 }
2817
2818 if( !(bCached || GraphicConverter::Export( aOStm, rBmpEx, ConvertDataFormat::PNG ) == ERRCODE_NONEErrCode(0)) )
2819 return;
2820
2821 Point aPt;
2822 Size aSz;
2823 Sequence< sal_Int8 > aSeq( static_cast<sal_Int8 const *>(aOStm.GetData()), aOStm.Tell() );
2824 OUStringBuffer aBuffer;
2825 if (bJPG)
2826 {
2827 aBuffer.append("data:image/jpeg;base64,");
2828 }
2829 else
2830 {
2831 aBuffer.append("data:image/png;base64,");
2832 }
2833 ::comphelper::Base64::encode( aBuffer, aSeq );
2834
2835 ImplMap( rPt, aPt );
2836 ImplMap( rSz, aSz );
2837
2838 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, OUString::number( aPt.X() ) );
2839 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, OUString::number( aPt.Y() ) );
2840 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, OUString::number( aSz.Width() ) );
2841 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, OUString::number( aSz.Height() ) );
2842
2843 // the image must be scaled to aSz in a non-uniform way
2844 mrExport.AddAttribute( XML_NAMESPACE_NONE, "preserveAspectRatio", "none" );
2845
2846 mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrXLinkHRef, aBuffer.makeStringAndClear() );
2847 {
2848 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_NONE, "image", true, true );
2849 }
2850}
2851
2852
2853void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
2854 sal_uInt32 nWriteFlags,
2855 const OUString* pElementId,
2856 const Reference< css::drawing::XShape >* pxShape,
2857 const GDIMetaFile* pTextEmbeddedBitmapMtf )
2858{
2859 // need a counter for the actions written per shape to avoid double ID
2860 // generation
2861 sal_Int32 nEntryCount(0);
2862
2863#if OSL_DEBUG_LEVEL1 > 0
2864 bool bIsTextShape = false;
2865 if( !mrExport.IsUsePositionedCharacters() && pxShape
2866 && Reference< XText >( *pxShape, UNO_QUERY ).is() )
2867 {
2868 bIsTextShape = true;
2869 }
2870#endif
2871 mbIsPlaceholderShape = false;
2872 if( ( pElementId != nullptr ) && ( *pElementId == sPlaceholderTag ) )
2873 {
2874 mbIsPlaceholderShape = true;
2875 // since we utilize pElementId in an improper way we reset it to NULL before to go on
2876 pElementId = nullptr;
2877 }
2878
2879 for( sal_uLong nCurAction = 0, nCount = rMtf.GetActionSize(); nCurAction < nCount; nCurAction++ )
2880 {
2881 const MetaAction* pAction = rMtf.GetAction( nCurAction );
2882 const MetaActionType nType = pAction->GetType();
2883
2884#if OSL_DEBUG_LEVEL1 > 0
2885 if( bIsTextShape )
2886 {
2887 try
2888 {
2889 SvXMLElementExport aElem( mrExport,
2890 XML_NAMESPACE_NONE, "desc", false, false );
2891 OUStringBuffer sType(OUString::number(static_cast<sal_uInt16>(nType)));
2892 if (pAction && (nType == MetaActionType::COMMENT))
2893 {
2894 sType.append(": ");
2895 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
2896 OString sComment = pA->GetComment();
2897 if (!sComment.isEmpty())
2898 {
2899 sType.append(OStringToOUString(
2900 sComment, RTL_TEXTENCODING_UTF8(((rtl_TextEncoding) 76))));
2901 }
2902 if (sComment.equalsIgnoreAsciiCase("FIELD_SEQ_BEGIN"))
2903 {
2904 sal_uInt8 const*const pData = pA->GetData();
2905 if (pData && (pA->GetDataSize()))
2906 {
2907 sal_uInt16 sz = static_cast<sal_uInt16>((pA->GetDataSize()) / 2);
2908 if (sz)
2909 {
2910 sType.append("; ");
2911 sType.append(
2912 reinterpret_cast<sal_Unicode const*>(pData),
2913 sz);
2914 }
2915 }
2916 }
2917 }
2918 if (sType.getLength())
2919 {
2920 mrExport.GetDocHandler()->characters(
2921 sType.makeStringAndClear());
2922 }
2923 }
2924 catch( ... )
2925 {
2926 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
2927 SAL_WARN( "filter.svg", pA->GetComment() )do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "filter.svg")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << pA->GetComment()) ==
1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("filter.svg"
), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "2927" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << pA->GetComment()), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
pA->GetComment(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "2927" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << pA->GetComment()) == 1) { ::sal_detail_log( (::
SAL_DETAIL_LOG_LEVEL_WARN), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "2927" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << pA->GetComment()), 0); } else { ::
std::ostringstream sal_detail_stream; sal_detail_stream <<
pA->GetComment(); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "2927" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
2928 }
2929
2930 }
2931#endif
2932 switch( nType )
2933 {
2934 case MetaActionType::PIXEL:
2935 {
2936 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
2937 {
2938 const MetaPixelAction* pA = static_cast<const MetaPixelAction*>(pAction);
2939
2940 maAttributeWriter.AddPaintAttr( pA->GetColor(), pA->GetColor() );
2941 ImplWriteLine( pA->GetPoint(), pA->GetPoint(), &pA->GetColor() );
2942 }
2943 }
2944 break;
2945
2946 case MetaActionType::POINT:
2947 {
2948 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
2949 {
2950 const MetaPointAction* pA = static_cast<const MetaPointAction*>(pAction);
2951
2952 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
2953 ImplWriteLine( pA->GetPoint(), pA->GetPoint() );
2954 }
2955 }
2956 break;
2957
2958 case MetaActionType::LINE:
2959 {
2960 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
2961 {
2962 const MetaLineAction* pA = static_cast<const MetaLineAction*>(pAction);
2963
2964 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetLineColor() );
2965 ImplWriteLine( pA->GetStartPoint(), pA->GetEndPoint() );
2966 }
2967 }
2968 break;
2969
2970 case MetaActionType::RECT:
2971 {
2972 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
2973 {
2974 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2975 ImplWriteRect( static_cast<const MetaRectAction*>(pAction)->GetRect() );
2976 }
2977 }
2978 break;
2979
2980 case MetaActionType::ROUNDRECT:
2981 {
2982 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
2983 {
2984 const MetaRoundRectAction* pA = static_cast<const MetaRoundRectAction*>(pAction);
2985
2986 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
2987 ImplWriteRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() );
2988 }
2989 }
2990 break;
2991
2992 case MetaActionType::ELLIPSE:
2993 {
2994 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
2995 {
2996 const MetaEllipseAction* pA = static_cast<const MetaEllipseAction*>(pAction);
2997 const tools::Rectangle& rRect = pA->GetRect();
2998
2999 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3000 ImplWriteEllipse( rRect.Center(), rRect.GetWidth() >> 1, rRect.GetHeight() >> 1 );
3001 }
3002 }
3003 break;
3004
3005 case MetaActionType::ARC:
3006 case MetaActionType::PIE:
3007 case MetaActionType::CHORD:
3008 case MetaActionType::POLYGON:
3009 {
3010 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3011 {
3012 tools::Polygon aPoly;
3013
3014 switch( nType )
3015 {
3016 case MetaActionType::ARC:
3017 {
3018 const MetaArcAction* pA = static_cast<const MetaArcAction*>(pAction);
3019 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Arc );
3020 }
3021 break;
3022
3023 case MetaActionType::PIE:
3024 {
3025 const MetaPieAction* pA = static_cast<const MetaPieAction*>(pAction);
3026 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Pie );
3027 }
3028 break;
3029
3030 case MetaActionType::CHORD:
3031 {
3032 const MetaChordAction* pA = static_cast<const MetaChordAction*>(pAction);
3033 aPoly = tools::Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), PolyStyle::Chord );
3034 }
3035 break;
3036
3037 case MetaActionType::POLYGON:
3038 aPoly = static_cast<const MetaPolygonAction*>(pAction)->GetPolygon();
3039 break;
3040 default: break;
3041 }
3042
3043 if( aPoly.GetSize() )
3044 {
3045 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3046 ImplWritePolyPolygon( aPoly, false );
3047 }
3048 }
3049 }
3050 break;
3051
3052 case MetaActionType::POLYLINE:
3053 {
3054 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3055 {
3056 const MetaPolyLineAction* pA = static_cast<const MetaPolyLineAction*>(pAction);
3057 const tools::Polygon& rPoly = pA->GetPolygon();
3058
3059 if( rPoly.GetSize() )
3060 {
3061 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), COL_TRANSPARENT );
3062 ImplAddLineAttr( pA->GetLineInfo() );
3063 ImplWritePolyPolygon( rPoly, true );
3064 }
3065 }
3066 }
3067 break;
3068
3069 case MetaActionType::POLYPOLYGON:
3070 {
3071 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3072 {
3073 const MetaPolyPolygonAction* pA = static_cast<const MetaPolyPolygonAction*>(pAction);
3074 const tools::PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
3075
3076 if( rPolyPoly.Count() )
3077 {
3078 maAttributeWriter.AddPaintAttr( mpVDev->GetLineColor(), mpVDev->GetFillColor() );
3079 ImplWritePolyPolygon( rPolyPoly, false );
3080 }
3081 }
3082 }
3083 break;
3084
3085 case MetaActionType::GRADIENT:
3086 {
3087 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3088 {
3089 const MetaGradientAction* pA = static_cast<const MetaGradientAction*>(pAction);
3090 const tools::Polygon aRectPoly( pA->GetRect() );
3091 const tools::PolyPolygon aRectPolyPoly( aRectPoly );
3092
3093 ImplWriteGradientEx( aRectPolyPoly, pA->GetGradient(), nWriteFlags );
3094 }
3095 }
3096 break;
3097
3098 case MetaActionType::GRADIENTEX:
3099 {
3100 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3101 {
3102 const MetaGradientExAction* pA = static_cast<const MetaGradientExAction*>(pAction);
3103 ImplWriteGradientEx( pA->GetPolyPolygon(), pA->GetGradient(), nWriteFlags );
3104 }
3105 }
3106 break;
3107
3108 case MetaActionType::HATCH:
3109 {
3110 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3111 {
3112 const MetaHatchAction* pA = static_cast<const MetaHatchAction*>(pAction);
3113 ImplWritePattern( pA->GetPolyPolygon(), &pA->GetHatch(), nullptr, nWriteFlags );
3114 }
3115 }
3116 break;
3117
3118 case MetaActionType::Transparent:
3119 {
3120 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3121 {
3122 const MetaTransparentAction* pA = static_cast<const MetaTransparentAction*>(pAction);
3123 const tools::PolyPolygon& rPolyPoly = pA->GetPolyPolygon();
3124
3125 if( rPolyPoly.Count() )
3126 {
3127 Color aNewLineColor( mpVDev->GetLineColor() ), aNewFillColor( mpVDev->GetFillColor() );
3128
3129 aNewLineColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
3130 aNewFillColor.SetTransparency( sal::static_int_cast<sal_uInt8>( FRound( pA->GetTransparence() * 2.55 ) ) );
3131
3132 maAttributeWriter.AddPaintAttr( aNewLineColor, aNewFillColor );
3133 ImplWritePolyPolygon( rPolyPoly, false );
3134 }
3135 }
3136 }
3137 break;
3138
3139 case MetaActionType::FLOATTRANSPARENT:
3140 {
3141 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3142 {
3143 const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pAction);
3144 GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
3145 ImplWriteMask( aTmpMtf, pA->GetPoint(), pA->GetSize(),
3146 pA->GetGradient(), nWriteFlags );
3147 }
3148 }
3149 break;
3150
3151 case MetaActionType::EPS:
3152 {
3153 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3154 {
3155 const MetaEPSAction* pA = static_cast<const MetaEPSAction*>(pAction);
3156 const GDIMetaFile& aGDIMetaFile( pA->GetSubstitute() );
3157 bool bFound = false;
3158
3159 for( sal_uInt32 k = 0, nCount2 = aGDIMetaFile.GetActionSize(); ( k < nCount2 ) && !bFound; ++k )
3160 {
3161 const MetaAction* pSubstAct = aGDIMetaFile.GetAction( k );
3162
3163 if( pSubstAct->GetType() == MetaActionType::BMPSCALE )
3164 {
3165 bFound = true;
3166 const MetaBmpScaleAction* pBmpScaleAction = static_cast<const MetaBmpScaleAction*>(pSubstAct);
3167 ImplWriteBmp( BitmapEx(pBmpScaleAction->GetBitmap()),
3168 pA->GetPoint(), pA->GetSize(),
3169 Point(), pBmpScaleAction->GetBitmap().GetSizePixel(), pxShape );
3170 }
3171 }
3172 }
3173 }
3174 break;
3175
3176 case MetaActionType::COMMENT:
3177 {
3178 const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pAction);
3179
3180 if( ( pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN") ) &&
3181 ( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 ) )
3182 {
3183 const MetaGradientExAction* pGradAction = nullptr;
3184 bool bDone = false;
3185
3186 while( !bDone && ( ++nCurAction < nCount ) )
3187 {
3188 pAction = rMtf.GetAction( nCurAction );
3189
3190 if( pAction->GetType() == MetaActionType::GRADIENTEX )
3191 pGradAction = static_cast<const MetaGradientExAction*>(pAction);
3192 else if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
3193 ( static_cast<const MetaCommentAction*>( pAction )->GetComment().
3194 equalsIgnoreAsciiCase("XGRAD_SEQ_END") ) )
3195 {
3196 bDone = true;
3197 }
3198 }
3199
3200 if( pGradAction )
3201 ImplWriteGradientEx( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), nWriteFlags );
3202 }
3203 else if( ( pA->GetComment().equalsIgnoreAsciiCase("XPATHFILL_SEQ_BEGIN") ) &&
3204 ( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS0x01000000 ) &&
3205 pA->GetDataSize() )
3206 {
3207 // write open shape in every case
3208 if (mapCurShape)
3209 {
3210 ImplWriteShape( *mapCurShape );
3211 mapCurShape.reset();
3212 }
3213
3214 SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(), StreamMode::READ );
3215 SvtGraphicFill aFill;
3216
3217 ReadSvtGraphicFill( aMemStm, aFill );
3218
3219 bool bGradient = SvtGraphicFill::fillGradient == aFill.getFillType() &&
3220 ( SvtGraphicFill::GradientType::Linear == aFill.getGradientType() ||
3221 SvtGraphicFill::GradientType::Radial == aFill.getGradientType() );
3222 bool bSkip = ( SvtGraphicFill::fillSolid == aFill.getFillType() || bGradient );
3223
3224 if( bSkip )
3225 {
3226 tools::PolyPolygon aShapePolyPoly;
3227
3228 aFill.getPath( aShapePolyPoly );
3229
3230 if( aShapePolyPoly.Count() )
3231 {
3232 mapCurShape.reset( new SVGShapeDescriptor );
3233
3234 if( pElementId )
3235 {
3236 mapCurShape->maId = *pElementId + "_" + OUString::number(nEntryCount++);
3237 }
3238
3239 mapCurShape->maShapePolyPoly = aShapePolyPoly;
3240 mapCurShape->maShapeFillColor = aFill.getFillColor();
3241 mapCurShape->maShapeFillColor.SetTransparency( static_cast<sal_uInt8>(FRound( 255.0 * aFill.getTransparency() )) );
3242
3243 if( bGradient )
3244 {
3245 // step through following actions until the first Gradient/GradientEx action is found
3246 while (!mapCurShape->mapShapeGradient && bSkip
3247 && (++nCurAction < nCount))
3248 {
3249 pAction = rMtf.GetAction( nCurAction );
3250
3251 if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
3252 ( static_cast<const MetaCommentAction*>(pAction)->GetComment().
3253 equalsIgnoreAsciiCase("XPATHFILL_SEQ_END") ) )
3254 {
3255 bSkip = false;
3256 }
3257 else if( pAction->GetType() == MetaActionType::GRADIENTEX )
3258 {
3259 mapCurShape->mapShapeGradient.reset( new Gradient(
3260 static_cast< const MetaGradientExAction* >( pAction )->GetGradient() ) );
3261 }
3262 else if( pAction->GetType() == MetaActionType::GRADIENT )
3263 {
3264 mapCurShape->mapShapeGradient.reset( new Gradient(
3265 static_cast< const MetaGradientAction* >( pAction )->GetGradient() ) );
3266 }
3267 }
3268 }
3269 }
3270 else
3271 bSkip = false;
3272 }
3273
3274 // skip rest of comment
3275 while( bSkip && ( ++nCurAction < nCount ) )
3276 {
3277 pAction = rMtf.GetAction( nCurAction );
3278
3279 if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
3280 ( static_cast<const MetaCommentAction*>( pAction )->GetComment().
3281 equalsIgnoreAsciiCase("XPATHFILL_SEQ_END") ) )
3282 {
3283 bSkip = false;
3284 }
3285 }
3286 }
3287 else if( ( pA->GetComment().equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_BEGIN") ) &&
3288 ( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 ) && !( nWriteFlags & SVGWRITER_NO_SHAPE_COMMENTS0x01000000 ) &&
3289 pA->GetDataSize() )
3290 {
3291 SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pA->GetData()), pA->GetDataSize(), StreamMode::READ );
3292 SvtGraphicStroke aStroke;
3293 tools::PolyPolygon aStartArrow, aEndArrow;
3294
3295 ReadSvtGraphicStroke( aMemStm, aStroke );
3296 aStroke.getStartArrow( aStartArrow );
3297 aStroke.getEndArrow( aEndArrow );
3298
3299 // Currently no support for strokes with start/end arrow(s)
3300 // added that support
3301 tools::Polygon aPoly;
3302
3303 aStroke.getPath(aPoly);
3304
3305 if (mapCurShape)
3306 {
3307 if(1 != mapCurShape->maShapePolyPoly.Count()
3308 || !mapCurShape->maShapePolyPoly[0].IsEqual(aPoly))
3309 {
3310 // this path action is not covering the same path than the already existing
3311 // fill polypolygon, so write out the fill polygon
3312 ImplWriteShape( *mapCurShape );
3313 mapCurShape.reset();
3314 }
3315 }
3316
3317 if (!mapCurShape)
3318 {
3319
3320 mapCurShape.reset( new SVGShapeDescriptor );
3321
3322 if( pElementId )
3323 {
3324 mapCurShape->maId = *pElementId + "_" + OUString::number(nEntryCount++);
3325 }
3326
3327 mapCurShape->maShapePolyPoly = aPoly;
3328 }
3329
3330 mapCurShape->maShapeLineColor = mpVDev->GetLineColor();
3331 mapCurShape->maShapeLineColor.SetTransparency( static_cast<sal_uInt8>(FRound( aStroke.getTransparency() * 255.0 )) );
3332 mapCurShape->mnStrokeWidth = FRound( aStroke.getStrokeWidth() );
3333 aStroke.getDashArray( mapCurShape->maDashArray );
3334
3335 // added support for LineJoin
3336 switch(aStroke.getJoinType())
3337 {
3338 default: /* SvtGraphicStroke::joinMiter, SvtGraphicStroke::joinNone */
3339 {
3340 mapCurShape->maLineJoin = basegfx::B2DLineJoin::Miter;
3341 break;
3342 }
3343 case SvtGraphicStroke::joinRound:
3344 {
3345 mapCurShape->maLineJoin = basegfx::B2DLineJoin::Round;
3346 break;
3347 }
3348 case SvtGraphicStroke::joinBevel:
3349 {
3350 mapCurShape->maLineJoin = basegfx::B2DLineJoin::Bevel;
3351 break;
3352 }
3353 }
3354
3355 // added support for LineCap
3356 switch(aStroke.getCapType())
3357 {
3358 default: /* SvtGraphicStroke::capButt */
3359 {
3360 mapCurShape->maLineCap = css::drawing::LineCap_BUTT;
3361 break;
3362 }
3363 case SvtGraphicStroke::capRound:
3364 {
3365 mapCurShape->maLineCap = css::drawing::LineCap_ROUND;
3366 break;
3367 }
3368 case SvtGraphicStroke::capSquare:
3369 {
3370 mapCurShape->maLineCap = css::drawing::LineCap_SQUARE;
3371 break;
3372 }
3373 }
3374
3375 if(mapCurShape && mapCurShape->maShapePolyPoly.Count() && (aStartArrow.Count() || aEndArrow.Count()))
3376 {
3377 ImplWriteShape( *mapCurShape );
3378
3379 mapCurShape->maShapeFillColor = mapCurShape->maShapeLineColor;
3380 mapCurShape->maShapeLineColor = COL_TRANSPARENT;
3381 mapCurShape->mnStrokeWidth = 0;
3382 mapCurShape->maDashArray.clear();
3383 mapCurShape->maLineJoin = basegfx::B2DLineJoin::Miter;
3384 mapCurShape->maLineCap = css::drawing::LineCap_BUTT;
3385
3386 if(aStartArrow.Count())
3387 {
3388 mapCurShape->maShapePolyPoly = aStartArrow;
3389
3390 if( pElementId ) // #i124825# pElementId is optional, may be zero
3391 {
3392 mapCurShape->maId = *pElementId + "_" + OUString::number(nEntryCount++);
3393 }
3394
3395 ImplWriteShape( *mapCurShape );
3396 }
3397
3398 if(aEndArrow.Count())
3399 {
3400 mapCurShape->maShapePolyPoly = aEndArrow;
3401
3402 if( pElementId ) // #i124825# pElementId is optional, may be zero
3403 {
3404 mapCurShape->maId = *pElementId + "_" + OUString::number(nEntryCount++);
3405 }
3406
3407 ImplWriteShape( *mapCurShape );
3408 }
3409
3410 mapCurShape.reset();
3411 }
3412
3413 // write open shape in every case
3414 if (mapCurShape)
3415 {
3416 ImplWriteShape( *mapCurShape );
3417 mapCurShape.reset();
3418 }
3419
3420 // skip rest of comment
3421 bool bSkip = true;
3422
3423 while( bSkip && ( ++nCurAction < nCount ) )
3424 {
3425 pAction = rMtf.GetAction( nCurAction );
3426
3427 if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
3428 ( static_cast<const MetaCommentAction*>(pAction)->GetComment().
3429 equalsIgnoreAsciiCase("XPATHSTROKE_SEQ_END") ) )
3430 {
3431 bSkip = false;
3432 }
3433 }
3434 }
3435 else if( !mrExport.IsUsePositionedCharacters() && ( nWriteFlags & SVGWRITER_WRITE_TEXT0x00000002 ) )
3436 {
3437 if( pA->GetComment().equalsIgnoreAsciiCase( "XTEXT_PAINTSHAPE_BEGIN" ) )
3438 {
3439 if( pxShape )
3440 {
3441 Reference< XText > xText( *pxShape, UNO_QUERY );
3442 if( xText.is() )
3443 maTextWriter.setTextShape( xText, pTextEmbeddedBitmapMtf );
3444 }
3445 maTextWriter.createParagraphEnumeration();
3446 {
3447 // nTextFound == -1 => no text found
3448 // nTextFound == 0 => no text found and end of text shape reached
3449 // nTextFound == 1 => text found!
3450 sal_Int32 nTextFound = -1;
3451 while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
3452 {
3453 nTextFound
3454 = maTextWriter.setTextPosition(rMtf, nCurAction, nWriteFlags);
3455 }
3456 // We found some text in the current text shape.
3457 if( nTextFound > 0 )
3458 {
3459 maTextWriter.setTextProperties( rMtf, nCurAction );
3460 maTextWriter.startTextShape();
3461 }
3462 // We reached the end of the current text shape
3463 // without finding any text. So we need to go back
3464 // by one action in order to handle the
3465 // XTEXT_PAINTSHAPE_END action because on the next
3466 // loop the nCurAction is incremented by one.
3467 else
3468 {
3469 --nCurAction;
3470 }
3471 }
3472 }
3473 else if( pA->GetComment().equalsIgnoreAsciiCase( "XTEXT_PAINTSHAPE_END" ) )
3474 {
3475 maTextWriter.endTextShape();
3476 }
3477 else if( pA->GetComment().equalsIgnoreAsciiCase( "XTEXT_EOP" ) )
3478 {
3479 const MetaAction* pNextAction = rMtf.GetAction( nCurAction + 1 );
3480 if( !( ( pNextAction->GetType() == MetaActionType::COMMENT ) &&
3481 ( static_cast<const MetaCommentAction*>(pNextAction)->GetComment().equalsIgnoreAsciiCase("XTEXT_PAINTSHAPE_END") ) ))
3482 {
3483 // nTextFound == -1 => no text found and end of paragraph reached
3484 // nTextFound == 0 => no text found and end of text shape reached
3485 // nTextFound == 1 => text found!
3486 sal_Int32 nTextFound = -1;
3487 while( ( nTextFound < 0 ) && ( nCurAction < nCount ) )
3488 {
3489 nTextFound
3490 = maTextWriter.setTextPosition(rMtf, nCurAction, nWriteFlags);
3491 }
3492 // We found a paragraph with some text in the
3493 // current text shape.
3494 if( nTextFound > 0 )
3495 {
3496 maTextWriter.setTextProperties( rMtf, nCurAction );
3497 maTextWriter.startTextParagraph();
3498 }
3499 // We reached the end of the current text shape
3500 // without finding any text. So we need to go back
3501 // by one action in order to handle the
3502 // XTEXT_PAINTSHAPE_END action because on the next
3503 // loop the nCurAction is incremented by one.
3504 else
3505 {
3506 --nCurAction;
3507 }
3508
3509 }
3510 }
3511 else if( pA->GetComment().equalsIgnoreAsciiCase( "XTEXT_EOL" ) )
3512 {
3513 const MetaAction* pNextAction = rMtf.GetAction( nCurAction + 1 );
3514 if( !( ( pNextAction->GetType() == MetaActionType::COMMENT ) &&
3515 ( static_cast<const MetaCommentAction*>(pNextAction)->GetComment().equalsIgnoreAsciiCase("XTEXT_EOP") ) ) )
3516 {
3517 // nTextFound == -2 => no text found and end of line reached
3518 // nTextFound == -1 => no text found and end of paragraph reached
3519 // nTextFound == 1 => text found!
3520 sal_Int32 nTextFound = -2;
3521 while( ( nTextFound < -1 ) && ( nCurAction < nCount ) )
3522 {
3523 nTextFound
3524 = maTextWriter.setTextPosition(rMtf, nCurAction, nWriteFlags);
3525 }
3526 // We found a line with some text in the current
3527 // paragraph.
3528 if( nTextFound > 0 )
3529 {
3530 maTextWriter.startTextPosition();
3531 }
3532 // We reached the end of the current paragraph
3533 // without finding any text. So we need to go back
3534 // by one action in order to handle the XTEXT_EOP
3535 // action because on the next loop the nCurAction is
3536 // incremented by one.
3537 else
3538 {
3539 --nCurAction;
3540 }
3541 }
3542 }
3543 }
3544 }
3545 break;
3546
3547 case MetaActionType::BMP:
3548 {
3549 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3550 {
3551 const MetaBmpAction* pA = static_cast<const MetaBmpAction*>(pAction);
3552
3553 ImplWriteBmp( BitmapEx(pA->GetBitmap()),
3554 pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmap().GetSizePixel() ),
3555 Point(), pA->GetBitmap().GetSizePixel(), pxShape );
3556 }
3557 }
3558 break;
3559
3560 case MetaActionType::BMPSCALE:
3561 {
3562 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3563 {
3564 const MetaBmpScaleAction* pA = static_cast<const MetaBmpScaleAction*>(pAction);
3565
3566 // Bitmaps embedded into text shapes are collected and exported elsewhere.
3567 if( maTextWriter.isTextShapeStarted() )
3568 {
3569 maTextWriter.writeBitmapPlaceholder( pA );
3570 }
3571 else
3572 {
3573 ImplWriteBmp( BitmapEx(pA->GetBitmap()),
3574 pA->GetPoint(), pA->GetSize(),
3575 Point(), pA->GetBitmap().GetSizePixel(), pxShape );
3576 }
3577 }
3578 }
3579 break;
3580
3581 case MetaActionType::BMPSCALEPART:
3582 {
3583 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3584 {
3585 const MetaBmpScalePartAction* pA = static_cast<const MetaBmpScalePartAction*>(pAction);
3586
3587 ImplWriteBmp( BitmapEx(pA->GetBitmap()),
3588 pA->GetDestPoint(), pA->GetDestSize(),
3589 pA->GetSrcPoint(), pA->GetSrcSize(), pxShape );
3590 }
3591 }
3592 break;
3593
3594 case MetaActionType::BMPEX:
3595 {
3596 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3597 {
3598 const MetaBmpExAction* pA = static_cast<const MetaBmpExAction*>(pAction);
3599
3600 ImplWriteBmp( pA->GetBitmapEx(),
3601 pA->GetPoint(), mpVDev->PixelToLogic( pA->GetBitmapEx().GetSizePixel() ),
3602 Point(), pA->GetBitmapEx().GetSizePixel(), pxShape );
3603 }
3604 }
3605 break;
3606
3607 case MetaActionType::BMPEXSCALE:
3608 {
3609 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3610 {
3611 const MetaBmpExScaleAction* pA = static_cast<const MetaBmpExScaleAction*>(pAction);
3612
3613 // Bitmaps embedded into text shapes are collected and exported elsewhere.
3614 if( maTextWriter.isTextShapeStarted() )
3615 {
3616 maTextWriter.writeBitmapPlaceholder( pA );
3617 }
3618 else
3619 {
3620 ImplWriteBmp( pA->GetBitmapEx(),
3621 pA->GetPoint(), pA->GetSize(),
3622 Point(), pA->GetBitmapEx().GetSizePixel(), pxShape );
3623 }
3624 }
3625 }
3626 break;
3627
3628 case MetaActionType::BMPEXSCALEPART:
3629 {
3630 if( nWriteFlags & SVGWRITER_WRITE_FILL0x00000001 )
3631 {
3632 const MetaBmpExScalePartAction* pA = static_cast<const MetaBmpExScalePartAction*>(pAction);
3633
3634 ImplWriteBmp( pA->GetBitmapEx(),
3635 pA->GetDestPoint(), pA->GetDestSize(),
3636 pA->GetSrcPoint(), pA->GetSrcSize(), pxShape );
3637 }
3638 }
3639 break;
3640
3641 case MetaActionType::TEXT:
3642 {
3643 if( nWriteFlags & SVGWRITER_WRITE_TEXT0x00000002 )
3644 {
3645 const MetaTextAction* pA = static_cast<const MetaTextAction*>(pAction);
3646 sal_Int32 aLength = std::min( pA->GetText().getLength(), pA->GetLen() );
3647 const OUString aText = pA->GetText().copy( pA->GetIndex(), aLength );
3648
3649 if( !aText.isEmpty() )
3650 {
3651 if( mrExport.IsUsePositionedCharacters() )
3652 {
3653 vcl::Font aFont = ImplSetCorrectFontHeight();
3654 maAttributeWriter.SetFontAttr( aFont );
3655 ImplWriteText( pA->GetPoint(), aText, nullptr, 0 );
3656 }
3657 else
3658 {
3659 maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3660 }
3661 }
3662 }
3663 }
3664 break;
3665
3666 case MetaActionType::TEXTRECT:
3667 {
3668 if( nWriteFlags & SVGWRITER_WRITE_TEXT0x00000002 )
3669 {
3670 const MetaTextRectAction* pA = static_cast<const MetaTextRectAction*>(pAction);
3671
3672 if (!pA->GetText().isEmpty())
3673 {
3674 if( mrExport.IsUsePositionedCharacters() )
3675 {
3676 vcl::Font aFont = ImplSetCorrectFontHeight();
3677 maAttributeWriter.SetFontAttr( aFont );
3678 ImplWriteText( pA->GetRect().TopLeft(), pA->GetText(), nullptr, 0 );
3679 }
3680 maTextWriter.writeTextPortion( pA->GetRect().TopLeft(), pA->GetText() );
3681 }
3682 }
3683 }
3684 break;
3685
3686 case MetaActionType::TEXTARRAY:
3687 {
3688 if( nWriteFlags & SVGWRITER_WRITE_TEXT0x00000002 )
3689 {
3690 const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pAction);
3691 sal_Int32 aLength = std::min( pA->GetText().getLength(), pA->GetLen() );
3692 const OUString aText = pA->GetText().copy( pA->GetIndex(), aLength );
3693
3694 if( !aText.isEmpty() )
3695 {
3696 if( mrExport.IsUsePositionedCharacters() )
3697 {
3698 vcl::Font aFont = ImplSetCorrectFontHeight();
3699 maAttributeWriter.SetFontAttr( aFont );
3700 ImplWriteText( pA->GetPoint(), aText, pA->GetDXArray(), 0 );
3701 }
3702 else
3703 {
3704 maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3705 }
3706 }
3707 }
3708 }
3709 break;
3710
3711 case MetaActionType::STRETCHTEXT:
3712 {
3713 if( nWriteFlags & SVGWRITER_WRITE_TEXT0x00000002 )
3714 {
3715 const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pAction);
3716 sal_Int32 aLength = std::min( pA->GetText().getLength(), pA->GetLen() );
3717 const OUString aText = pA->GetText().copy( pA->GetIndex(), aLength );
3718
3719 if( !aText.isEmpty() )
3720 {
3721 if( mrExport.IsUsePositionedCharacters() )
3722 {
3723 vcl::Font aFont = ImplSetCorrectFontHeight();
3724 maAttributeWriter.SetFontAttr( aFont );
3725 ImplWriteText( pA->GetPoint(), aText, nullptr, pA->GetWidth() );
3726 }
3727 else
3728 {
3729 maTextWriter.writeTextPortion( pA->GetPoint(), aText );
3730 }
3731 }
3732 }
3733 }
3734 break;
3735
3736 case MetaActionType::CLIPREGION:
3737 case MetaActionType::ISECTRECTCLIPREGION:
3738 case MetaActionType::ISECTREGIONCLIPREGION:
3739 case MetaActionType::MOVECLIPREGION:
3740 {
3741 const_cast<MetaAction*>(pAction)->Execute( mpVDev );
3742 const vcl::Region& rClipRegion = mpVDev->GetActiveClipRegion();
3743 ImplWriteClipPath( rClipRegion.GetAsPolyPolygon() );
3744
3745 mbClipAttrChanged = true;
3746 }
3747 break;
3748
3749 case MetaActionType::PUSH:
3750 {
3751 const MetaPushAction* pA = static_cast<const MetaPushAction*>(pAction);
3752 PushFlags mnFlags = pA->GetFlags();
3753
3754 const_cast<MetaAction*>(pAction)->Execute( mpVDev );
3755
3756 maContextHandler.pushState( mnFlags );
3757 }
3758 break;
3759
3760 case MetaActionType::POP:
3761 {
3762 const_cast<MetaAction*>(pAction)->Execute( mpVDev );
3763
3764 PushFlags mnFlags = maContextHandler.getPushFlags();
3765
3766 maContextHandler.popState();
3767
3768 if( mnFlags & PushFlags::CLIPREGION )
3769 {
3770 ImplEndClipRegion();
3771 ImplStartClipRegion( mrCurrentState.nRegionClipPathId );
3772 }
3773 }
3774 break;
3775
3776 case MetaActionType::REFPOINT:
3777 case MetaActionType::MAPMODE:
3778 case MetaActionType::LINECOLOR:
3779 case MetaActionType::FILLCOLOR:
3780 case MetaActionType::TEXTLINECOLOR:
3781 case MetaActionType::TEXTFILLCOLOR:
3782 case MetaActionType::TEXTCOLOR:
3783 case MetaActionType::TEXTALIGN:
3784 case MetaActionType::FONT:
3785 case MetaActionType::LAYOUTMODE:
3786 {
3787 const_cast<MetaAction*>(pAction)->Execute( mpVDev );
3788 }
3789 break;
3790
3791 case MetaActionType::RASTEROP:
3792 case MetaActionType::MASK:
3793 case MetaActionType::MASKSCALE:
3794 case MetaActionType::MASKSCALEPART:
3795 case MetaActionType::WALLPAPER:
3796 case MetaActionType::TEXTLINE:
3797 case MetaActionType::TEXTLANGUAGE:
3798 {
3799 // !!! >>> we don't want to support these actions
3800 }
3801 break;
3802
3803 default:
3804 SAL_WARN("filter.svg", "SVGActionWriter::ImplWriteActions: unsupported MetaAction # " << sal_Int32(nType))do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "filter.svg")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "SVGActionWriter::ImplWriteActions: unsupported MetaAction # "
<< sal_Int32(nType)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "3804" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SVGActionWriter::ImplWriteActions: unsupported MetaAction # "
<< sal_Int32(nType)), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "SVGActionWriter::ImplWriteActions: unsupported MetaAction # "
<< sal_Int32(nType); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "3804" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "SVGActionWriter::ImplWriteActions: unsupported MetaAction # "
<< sal_Int32(nType)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "3804" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "SVGActionWriter::ImplWriteActions: unsupported MetaAction # "
<< sal_Int32(nType)), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "SVGActionWriter::ImplWriteActions: unsupported MetaAction # "
<< sal_Int32(nType); ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("filter.svg"), ("/home/maarten/src/libreoffice/core/filter/source/svg/svgwriter.cxx"
":" "3804" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
3805 break;
3806 }
3807 }
3808}
3809
3810
3811vcl::Font SVGActionWriter::ImplSetCorrectFontHeight() const
3812{
3813 vcl::Font aFont( mpVDev->GetFont() );
3814 Size aSz;
3815
3816 ImplMap( Size( 0, aFont.GetFontHeight() ), aSz );
3817
3818 aFont.SetFontHeight( aSz.Height() );
3819
3820 return aFont;
3821}
3822
3823
3824void SVGActionWriter::WriteMetaFile( const Point& rPos100thmm,
3825 const Size& rSize100thmm,
3826 const GDIMetaFile& rMtf,
3827 sal_uInt32 nWriteFlags,
3828 const OUString* pElementId,
3829 const Reference< css::drawing::XShape >* pXShape,
3830 const GDIMetaFile* pTextEmbeddedBitmapMtf )
3831{
3832 MapMode aMapMode( rMtf.GetPrefMapMode() );
3833 Size aPrefSize( rMtf.GetPrefSize() );
3834 Fraction aFractionX( aMapMode.GetScaleX() );
3835 Fraction aFractionY( aMapMode.GetScaleY() );
3836
3837 mpVDev->Push();
3838
3839 Size aSize( OutputDevice::LogicToLogic(rSize100thmm, MapMode(MapUnit::Map100thMM), aMapMode) );
3840 aFractionX *= Fraction( aSize.Width(), aPrefSize.Width() );
3841 aMapMode.SetScaleX( aFractionX );
3842 aFractionY *= Fraction( aSize.Height(), aPrefSize.Height() );
3843 aMapMode.SetScaleY( aFractionY );
3844
3845 Point aOffset( OutputDevice::LogicToLogic(rPos100thmm, MapMode(MapUnit::Map100thMM), aMapMode ) );
3846 aOffset += aMapMode.GetOrigin();
3847 aMapMode.SetOrigin( aOffset );
3848
3849 mpVDev->SetMapMode( aMapMode );
3850
3851 mapCurShape.reset();
3852
3853 ImplWriteActions( rMtf, nWriteFlags, pElementId, pXShape, pTextEmbeddedBitmapMtf );
3854 maTextWriter.endTextParagraph();
3855 ImplEndClipRegion();
3856
3857 // draw open shape that doesn't have a border
3858 if (mapCurShape)
3859 {
3860 ImplWriteShape( *mapCurShape );
3861 mapCurShape.reset();
3862 }
3863
3864 mpVDev->Pop();
3865}
3866
3867
3868SVGWriter::SVGWriter( const Sequence<Any>& args, const Reference< XComponentContext >& rxCtx )
3869 : mxContext(rxCtx)
3870{
3871 if(args.getLength()==1)
3872 args[0]>>=maFilterData;
3873}
3874
3875
3876SVGWriter::~SVGWriter()
3877{
3878}
3879
3880
3881void SAL_CALL SVGWriter::write( const Reference<XDocumentHandler>& rxDocHandler,
3882 const Sequence<sal_Int8>& rMtfSeq )
3883{
3884 SvMemoryStream aMemStm( const_cast<sal_Int8 *>(rMtfSeq.getConstArray()), rMtfSeq.getLength(), StreamMode::READ );
3885 GDIMetaFile aMtf;
3886
3887 ReadGDIMetaFile( aMemStm, aMtf );
3888
3889 rtl::Reference<SVGExport> pWriter(new SVGExport( mxContext, rxDocHandler, maFilterData ));
3890 pWriter->writeMtf( aMtf );
3891}
3892
3893// XServiceInfo
3894sal_Bool SVGWriter::supportsService(const OUString& sServiceName)
3895{
3896 return cppu::supportsService(this, sServiceName);
3897}
3898OUString SVGWriter::getImplementationName()
3899{
3900 return "com.sun.star.comp.Draw.SVGWriter";
3901}
3902css::uno::Sequence< OUString > SVGWriter::getSupportedServiceNames()
3903{
3904 return { "com.sun.star.svg.SVGWriter" };
3905}
3906
3907extern "C" SAL_DLLPUBLIC_EXPORT__attribute__ ((visibility("default"))) css::uno::XInterface*
3908filter_SVGWriter_get_implementation(
3909 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
3910{
3911 return cppu::acquire(new SVGWriter(args, context));
3912}
3913
3914/* 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);
2
Calling copy constructor for 'Reference<VirtualDevice>'
5
Returning from copy constructor for 'Reference<VirtualDevice>'
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
6
Calling 'Reference::clear'
13
Returning; memory was released
205 if (aTmp.get()) {
14
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();
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)
3
Assuming field 'm_pBody' is non-null
4
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
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
6.1
Field 'm_pBody' is non-null
)
7
Taking true branch
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
8
Calling 'VclReferenceBase::release'
12
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;
15
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)
9
Assuming the condition is true
10
Taking true branch
40 delete this;
11
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