1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svgtools.hxx>
21 #include <sal/log.hxx>
22 #include <osl/diagnose.h>
23 #include <tools/color.hxx>
24 #include <rtl/math.hxx>
25 #include <basegfx/matrix/b2dhommatrix.hxx>
26 #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 #include <svgtoken.hxx>
28 #include <unordered_map>
30 namespace svgio::svgreader
32 basegfx::B2DHomMatrix
SvgAspectRatio::createLinearMapping(const basegfx::B2DRange
& rTarget
, const basegfx::B2DRange
& rSource
)
34 basegfx::B2DHomMatrix aRetval
;
35 const double fSWidth(rSource
.getWidth());
36 const double fSHeight(rSource
.getHeight());
37 const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth
));
38 const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight
));
40 // transform from source state to unit range
41 aRetval
.translate(-rSource
.getMinX(), -rSource
.getMinY());
43 (bNoSWidth
? 1.0 : 1.0 / fSWidth
) * rTarget
.getWidth(),
44 (bNoSHeight
? 1.0 : 1.0 / fSHeight
) * rTarget
.getHeight());
46 // transform from unit rage to target range
47 aRetval
.translate(rTarget
.getMinX(), rTarget
.getMinY());
52 basegfx::B2DHomMatrix
SvgAspectRatio::createMapping(const basegfx::B2DRange
& rTarget
, const basegfx::B2DRange
& rSource
) const
54 // removed !isSet() from below. Due to correct defaults in the constructor an instance
55 // of this class is perfectly useful without being set by any importer
56 if(Align_none
== getSvgAlign())
58 // create linear mapping (default)
59 return createLinearMapping(rTarget
, rSource
);
62 basegfx::B2DHomMatrix aRetval
;
64 const double fSWidth(rSource
.getWidth());
65 const double fSHeight(rSource
.getHeight());
66 const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth
));
67 const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight
));
68 const double fScaleX((bNoSWidth
? 1.0 : 1.0 / fSWidth
) * rTarget
.getWidth());
69 const double fScaleY((bNoSHeight
? 1.0 : 1.0 / fSHeight
) * rTarget
.getHeight());
70 const double fScale(isMeetOrSlice() ? std::min(fScaleX
, fScaleY
) : std::max(fScaleX
, fScaleY
));
72 // remove source translation, apply scale
73 aRetval
.translate(-rSource
.getMinX(), -rSource
.getMinY());
74 aRetval
.scale(fScale
, fScale
);
76 // evaluate horizontal alignment
77 const double fNewWidth(fSWidth
* fScale
);
87 const double fFreeSpace(rTarget
.getWidth() - fNewWidth
);
88 fTransX
= fFreeSpace
* 0.5;
96 const double fFreeSpace(rTarget
.getWidth() - fNewWidth
);
103 // evaluate vertical alignment
104 const double fNewHeight(fSHeight
* fScale
);
107 switch(getSvgAlign())
114 const double fFreeSpace(rTarget
.getHeight() - fNewHeight
);
115 fTransY
= fFreeSpace
* 0.5;
123 const double fFreeSpace(rTarget
.getHeight() - fNewHeight
);
124 fTransY
= fFreeSpace
;
130 // add target translation
132 rTarget
.getMinX() + fTransX
,
133 rTarget
.getMinY() + fTransY
);
138 double SvgNumber::solveNonPercentage(const InfoProvider
& rInfoProvider
) const
146 return mfNumber
* rInfoProvider
.getCurrentFontSizeInherited();
150 return mfNumber
* rInfoProvider
.getCurrentXHeightInherited() * 0.5;
162 double fRetval(mfNumber
);
166 case Unit_pt
: fRetval
*= F_SVG_PIXEL_PER_INCH
/ 72.0; break;
167 case Unit_pc
: fRetval
*= F_SVG_PIXEL_PER_INCH
/ 6.0; break;
168 case Unit_cm
: fRetval
*= F_SVG_PIXEL_PER_INCH
/ 2.54; break;
169 case Unit_mm
: fRetval
*= 0.1 * F_SVG_PIXEL_PER_INCH
/ 2.54; break;
170 case Unit_in
: fRetval
*= F_SVG_PIXEL_PER_INCH
; break;
178 SAL_WARN("svgio", "Design error, this case should have been handled in the caller");
183 OSL_ENSURE(false, "Do not use with percentage! ");
190 OSL_ENSURE(false, "SvgNumber not set (!)");
194 double SvgNumber::solve(const InfoProvider
& rInfoProvider
, NumberType aNumberType
) const
213 return solveNonPercentage( rInfoProvider
);
217 double fRetval(mfNumber
* 0.01);
218 basegfx::B2DRange aViewPort
= rInfoProvider
.getCurrentViewPort();
220 if ( aViewPort
.isEmpty() )
222 SAL_WARN("svgio", "Design error, this case should have been handled in the caller");
223 // no viewPort, assume a normal page size (A4)
224 aViewPort
= basegfx::B2DRange(
227 210.0 * F_SVG_PIXEL_PER_INCH
/ 2.54,
228 297.0 * F_SVG_PIXEL_PER_INCH
/ 2.54);
232 if ( !aViewPort
.isEmpty() )
234 if(xcoordinate
== aNumberType
)
236 // it's a x-coordinate, relative to current width (w)
237 fRetval
*= aViewPort
.getWidth();
239 else if(ycoordinate
== aNumberType
)
241 // it's a y-coordinate, relative to current height (h)
242 fRetval
*= aViewPort
.getHeight();
246 // it's a length, relative to sqrt(w*w + h*h)/sqrt(2)
247 const double fCurrentWidth(aViewPort
.getWidth());
248 const double fCurrentHeight(aViewPort
.getHeight());
249 const double fCurrentLength(
250 sqrt(fCurrentWidth
* fCurrentWidth
+ fCurrentHeight
* fCurrentHeight
)/sqrt(2.0));
252 fRetval
*= fCurrentLength
;
266 OSL_ENSURE(false, "SvgNumber not set (!)");
270 bool SvgNumber::isPositive() const
272 return basegfx::fTools::moreOrEqual(mfNumber
, 0.0);
275 void skip_char(std::u16string_view rCandidate
, sal_Unicode nChar
, sal_Int32
& nPos
, const sal_Int32 nLen
)
277 while(nPos
< nLen
&& nChar
== rCandidate
[nPos
])
283 void skip_char(std::u16string_view rCandidate
, sal_Unicode nCharA
, sal_Unicode nCharB
, sal_Int32
& nPos
, const sal_Int32 nLen
)
285 while(nPos
< nLen
&& (nCharA
== rCandidate
[nPos
] || nCharB
== rCandidate
[nPos
]))
291 void copySign(std::u16string_view rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
295 const sal_Unicode
aChar(rCandidate
[nPos
]);
297 if('+' == aChar
|| '-' == aChar
)
299 rTarget
.append(aChar
);
305 void copyNumber(std::u16string_view rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
307 bool bOnNumber(true);
309 while(bOnNumber
&& nPos
< nLen
)
311 const sal_Unicode
aChar(rCandidate
[nPos
]);
313 bOnNumber
= ('0' <= aChar
&& '9' >= aChar
) || '.' == aChar
;
317 rTarget
.append(aChar
);
323 void copyHex(std::u16string_view rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
327 while(bOnHex
&& nPos
< nLen
)
329 const sal_Unicode
aChar(rCandidate
[nPos
]);
331 bOnHex
= ('0' <= aChar
&& '9' >= aChar
)
332 || ('A' <= aChar
&& 'F' >= aChar
)
333 || ('a' <= aChar
&& 'f' >= aChar
);
337 rTarget
.append(aChar
);
343 void copyString(std::u16string_view rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
347 while(bOnChar
&& nPos
< nLen
)
349 const sal_Unicode
aChar(rCandidate
[nPos
]);
351 bOnChar
= ('a' <= aChar
&& 'z' >= aChar
)
352 || ('A' <= aChar
&& 'Z' >= aChar
)
357 rTarget
.append(aChar
);
363 void copyToLimiter(std::u16string_view rCandidate
, sal_Unicode nLimiter
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
365 while(nPos
< nLen
&& nLimiter
!= rCandidate
[nPos
])
367 rTarget
.append(rCandidate
[nPos
]);
372 bool readNumber(std::u16string_view rCandidate
, sal_Int32
& nPos
, double& fNum
, const sal_Int32 nLen
)
378 copySign(rCandidate
, nPos
, aNum
, nLen
);
379 copyNumber(rCandidate
, nPos
, aNum
, nLen
);
383 const sal_Unicode
aChar(rCandidate
[nPos
]);
385 if('e' == aChar
|| 'E' == aChar
)
387 // try to read exponential number, but be careful. I had
388 // a case where dx="2em" was used, thus the 'e' was consumed
389 // by error. First try if there are numbers after the 'e',
390 // safe current state
392 const OUStringBuffer
aNum2(aNum
);
393 const sal_Int32
nPosAfterE(nPos
);
396 copySign(rCandidate
, nPos
, aNum
, nLen
);
397 copyNumber(rCandidate
, nPos
, aNum
, nLen
);
399 if(nPosAfterE
== nPos
)
401 // no number after 'e', go back. Do not
402 // return false, it's still a valid integer number
411 rtl_math_ConversionStatus eStatus
;
413 fNum
= rtl::math::stringToDouble(
414 aNum
.makeStringAndClear(), '.', ',',
417 return eStatus
== rtl_math_ConversionStatus_Ok
;
424 SvgUnit
readUnit(std::u16string_view rCandidate
, sal_Int32
& nPos
, const sal_Int32 nLen
)
426 SvgUnit
aRetval(Unit_px
);
430 const sal_Unicode
aCharA(rCandidate
[nPos
]);
434 const sal_Unicode
aCharB(rCandidate
[nPos
+ 1]);
435 bool bTwoCharValid(false);
443 // 'em' Relative to current font size
445 bTwoCharValid
= true;
447 else if('x' == aCharB
)
449 // 'ex' Relative to current font x-height
451 bTwoCharValid
= true;
459 // 'px' UserUnit (default)
460 bTwoCharValid
= true;
462 else if('t' == aCharB
)
466 bTwoCharValid
= true;
468 else if('c' == aCharB
)
472 bTwoCharValid
= true;
480 // 'in' == 96 px, since CSS 2.1
482 bTwoCharValid
= true;
490 // 'cm' == 37.79527559 px
492 bTwoCharValid
= true;
500 // 'mm' == 3.779528 px
502 bTwoCharValid
= true;
517 // percent used, relative to current
519 aRetval
= Unit_percent
;
527 bool readNumberAndUnit(std::u16string_view rCandidate
, sal_Int32
& nPos
, SvgNumber
& aNum
, const sal_Int32 nLen
)
531 if(readNumber(rCandidate
, nPos
, fNum
, nLen
))
533 skip_char(rCandidate
, ' ', nPos
, nLen
);
534 aNum
= SvgNumber(fNum
, readUnit(rCandidate
, nPos
, nLen
));
542 bool readAngle(const OUString
& rCandidate
, sal_Int32
& nPos
, double& fAngle
, const sal_Int32 nLen
)
544 if(readNumber(rCandidate
, nPos
, fAngle
, nLen
))
546 skip_char(rCandidate
, ' ', nPos
, nLen
);
553 } aType(deg
); // degrees is default
557 const sal_Unicode
aChar(rCandidate
[nPos
]);
558 static const char aStrGrad
[] = "grad";
559 static const char aStrRad
[] = "rad";
566 if(rCandidate
.matchIgnoreAsciiCase(aStrGrad
, nPos
))
569 nPos
+= strlen(aStrGrad
);
577 if(rCandidate
.matchIgnoreAsciiCase(aStrRad
, nPos
))
580 nPos
+= strlen(aStrRad
);
588 // convert to radians
591 fAngle
= basegfx::deg2rad(fAngle
);
593 else if(grad
== aType
)
595 // looks like 100 grad is 90 degrees
596 fAngle
*= F_PI
/ 200.0;
605 sal_Int32
read_hex(sal_Unicode nChar
)
607 if(nChar
>= '0' && nChar
<= '9')
611 else if(nChar
>= 'A' && nChar
<= 'F')
613 return 10 + sal_Int32(nChar
- u
'A');
615 else if(nChar
>= 'a' && nChar
<= 'f')
617 return 10 + sal_Int32(nChar
- u
'a');
626 bool match_colorKeyword(basegfx::BColor
& rColor
, const OUString
& rName
, bool bCaseIndependent
)
628 typedef std::unordered_map
< OUString
, Color
> ColorTokenMapper
;
629 typedef std::pair
< OUString
, Color
> ColorTokenValueType
;
630 static const ColorTokenMapper aColorTokenMapperList
{
631 { ColorTokenValueType(OUString("aliceblue"), Color(240, 248, 255)) },
632 { ColorTokenValueType(OUString("antiquewhite"), Color(250, 235, 215) ) },
633 { ColorTokenValueType(OUString("aqua"), Color( 0, 255, 255) ) },
634 { ColorTokenValueType(OUString("aquamarine"), Color(127, 255, 212) ) },
635 { ColorTokenValueType(OUString("azure"), Color(240, 255, 255) ) },
636 { ColorTokenValueType(OUString("beige"), Color(245, 245, 220) ) },
637 { ColorTokenValueType(OUString("bisque"), Color(255, 228, 196) ) },
638 { ColorTokenValueType(OUString("black"), Color( 0, 0, 0) ) },
639 { ColorTokenValueType(OUString("blanchedalmond"), Color(255, 235, 205) ) },
640 { ColorTokenValueType(OUString("blue"), Color( 0, 0, 255) ) },
641 { ColorTokenValueType(OUString("blueviolet"), Color(138, 43, 226) ) },
642 { ColorTokenValueType(OUString("brown"), Color(165, 42, 42) ) },
643 { ColorTokenValueType(OUString("burlywood"), Color(222, 184, 135) ) },
644 { ColorTokenValueType(OUString("cadetblue"), Color( 95, 158, 160) ) },
645 { ColorTokenValueType(OUString("chartreuse"), Color(127, 255, 0) ) },
646 { ColorTokenValueType(OUString("chocolate"), Color(210, 105, 30) ) },
647 { ColorTokenValueType(OUString("coral"), Color(255, 127, 80) ) },
648 { ColorTokenValueType(OUString("cornflowerblue"), Color(100, 149, 237) ) },
649 { ColorTokenValueType(OUString("cornsilk"), Color(255, 248, 220) ) },
650 { ColorTokenValueType(OUString("crimson"), Color(220, 20, 60) ) },
651 { ColorTokenValueType(OUString("cyan"), Color( 0, 255, 255) ) },
652 { ColorTokenValueType(OUString("darkblue"), Color( 0, 0, 139) ) },
653 { ColorTokenValueType(OUString("darkcyan"), Color( 0, 139, 139) ) },
654 { ColorTokenValueType(OUString("darkgoldenrod"), Color(184, 134, 11) ) },
655 { ColorTokenValueType(OUString("darkgray"), Color(169, 169, 169) ) },
656 { ColorTokenValueType(OUString("darkgreen"), Color( 0, 100, 0) ) },
657 { ColorTokenValueType(OUString("darkgrey"), Color(169, 169, 169) ) },
658 { ColorTokenValueType(OUString("darkkhaki"), Color(189, 183, 107) ) },
659 { ColorTokenValueType(OUString("darkmagenta"), Color(139, 0, 139) ) },
660 { ColorTokenValueType(OUString("darkolivegreen"), Color( 85, 107, 47) ) },
661 { ColorTokenValueType(OUString("darkorange"), Color(255, 140, 0) ) },
662 { ColorTokenValueType(OUString("darkorchid"), Color(153, 50, 204) ) },
663 { ColorTokenValueType(OUString("darkred"), Color(139, 0, 0) ) },
664 { ColorTokenValueType(OUString("darksalmon"), Color(233, 150, 122) ) },
665 { ColorTokenValueType(OUString("darkseagreen"), Color(143, 188, 143) ) },
666 { ColorTokenValueType(OUString("darkslateblue"), Color( 72, 61, 139) ) },
667 { ColorTokenValueType(OUString("darkslategray"), Color( 47, 79, 79) ) },
668 { ColorTokenValueType(OUString("darkslategrey"), Color( 47, 79, 79) ) },
669 { ColorTokenValueType(OUString("darkturquoise"), Color( 0, 206, 209) ) },
670 { ColorTokenValueType(OUString("darkviolet"), Color(148, 0, 211) ) },
671 { ColorTokenValueType(OUString("deeppink"), Color(255, 20, 147) ) },
672 { ColorTokenValueType(OUString("deepskyblue"), Color( 0, 191, 255) ) },
673 { ColorTokenValueType(OUString("dimgray"), Color(105, 105, 105) ) },
674 { ColorTokenValueType(OUString("dimgrey"), Color(105, 105, 105) ) },
675 { ColorTokenValueType(OUString("dodgerblue"), Color( 30, 144, 255) ) },
676 { ColorTokenValueType(OUString("firebrick"), Color(178, 34, 34) ) },
677 { ColorTokenValueType(OUString("floralwhite"), Color(255, 250, 240) ) },
678 { ColorTokenValueType(OUString("forestgreen"), Color( 34, 139, 34) ) },
679 { ColorTokenValueType(OUString("fuchsia"), Color(255, 0, 255) ) },
680 { ColorTokenValueType(OUString("gainsboro"), Color(220, 220, 220) ) },
681 { ColorTokenValueType(OUString("ghostwhite"), Color(248, 248, 255) ) },
682 { ColorTokenValueType(OUString("gold"), Color(255, 215, 0) ) },
683 { ColorTokenValueType(OUString("goldenrod"), Color(218, 165, 32) ) },
684 { ColorTokenValueType(OUString("gray"), Color(128, 128, 128) ) },
685 { ColorTokenValueType(OUString("grey"), Color(128, 128, 128) ) },
686 { ColorTokenValueType(OUString("green"), Color(0, 128, 0) ) },
687 { ColorTokenValueType(OUString("greenyellow"), Color(173, 255, 47) ) },
688 { ColorTokenValueType(OUString("honeydew"), Color(240, 255, 240) ) },
689 { ColorTokenValueType(OUString("hotpink"), Color(255, 105, 180) ) },
690 { ColorTokenValueType(OUString("indianred"), Color(205, 92, 92) ) },
691 { ColorTokenValueType(OUString("indigo"), Color( 75, 0, 130) ) },
692 { ColorTokenValueType(OUString("ivory"), Color(255, 255, 240) ) },
693 { ColorTokenValueType(OUString("khaki"), Color(240, 230, 140) ) },
694 { ColorTokenValueType(OUString("lavender"), Color(230, 230, 250) ) },
695 { ColorTokenValueType(OUString("lavenderblush"), Color(255, 240, 245) ) },
696 { ColorTokenValueType(OUString("lawngreen"), Color(124, 252, 0) ) },
697 { ColorTokenValueType(OUString("lemonchiffon"), Color(255, 250, 205) ) },
698 { ColorTokenValueType(OUString("lightblue"), Color(173, 216, 230) ) },
699 { ColorTokenValueType(OUString("lightcoral"), Color(240, 128, 128) ) },
700 { ColorTokenValueType(OUString("lightcyan"), Color(224, 255, 255) ) },
701 { ColorTokenValueType(OUString("lightgoldenrodyellow"), Color(250, 250, 210) ) },
702 { ColorTokenValueType(OUString("lightgray"), Color(211, 211, 211) ) },
703 { ColorTokenValueType(OUString("lightgreen"), Color(144, 238, 144) ) },
704 { ColorTokenValueType(OUString("lightgrey"), Color(211, 211, 211) ) },
705 { ColorTokenValueType(OUString("lightpink"), Color(255, 182, 193) ) },
706 { ColorTokenValueType(OUString("lightsalmon"), Color(255, 160, 122) ) },
707 { ColorTokenValueType(OUString("lightseagreen"), Color( 32, 178, 170) ) },
708 { ColorTokenValueType(OUString("lightskyblue"), Color(135, 206, 250) ) },
709 { ColorTokenValueType(OUString("lightslategray"), Color(119, 136, 153) ) },
710 { ColorTokenValueType(OUString("lightslategrey"), Color(119, 136, 153) ) },
711 { ColorTokenValueType(OUString("lightsteelblue"), Color(176, 196, 222) ) },
712 { ColorTokenValueType(OUString("lightyellow"), Color(255, 255, 224) ) },
713 { ColorTokenValueType(OUString("lime"), Color( 0, 255, 0) ) },
714 { ColorTokenValueType(OUString("limegreen"), Color( 50, 205, 50) ) },
715 { ColorTokenValueType(OUString("linen"), Color(250, 240, 230) ) },
716 { ColorTokenValueType(OUString("magenta"), Color(255, 0, 255) ) },
717 { ColorTokenValueType(OUString("maroon"), Color(128, 0, 0) ) },
718 { ColorTokenValueType(OUString("mediumaquamarine"), Color(102, 205, 170) ) },
719 { ColorTokenValueType(OUString("mediumblue"), Color( 0, 0, 205) ) },
720 { ColorTokenValueType(OUString("mediumorchid"), Color(186, 85, 211) ) },
721 { ColorTokenValueType(OUString("mediumpurple"), Color(147, 112, 219) ) },
722 { ColorTokenValueType(OUString("mediumseagreen"), Color( 60, 179, 113) ) },
723 { ColorTokenValueType(OUString("mediumslateblue"), Color(123, 104, 238) ) },
724 { ColorTokenValueType(OUString("mediumspringgreen"), Color( 0, 250, 154) ) },
725 { ColorTokenValueType(OUString("mediumturquoise"), Color( 72, 209, 204) ) },
726 { ColorTokenValueType(OUString("mediumvioletred"), Color(199, 21, 133) ) },
727 { ColorTokenValueType(OUString("midnightblue"), Color( 25, 25, 112) ) },
728 { ColorTokenValueType(OUString("mintcream"), Color(245, 255, 250) ) },
729 { ColorTokenValueType(OUString("mistyrose"), Color(255, 228, 225) ) },
730 { ColorTokenValueType(OUString("moccasin"), Color(255, 228, 181) ) },
731 { ColorTokenValueType(OUString("navajowhite"), Color(255, 222, 173) ) },
732 { ColorTokenValueType(OUString("navy"), Color( 0, 0, 128) ) },
733 { ColorTokenValueType(OUString("oldlace"), Color(253, 245, 230) ) },
734 { ColorTokenValueType(OUString("olive"), Color(128, 128, 0) ) },
735 { ColorTokenValueType(OUString("olivedrab"), Color(107, 142, 35) ) },
736 { ColorTokenValueType(OUString("orange"), Color(255, 165, 0) ) },
737 { ColorTokenValueType(OUString("orangered"), Color(255, 69, 0) ) },
738 { ColorTokenValueType(OUString("orchid"), Color(218, 112, 214) ) },
739 { ColorTokenValueType(OUString("palegoldenrod"), Color(238, 232, 170) ) },
740 { ColorTokenValueType(OUString("palegreen"), Color(152, 251, 152) ) },
741 { ColorTokenValueType(OUString("paleturquoise"), Color(175, 238, 238) ) },
742 { ColorTokenValueType(OUString("palevioletred"), Color(219, 112, 147) ) },
743 { ColorTokenValueType(OUString("papayawhip"), Color(255, 239, 213) ) },
744 { ColorTokenValueType(OUString("peachpuff"), Color(255, 218, 185) ) },
745 { ColorTokenValueType(OUString("peru"), Color(205, 133, 63) ) },
746 { ColorTokenValueType(OUString("pink"), Color(255, 192, 203) ) },
747 { ColorTokenValueType(OUString("plum"), Color(221, 160, 221) ) },
748 { ColorTokenValueType(OUString("powderblue"), Color(176, 224, 230) ) },
749 { ColorTokenValueType(OUString("purple"), Color(128, 0, 128) ) },
750 { ColorTokenValueType(OUString("red"), Color(255, 0, 0) ) },
751 { ColorTokenValueType(OUString("rosybrown"), Color(188, 143, 143) ) },
752 { ColorTokenValueType(OUString("royalblue"), Color( 65, 105, 225) ) },
753 { ColorTokenValueType(OUString("saddlebrown"), Color(139, 69, 19) ) },
754 { ColorTokenValueType(OUString("salmon"), Color(250, 128, 114) ) },
755 { ColorTokenValueType(OUString("sandybrown"), Color(244, 164, 96) ) },
756 { ColorTokenValueType(OUString("seagreen"), Color( 46, 139, 87) ) },
757 { ColorTokenValueType(OUString("seashell"), Color(255, 245, 238) ) },
758 { ColorTokenValueType(OUString("sienna"), Color(160, 82, 45) ) },
759 { ColorTokenValueType(OUString("silver"), Color(192, 192, 192) ) },
760 { ColorTokenValueType(OUString("skyblue"), Color(135, 206, 235) ) },
761 { ColorTokenValueType(OUString("slateblue"), Color(106, 90, 205) ) },
762 { ColorTokenValueType(OUString("slategray"), Color(112, 128, 144) ) },
763 { ColorTokenValueType(OUString("slategrey"), Color(112, 128, 144) ) },
764 { ColorTokenValueType(OUString("snow"), Color(255, 250, 250) ) },
765 { ColorTokenValueType(OUString("springgreen"), Color( 0, 255, 127) ) },
766 { ColorTokenValueType(OUString("steelblue"), Color( 70, 130, 180) ) },
767 { ColorTokenValueType(OUString("tan"), Color(210, 180, 140) ) },
768 { ColorTokenValueType(OUString("teal"), Color( 0, 128, 128) ) },
769 { ColorTokenValueType(OUString("thistle"), Color(216, 191, 216) ) },
770 { ColorTokenValueType(OUString("tomato"), Color(255, 99, 71) ) },
771 { ColorTokenValueType(OUString("turquoise"), Color( 64, 224, 208) ) },
772 { ColorTokenValueType(OUString("violet"), Color(238, 130, 238) ) },
773 { ColorTokenValueType(OUString("wheat"), Color(245, 222, 179) ) },
774 { ColorTokenValueType(OUString("white"), Color(255, 255, 255) ) },
775 { ColorTokenValueType(OUString("whitesmoke"), Color(245, 245, 245) ) },
776 { ColorTokenValueType(OUString("yellow"), Color(255, 255, 0) ) },
777 { ColorTokenValueType(OUString("yellowgreen"), Color(154, 205, 50) ) },
780 ColorTokenMapper::const_iterator
aResult(aColorTokenMapperList
.find(rName
));
782 if(bCaseIndependent
&& aResult
== aColorTokenMapperList
.end())
784 // also try case independent match (e.g. for Css styles)
785 aResult
= aColorTokenMapperList
.find(rName
.toAsciiLowerCase());
788 if(aResult
== aColorTokenMapperList
.end())
794 rColor
= aResult
->second
.getBColor();
799 bool read_color(const OUString
& rCandidate
, basegfx::BColor
& rColor
, bool bCaseIndependent
, SvgNumber
& rOpacity
)
801 const sal_Int32
nLen(rCandidate
.getLength());
805 const sal_Unicode
aChar(rCandidate
[0]);
806 const double fFactor(1.0 / 255.0);
814 copyHex(rCandidate
, nPos
, aNum
, nLen
);
815 const sal_Int32
nLength(aNum
.getLength());
819 const sal_Int32
nR(read_hex(aNum
[0]));
820 const sal_Int32
nG(read_hex(aNum
[1]));
821 const sal_Int32
nB(read_hex(aNum
[2]));
823 rColor
.setRed((nR
| (nR
<< 4)) * fFactor
);
824 rColor
.setGreen((nG
| (nG
<< 4)) * fFactor
);
825 rColor
.setBlue((nB
| (nB
<< 4)) * fFactor
);
829 else if(6 == nLength
)
831 const sal_Int32
nR1(read_hex(aNum
[0]));
832 const sal_Int32
nR2(read_hex(aNum
[1]));
833 const sal_Int32
nG1(read_hex(aNum
[2]));
834 const sal_Int32
nG2(read_hex(aNum
[3]));
835 const sal_Int32
nB1(read_hex(aNum
[4]));
836 const sal_Int32
nB2(read_hex(aNum
[5]));
838 rColor
.setRed((nR2
| (nR1
<< 4)) * fFactor
);
839 rColor
.setGreen((nG2
| (nG1
<< 4)) * fFactor
);
840 rColor
.setBlue((nB2
| (nB1
<< 4)) * fFactor
);
847 static const char aStrRgb
[] = "rgb";
849 if(rCandidate
.matchIgnoreAsciiCase(aStrRgb
, 0))
851 // rgb/rgba definition
852 sal_Int32
nPos(strlen(aStrRgb
));
853 bool bIsRGBA
= false;
855 if('a' == rCandidate
[nPos
])
857 //Delete the 'a' from 'rbga'
858 skip_char(rCandidate
, 'a', nPos
, nPos
+ 1);
862 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
865 if(readNumber(rCandidate
, nPos
, fR
, nLen
))
867 skip_char(rCandidate
, ' ', nPos
, nLen
);
871 const sal_Unicode
aPercentChar(rCandidate
[nPos
]);
872 const bool bIsPercent('%' == aPercentChar
);
877 skip_char(rCandidate
, '%', nPos
, nLen
);
880 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
882 if(readNumber(rCandidate
, nPos
, fG
, nLen
))
888 skip_char(rCandidate
, '%', nPos
, nLen
);
891 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
893 if(readNumber(rCandidate
, nPos
, fB
, nLen
))
899 skip_char(rCandidate
, '%', nPos
, nLen
);
902 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
904 if(readNumber(rCandidate
, nPos
, fA
, nLen
))
908 const double fFac(bIsPercent
? 0.01 : 1);
909 rOpacity
= SvgNumber(fA
* fFac
);
913 skip_char(rCandidate
, '%', nPos
, nLen
);
922 const double fFac(bIsPercent
? 0.01 : fFactor
);
924 rColor
.setRed(fR
* fFac
);
925 rColor
.setGreen(fG
* fFac
);
926 rColor
.setBlue(fB
* fFac
);
928 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
938 if(match_colorKeyword(rColor
, rCandidate
, bCaseIndependent
))
949 basegfx::B2DRange
readViewBox(const OUString
& rCandidate
, InfoProvider
const & rInfoProvider
)
951 const sal_Int32
nLen(rCandidate
.getLength());
957 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
959 if(readNumberAndUnit(rCandidate
, nPos
, aMinX
, nLen
))
962 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
964 if(readNumberAndUnit(rCandidate
, nPos
, aMinY
, nLen
))
967 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
969 if(readNumberAndUnit(rCandidate
, nPos
, aWidth
, nLen
))
972 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
974 if(readNumberAndUnit(rCandidate
, nPos
, aHeight
, nLen
))
976 double fX(aMinX
.solve(rInfoProvider
, xcoordinate
));
977 double fY(aMinY
.solve(rInfoProvider
, ycoordinate
));
978 double fW(aWidth
.solve(rInfoProvider
,xcoordinate
));
979 double fH(aHeight
.solve(rInfoProvider
,ycoordinate
));
980 return basegfx::B2DRange(fX
,fY
,fX
+fW
,fY
+fH
);
987 return basegfx::B2DRange();
990 basegfx::B2DHomMatrix
readTransform(const OUString
& rCandidate
, InfoProvider
const & rInfoProvider
)
992 basegfx::B2DHomMatrix aMatrix
;
993 const sal_Int32
nLen(rCandidate
.getLength());
998 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1002 const sal_Unicode
aChar(rCandidate
[nPos
]);
1003 const sal_Int32
nInitPos(nPos
);
1004 static const char aStrMatrix
[] = "matrix";
1005 static const char aStrTranslate
[] = "translate";
1006 static const char aStrScale
[] = "scale";
1007 static const char aStrRotate
[] = "rotate";
1008 static const char aStrSkewX
[] = "skewX";
1009 static const char aStrSkewY
[] = "skewY";
1015 if(rCandidate
.match(aStrMatrix
, nPos
))
1018 nPos
+= strlen(aStrMatrix
);
1019 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1021 basegfx::B2DHomMatrix aNew
;
1023 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1025 aNew
.set(0, 0, aVal
.solve(rInfoProvider
)); // Element A
1026 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1028 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1030 aNew
.set(1, 0, aVal
.solve(rInfoProvider
)); // Element B
1031 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1033 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1035 aNew
.set(0, 1, aVal
.solve(rInfoProvider
)); // Element C
1036 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1038 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1040 aNew
.set(1, 1, aVal
.solve(rInfoProvider
)); // Element D
1041 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1043 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1045 aNew
.set(0, 2, aVal
.solve(rInfoProvider
, xcoordinate
)); // Element E
1046 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1048 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1050 aNew
.set(1, 2, aVal
.solve(rInfoProvider
, ycoordinate
)); // Element F
1051 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1052 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1054 // caution: String is evaluated from left to right, but matrix multiplication
1055 // in SVG is right to left, so put the new transformation before the current
1056 // one by multiplicating from the right side
1057 aMatrix
= aMatrix
* aNew
;
1069 if(rCandidate
.match(aStrTranslate
, nPos
))
1071 // translate element
1072 nPos
+= strlen(aStrTranslate
);
1073 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1076 if(readNumberAndUnit(rCandidate
, nPos
, aTransX
, nLen
))
1078 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1080 readNumberAndUnit(rCandidate
, nPos
, aTransY
, nLen
);
1081 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1082 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1084 aMatrix
= aMatrix
* basegfx::utils::createTranslateB2DHomMatrix(
1085 aTransX
.solve(rInfoProvider
, xcoordinate
),
1086 aTransY
.solve(rInfoProvider
, ycoordinate
));
1093 if(rCandidate
.match(aStrScale
, nPos
))
1096 nPos
+= strlen(aStrScale
);
1097 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1100 if(readNumberAndUnit(rCandidate
, nPos
, aScaleX
, nLen
))
1102 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1103 SvgNumber
aScaleY(aScaleX
);
1104 readNumberAndUnit(rCandidate
, nPos
, aScaleY
, nLen
);
1105 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1106 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1108 aMatrix
= aMatrix
* basegfx::utils::createScaleB2DHomMatrix(
1109 aScaleX
.solve(rInfoProvider
),
1110 aScaleY
.solve(rInfoProvider
));
1113 else if(rCandidate
.match(aStrSkewX
, nPos
))
1116 nPos
+= strlen(aStrSkewX
);
1117 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1120 if(readAngle(rCandidate
, nPos
, fSkewX
, nLen
))
1122 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1123 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1125 aMatrix
= aMatrix
* basegfx::utils::createShearXB2DHomMatrix(tan(fSkewX
));
1128 else if(rCandidate
.match(aStrSkewY
, nPos
))
1131 nPos
+= strlen(aStrSkewY
);
1132 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1135 if(readAngle(rCandidate
, nPos
, fSkewY
, nLen
))
1137 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1138 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1140 aMatrix
= aMatrix
* basegfx::utils::createShearYB2DHomMatrix(tan(fSkewY
));
1147 if(rCandidate
.match(aStrRotate
, nPos
))
1150 nPos
+= strlen(aStrRotate
);
1151 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1154 if(readAngle(rCandidate
, nPos
, fAngle
, nLen
))
1156 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1158 readNumberAndUnit(rCandidate
, nPos
, aX
, nLen
);
1159 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1161 readNumberAndUnit(rCandidate
, nPos
, aY
, nLen
);
1162 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1163 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1165 const double fX(aX
.isSet() ? aX
.solve(rInfoProvider
, xcoordinate
) : 0.0);
1166 const double fY(aY
.isSet() ? aY
.solve(rInfoProvider
, ycoordinate
) : 0.0);
1168 if(!basegfx::fTools::equalZero(fX
) || !basegfx::fTools::equalZero(fY
))
1170 // rotate around point
1171 aMatrix
= aMatrix
* basegfx::utils::createRotateAroundPoint(fX
, fY
, fAngle
);
1176 aMatrix
= aMatrix
* basegfx::utils::createRotateB2DHomMatrix(fAngle
);
1184 if(nInitPos
== nPos
)
1186 OSL_ENSURE(false, "Could not interpret on current position (!)");
1195 bool readSingleNumber(const OUString
& rCandidate
, SvgNumber
& aNum
)
1197 const sal_Int32
nLen(rCandidate
.getLength());
1200 return readNumberAndUnit(rCandidate
, nPos
, aNum
, nLen
);
1203 bool readLocalUrl(const OUString
& rCandidate
, OUString
& rURL
)
1205 static const char aStrUrl
[] = "url";
1207 if(rCandidate
.startsWith(aStrUrl
))
1209 const sal_Int32
nLen(rCandidate
.getLength());
1210 sal_Int32
nPos(strlen(aStrUrl
));
1212 skip_char(rCandidate
, '(', '#', nPos
, nLen
);
1213 OUStringBuffer aTokenValue
;
1214 copyToLimiter(rCandidate
, ')', nPos
, aTokenValue
, nLen
);
1215 rURL
= aTokenValue
.makeStringAndClear();
1223 bool readSvgPaint(const OUString
& rCandidate
, SvgPaint
& rSvgPaint
,
1224 OUString
& rURL
, bool bCaseIndependent
, SvgNumber
& rOpacity
)
1226 if( !rCandidate
.isEmpty() )
1228 basegfx::BColor aColor
;
1230 if(read_color(rCandidate
, aColor
, bCaseIndependent
, rOpacity
))
1232 rSvgPaint
= SvgPaint(aColor
, true, true);
1237 if(rCandidate
.startsWith("none"))
1239 rSvgPaint
= SvgPaint(aColor
, true, false, false);
1242 else if(readLocalUrl(rCandidate
, rURL
))
1244 /// Url is copied to rURL, but needs to be solved outside this helper
1247 else if(rCandidate
.startsWith("currentColor"))
1249 rSvgPaint
= SvgPaint(aColor
, true, true, true);
1258 bool readSvgNumberVector(const OUString
& rCandidate
, SvgNumberVector
& rSvgNumberVector
)
1260 const sal_Int32
nLen(rCandidate
.getLength());
1261 rSvgNumberVector
.clear();
1267 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1269 while(readNumberAndUnit(rCandidate
, nPos
, aNum
, nLen
))
1271 rSvgNumberVector
.push_back(aNum
);
1272 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1275 return !rSvgNumberVector
.empty();
1281 SvgAspectRatio
readSvgAspectRatio(const OUString
& rCandidate
)
1283 const sal_Int32
nLen(rCandidate
.getLength());
1288 SvgAlign
aSvgAlign(Align_xMidYMid
);
1289 bool bMeetOrSlice(true);
1290 bool bChanged(false);
1294 const sal_Int32
nInitPos(nPos
);
1295 skip_char(rCandidate
, ' ', nPos
, nLen
);
1296 OUStringBuffer aTokenName
;
1297 copyString(rCandidate
, nPos
, aTokenName
, nLen
);
1299 if(!aTokenName
.isEmpty())
1301 switch(StrToSVGToken(aTokenName
.makeStringAndClear(), false))
1310 aSvgAlign
= Align_none
;
1314 case SVGTokenXMinYMin
:
1316 aSvgAlign
= Align_xMinYMin
;
1320 case SVGTokenXMidYMin
:
1322 aSvgAlign
= Align_xMidYMin
;
1326 case SVGTokenXMaxYMin
:
1328 aSvgAlign
= Align_xMaxYMin
;
1332 case SVGTokenXMinYMid
:
1334 aSvgAlign
= Align_xMinYMid
;
1338 case SVGTokenXMidYMid
:
1340 aSvgAlign
= Align_xMidYMid
;
1344 case SVGTokenXMaxYMid
:
1346 aSvgAlign
= Align_xMaxYMid
;
1350 case SVGTokenXMinYMax
:
1352 aSvgAlign
= Align_xMinYMax
;
1356 case SVGTokenXMidYMax
:
1358 aSvgAlign
= Align_xMidYMax
;
1362 case SVGTokenXMaxYMax
:
1364 aSvgAlign
= Align_xMaxYMax
;
1370 bMeetOrSlice
= true;
1376 bMeetOrSlice
= false;
1387 if(nInitPos
== nPos
)
1389 OSL_ENSURE(false, "Could not interpret on current position (!)");
1396 return SvgAspectRatio(aSvgAlign
, bMeetOrSlice
);
1400 return SvgAspectRatio();
1403 bool readSvgStringVector(const OUString
& rCandidate
, SvgStringVector
& rSvgStringVector
)
1405 rSvgStringVector
.clear();
1406 const sal_Int32
nLen(rCandidate
.getLength());
1411 OUStringBuffer aTokenValue
;
1412 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1416 copyToLimiter(rCandidate
, ',', nPos
, aTokenValue
, nLen
);
1417 skip_char(rCandidate
, ',', ' ', nPos
, nLen
);
1418 const OUString aString
= aTokenValue
.makeStringAndClear();
1420 if(!aString
.isEmpty())
1422 rSvgStringVector
.push_back(aString
);
1427 return !rSvgStringVector
.empty();
1430 void readImageLink(const OUString
& rCandidate
, OUString
& rXLink
, OUString
& rUrl
, OUString
& rMimeType
, OUString
& rData
)
1437 if('#' == rCandidate
[0])
1440 rXLink
= rCandidate
.copy(1);
1444 static const char aStrData
[] = "data:";
1446 if(rCandidate
.match(aStrData
, 0))
1449 sal_Int32
nPos(strlen(aStrData
));
1450 sal_Int32
nLen(rCandidate
.getLength());
1451 OUStringBuffer aBuffer
;
1454 skip_char(rCandidate
, ' ', nPos
, nLen
);
1455 copyToLimiter(rCandidate
, ';', nPos
, aBuffer
, nLen
);
1456 skip_char(rCandidate
, ' ', ';', nPos
, nLen
);
1457 rMimeType
= aBuffer
.makeStringAndClear();
1459 if(!rMimeType
.isEmpty() && nPos
< nLen
)
1461 if(rMimeType
.startsWith("image"))
1464 OUString
aData(rCandidate
.copy(nPos
));
1465 static const char aStrBase64
[] = "base64";
1467 if(aData
.startsWith(aStrBase64
))
1470 nPos
= strlen(aStrBase64
);
1471 nLen
= aData
.getLength();
1473 skip_char(aData
, ' ', ',', nPos
, nLen
);
1477 rData
= aData
.copy(nPos
);
1485 // Url (path and filename)
1491 OUString
convert(const OUString
& rCandidate
, sal_Unicode nPattern
, sal_Unicode nNew
, bool bRemove
)
1493 const sal_Int32
nLen(rCandidate
.getLength());
1498 OUStringBuffer aBuffer
;
1499 bool bChanged(false);
1503 const sal_Unicode
aChar(rCandidate
[nPos
]);
1505 if(nPattern
== aChar
)
1511 aBuffer
.append(nNew
);
1516 aBuffer
.append(aChar
);
1524 return aBuffer
.makeStringAndClear();
1532 OUString
removeBlockComments(const OUString
& rCandidate
)
1534 const sal_Int32
nLen(rCandidate
.getLength());
1539 OUStringBuffer aBuffer
;
1540 bool bChanged(false);
1541 sal_Int32
nInsideComment(0);
1542 const sal_Unicode
aCommentSlash('/');
1543 const sal_Unicode
aCommentStar('*');
1547 const sal_Unicode
aChar(rCandidate
[nPos
]);
1548 const bool bStart(aCommentSlash
== aChar
&& nPos
+ 1 < nLen
&& aCommentStar
== rCandidate
[nPos
+ 1]);
1549 const bool bEnd(aCommentStar
== aChar
&& nPos
+ 1 < nLen
&& aCommentSlash
== rCandidate
[nPos
+ 1]);
1566 aBuffer
.append(aChar
);
1575 return aBuffer
.makeStringAndClear();
1582 OUString
consolidateContiguousSpace(const OUString
& rCandidate
)
1584 const sal_Int32
nLen(rCandidate
.getLength());
1589 OUStringBuffer aBuffer
;
1590 bool bInsideSpace(false);
1591 const sal_Unicode
aSpace(' ');
1595 const sal_Unicode
aChar(rCandidate
[nPos
]);
1599 bInsideSpace
= true;
1605 bInsideSpace
= false;
1606 aBuffer
.append(aSpace
);
1609 aBuffer
.append(aChar
);
1617 aBuffer
.append(aSpace
);
1620 if(aBuffer
.getLength() != nLen
)
1622 return aBuffer
.makeStringAndClear();
1629 OUString
whiteSpaceHandlingDefault(const OUString
& rCandidate
)
1631 const sal_Unicode
aNewline('\n');
1632 const sal_Unicode
aTab('\t');
1633 const sal_Unicode
aSpace(' ');
1635 // remove all newline characters
1636 OUString
aRetval(convert(rCandidate
, aNewline
, aNewline
, true));
1638 // convert tab to space
1639 aRetval
= convert(aRetval
, aTab
, aSpace
, false);
1641 // strip of all leading and trailing spaces
1642 aRetval
= aRetval
.trim();
1644 // consolidate contiguous space
1645 aRetval
= consolidateContiguousSpace(aRetval
);
1650 OUString
whiteSpaceHandlingPreserve(const OUString
& rCandidate
)
1652 const sal_Unicode
aNewline('\n');
1653 const sal_Unicode
aTab('\t');
1654 const sal_Unicode
aSpace(' ');
1656 // convert newline to space
1657 convert(rCandidate
, aNewline
, aSpace
, false);
1659 // convert tab to space
1660 convert(rCandidate
, aTab
, aSpace
, false);
1665 ::std::vector
< double > solveSvgNumberVector(const SvgNumberVector
& rInput
, const InfoProvider
& rInfoProvider
)
1667 ::std::vector
< double > aRetval
;
1671 const double nCount(rInput
.size());
1672 aRetval
.reserve(nCount
);
1674 for(sal_uInt32
a(0); a
< nCount
; a
++)
1676 aRetval
.push_back(rInput
[a
].solve(rInfoProvider
));
1683 } // end of namespace svgio::svgreader
1685 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */