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