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 <osl/thread.h>
22 #include <tools/color.hxx>
23 #include <basegfx/matrix/b2dhommatrix.hxx>
24 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 #include <svgtoken.hxx>
26 #include <unordered_map>
32 // common non-token strings
33 const OUString
commonStrings::aStrUserSpaceOnUse("userSpaceOnUse");
34 const OUString
commonStrings::aStrObjectBoundingBox("objectBoundingBox");
35 const OUString
commonStrings::aStrNonzero("nonzero");
36 const OUString
commonStrings::aStrEvenOdd("evenodd");
38 basegfx::B2DHomMatrix
SvgAspectRatio::createLinearMapping(const basegfx::B2DRange
& rTarget
, const basegfx::B2DRange
& rSource
)
40 basegfx::B2DHomMatrix aRetval
;
41 const double fSWidth(rSource
.getWidth());
42 const double fSHeight(rSource
.getHeight());
43 const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth
));
44 const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight
));
46 // transform from source state to unit range
47 aRetval
.translate(-rSource
.getMinX(), -rSource
.getMinY());
49 (bNoSWidth
? 1.0 : 1.0 / fSWidth
) * rTarget
.getWidth(),
50 (bNoSHeight
? 1.0 : 1.0 / fSHeight
) * rTarget
.getHeight());
52 // transform from unit rage to target range
53 aRetval
.translate(rTarget
.getMinX(), rTarget
.getMinY());
58 basegfx::B2DHomMatrix
SvgAspectRatio::createMapping(const basegfx::B2DRange
& rTarget
, const basegfx::B2DRange
& rSource
) const
60 // removed !isSet() from below. Due to correct defaults in the constructor an instance
61 // of this class is perfectly useful without being set by any importer
62 if(Align_none
== getSvgAlign())
64 // create linear mapping (default)
65 return createLinearMapping(rTarget
, rSource
);
68 basegfx::B2DHomMatrix aRetval
;
70 const double fSWidth(rSource
.getWidth());
71 const double fSHeight(rSource
.getHeight());
72 const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth
));
73 const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight
));
74 const double fScaleX((bNoSWidth
? 1.0 : 1.0 / fSWidth
) * rTarget
.getWidth());
75 const double fScaleY((bNoSHeight
? 1.0 : 1.0 / fSHeight
) * rTarget
.getHeight());
76 const double fScale(isMeetOrSlice() ? std::min(fScaleX
, fScaleY
) : std::max(fScaleX
, fScaleY
));
78 // remove source translation, apply scale
79 aRetval
.translate(-rSource
.getMinX(), -rSource
.getMinY());
80 aRetval
.scale(fScale
, fScale
);
82 // evaluate horizontal alignment
83 const double fNewWidth(fSWidth
* fScale
);
93 const double fFreeSpace(rTarget
.getWidth() - fNewWidth
);
94 fTransX
= fFreeSpace
* 0.5;
102 const double fFreeSpace(rTarget
.getWidth() - fNewWidth
);
103 fTransX
= fFreeSpace
;
109 // evaluate vertical alignment
110 const double fNewHeight(fSHeight
* fScale
);
113 switch(getSvgAlign())
120 const double fFreeSpace(rTarget
.getHeight() - fNewHeight
);
121 fTransY
= fFreeSpace
* 0.5;
129 const double fFreeSpace(rTarget
.getHeight() - fNewHeight
);
130 fTransY
= fFreeSpace
;
136 // add target translation
138 rTarget
.getMinX() + fTransX
,
139 rTarget
.getMinY() + fTransY
);
144 double SvgNumber::solveNonPercentage(const InfoProvider
& rInfoProvider
) const
152 return mfNumber
* rInfoProvider
.getCurrentFontSizeInherited();
156 return mfNumber
* rInfoProvider
.getCurrentXHeightInherited() * 0.5;
168 double fRetval(mfNumber
);
172 case Unit_pt
: fRetval
*= F_SVG_PIXEL_PER_INCH
/ 72.0; break;
173 case Unit_pc
: fRetval
*= F_SVG_PIXEL_PER_INCH
/ 6.0; break;
174 case Unit_cm
: fRetval
*= F_SVG_PIXEL_PER_INCH
/ 2.54; break;
175 case Unit_mm
: fRetval
*= 0.1 * F_SVG_PIXEL_PER_INCH
/ 2.54; break;
176 case Unit_in
: fRetval
*= F_SVG_PIXEL_PER_INCH
; break;
184 SAL_WARN("svgio", "Design error, this case should have been handled in the caller");
189 OSL_ENSURE(false, "Do not use with percentage! ");
196 OSL_ENSURE(false, "SvgNumber not set (!)");
200 double SvgNumber::solve(const InfoProvider
& rInfoProvider
, NumberType aNumberType
) const
219 return solveNonPercentage( rInfoProvider
);
223 double fRetval(mfNumber
* 0.01);
224 basegfx::B2DRange aViewPort
= rInfoProvider
.getCurrentViewPort();
226 if ( aViewPort
.isEmpty() )
228 SAL_WARN("svgio", "Design error, this case should have been handled in the caller");
229 // no viewPort, assume a normal page size (A4)
230 aViewPort
= basegfx::B2DRange(
233 210.0 * F_SVG_PIXEL_PER_INCH
/ 2.54,
234 297.0 * F_SVG_PIXEL_PER_INCH
/ 2.54);
238 if ( !aViewPort
.isEmpty() )
240 if(xcoordinate
== aNumberType
)
242 // it's a x-coordinate, relative to current width (w)
243 fRetval
*= aViewPort
.getWidth();
245 else if(ycoordinate
== aNumberType
)
247 // it's a y-coordinate, relative to current height (h)
248 fRetval
*= aViewPort
.getHeight();
252 // it's a length, relative to sqrt(w*w + h*h)/sqrt(2)
253 const double fCurrentWidth(aViewPort
.getWidth());
254 const double fCurrentHeight(aViewPort
.getHeight());
255 const double fCurrentLength(
256 sqrt(fCurrentWidth
* fCurrentWidth
+ fCurrentHeight
* fCurrentHeight
)/sqrt(2.0));
258 fRetval
*= fCurrentLength
;
272 OSL_ENSURE(false, "SvgNumber not set (!)");
276 bool SvgNumber::isPositive() const
278 return basegfx::fTools::moreOrEqual(mfNumber
, 0.0);
281 void skip_char(const OUString
& rCandidate
, sal_Unicode nChar
, sal_Int32
& nPos
, const sal_Int32 nLen
)
283 while(nPos
< nLen
&& nChar
== rCandidate
[nPos
])
289 void skip_char(const OUString
& rCandidate
, sal_Unicode nCharA
, sal_Unicode nCharB
, sal_Int32
& nPos
, const sal_Int32 nLen
)
291 while(nPos
< nLen
&& (nCharA
== rCandidate
[nPos
] || nCharB
== rCandidate
[nPos
]))
297 void copySign(const OUString
& rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
301 const sal_Unicode
aChar(rCandidate
[nPos
]);
303 if('+' == aChar
|| '-' == aChar
)
305 rTarget
.append(aChar
);
311 void copyNumber(const OUString
& rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
313 bool bOnNumber(true);
315 while(bOnNumber
&& nPos
< nLen
)
317 const sal_Unicode
aChar(rCandidate
[nPos
]);
319 bOnNumber
= ('0' <= aChar
&& '9' >= aChar
) || '.' == aChar
;
323 rTarget
.append(aChar
);
329 void copyHex(const OUString
& rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
333 while(bOnHex
&& nPos
< nLen
)
335 const sal_Unicode
aChar(rCandidate
[nPos
]);
337 bOnHex
= ('0' <= aChar
&& '9' >= aChar
)
338 || ('A' <= aChar
&& 'F' >= aChar
)
339 || ('a' <= aChar
&& 'f' >= aChar
);
343 rTarget
.append(aChar
);
349 void copyString(const OUString
& rCandidate
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
353 while(bOnChar
&& nPos
< nLen
)
355 const sal_Unicode
aChar(rCandidate
[nPos
]);
357 bOnChar
= ('a' <= aChar
&& 'z' >= aChar
)
358 || ('A' <= aChar
&& 'Z' >= aChar
)
363 rTarget
.append(aChar
);
369 void copyToLimiter(const OUString
& rCandidate
, sal_Unicode nLimiter
, sal_Int32
& nPos
, OUStringBuffer
& rTarget
, const sal_Int32 nLen
)
371 while(nPos
< nLen
&& nLimiter
!= rCandidate
[nPos
])
373 rTarget
.append(rCandidate
[nPos
]);
378 bool readNumber(const OUString
& rCandidate
, sal_Int32
& nPos
, double& fNum
, const sal_Int32 nLen
)
384 copySign(rCandidate
, nPos
, aNum
, nLen
);
385 copyNumber(rCandidate
, nPos
, aNum
, nLen
);
389 const sal_Unicode
aChar(rCandidate
[nPos
]);
391 if('e' == aChar
|| 'E' == aChar
)
393 // try to read exponential number, but be careful. I had
394 // a case where dx="2em" was used, thus the 'e' was consumed
395 // by error. First try if there are numbers after the 'e',
396 // safe current state
398 const OUStringBuffer
aNum2(aNum
);
399 const sal_Int32
nPosAfterE(nPos
);
402 copySign(rCandidate
, nPos
, aNum
, nLen
);
403 copyNumber(rCandidate
, nPos
, aNum
, nLen
);
405 if(nPosAfterE
== nPos
)
407 // no number after 'e', go back. Do not
408 // return false, it's still a valid integer number
417 rtl_math_ConversionStatus eStatus
;
419 fNum
= rtl::math::stringToDouble(
420 aNum
.makeStringAndClear(), '.', ',',
423 return eStatus
== rtl_math_ConversionStatus_Ok
;
430 SvgUnit
readUnit(const OUString
& rCandidate
, sal_Int32
& nPos
, const sal_Int32 nLen
)
432 SvgUnit
aRetval(Unit_px
);
436 const sal_Unicode
aCharA(rCandidate
[nPos
]);
440 const sal_Unicode
aCharB(rCandidate
[nPos
+ 1]);
441 bool bTwoCharValid(false);
449 // 'em' Relative to current font size
451 bTwoCharValid
= true;
453 else if('x' == aCharB
)
455 // 'ex' Relative to current font x-height
457 bTwoCharValid
= true;
465 // 'px' UserUnit (default)
466 bTwoCharValid
= true;
468 else if('t' == aCharB
)
472 bTwoCharValid
= true;
474 else if('c' == aCharB
)
478 bTwoCharValid
= true;
486 // 'in' == 96 px, since CSS 2.1
488 bTwoCharValid
= true;
496 // 'cm' == 37.79527559 px
498 bTwoCharValid
= true;
506 // 'mm' == 3.779528 px
508 bTwoCharValid
= true;
523 // percent used, relative to current
525 aRetval
= Unit_percent
;
533 bool readNumberAndUnit(const OUString
& rCandidate
, sal_Int32
& nPos
, SvgNumber
& aNum
, const sal_Int32 nLen
)
537 if(readNumber(rCandidate
, nPos
, fNum
, nLen
))
539 skip_char(rCandidate
, ' ', nPos
, nLen
);
540 aNum
= SvgNumber(fNum
, readUnit(rCandidate
, nPos
, nLen
));
548 bool readAngle(const OUString
& rCandidate
, sal_Int32
& nPos
, double& fAngle
, const sal_Int32 nLen
)
550 if(readNumber(rCandidate
, nPos
, fAngle
, nLen
))
552 skip_char(rCandidate
, ' ', nPos
, nLen
);
559 } aType(deg
); // degrees is default
563 const sal_Unicode
aChar(rCandidate
[nPos
]);
564 static const char aStrGrad
[] = "grad";
565 static const char aStrRad
[] = "rad";
572 if(rCandidate
.matchIgnoreAsciiCase(aStrGrad
, nPos
))
575 nPos
+= strlen(aStrGrad
);
583 if(rCandidate
.matchIgnoreAsciiCase(aStrRad
, nPos
))
586 nPos
+= strlen(aStrRad
);
594 // convert to radians
597 fAngle
*= F_PI
/ 180.0;
599 else if(grad
== aType
)
601 // looks like 100 grad is 90 degrees
602 fAngle
*= F_PI
/ 200.0;
611 sal_Int32
read_hex(sal_Unicode nChar
)
613 if(nChar
>= '0' && nChar
<= '9')
617 else if(nChar
>= 'A' && nChar
<= 'F')
619 return 10 + sal_Int32(nChar
- u
'A');
621 else if(nChar
>= 'a' && nChar
<= 'f')
623 return 10 + sal_Int32(nChar
- u
'a');
632 bool match_colorKeyword(basegfx::BColor
& rColor
, const OUString
& rName
, bool bCaseIndependent
)
634 typedef std::unordered_map
< OUString
, Color
> ColorTokenMapper
;
635 typedef std::pair
< OUString
, Color
> ColorTokenValueType
;
636 ColorTokenMapper aColorTokenMapperList
;
638 if(aColorTokenMapperList
.empty())
640 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("aliceblue"), Color(240, 248, 255)));
641 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("antiquewhite"), Color(250, 235, 215)));
642 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("aqua"), Color( 0, 255, 255)));
643 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("aquamarine"), Color(127, 255, 212)));
644 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("azure"), Color(240, 255, 255)));
645 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("beige"), Color(245, 245, 220)));
646 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("bisque"), Color(255, 228, 196)));
647 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("black"), Color( 0, 0, 0)));
648 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("blanchedalmond"), Color(255, 235, 205)));
649 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("blue"), Color( 0, 0, 255)));
650 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("blueviolet"), Color(138, 43, 226)));
651 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("brown"), Color(165, 42, 42)));
652 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("burlywood"), Color(222, 184, 135)));
653 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("cadetblue"), Color( 95, 158, 160)));
654 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("chartreuse"), Color(127, 255, 0)));
655 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("chocolate"), Color(210, 105, 30)));
656 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("coral"), Color(255, 127, 80)));
657 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("cornflowerblue"), Color(100, 149, 237)));
658 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("cornsilk"), Color(255, 248, 220)));
659 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("crimson"), Color(220, 20, 60)));
660 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("cyan"), Color( 0, 255, 255)));
661 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkblue"), Color( 0, 0, 139)));
662 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkcyan"), Color( 0, 139, 139)));
663 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkgoldenrod"), Color(184, 134, 11)));
664 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkgray"), Color(169, 169, 169)));
665 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkgreen"), Color( 0, 100, 0)));
666 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkgrey"), Color(169, 169, 169)));
667 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkkhaki"), Color(189, 183, 107)));
668 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkmagenta"), Color(139, 0, 139)));
669 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkolivegreen"), Color( 85, 107, 47)));
670 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkorange"), Color(255, 140, 0)));
671 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkorchid"), Color(153, 50, 204)));
672 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkred"), Color(139, 0, 0)));
673 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darksalmon"), Color(233, 150, 122)));
674 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkseagreen"), Color(143, 188, 143)));
675 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkslateblue"), Color( 72, 61, 139)));
676 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkslategray"), Color( 47, 79, 79)));
677 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkslategrey"), Color( 47, 79, 79)));
678 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkturquoise"), Color( 0, 206, 209)));
679 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("darkviolet"), Color(148, 0, 211)));
680 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("deeppink"), Color(255, 20, 147)));
681 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("deepskyblue"), Color( 0, 191, 255)));
682 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("dimgray"), Color(105, 105, 105)));
683 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("dimgrey"), Color(105, 105, 105)));
684 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("dodgerblue"), Color( 30, 144, 255)));
685 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("firebrick"), Color(178, 34, 34)));
686 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("floralwhite"), Color(255, 250, 240)));
687 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("forestgreen"), Color( 34, 139, 34)));
688 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("fuchsia"), Color(255, 0, 255)));
689 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("gainsboro"), Color(220, 220, 220)));
690 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("ghostwhite"), Color(248, 248, 255)));
691 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("gold"), Color(255, 215, 0)));
692 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("goldenrod"), Color(218, 165, 32)));
693 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("gray"), Color(128, 128, 128)));
694 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("grey"), Color(128, 128, 128)));
695 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("green"), Color(0, 128, 0)));
696 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("greenyellow"), Color(173, 255, 47)));
697 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("honeydew"), Color(240, 255, 240)));
698 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("hotpink"), Color(255, 105, 180)));
699 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("indianred"), Color(205, 92, 92)));
700 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("indigo"), Color( 75, 0, 130)));
701 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("ivory"), Color(255, 255, 240)));
702 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("khaki"), Color(240, 230, 140)));
703 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lavender"), Color(230, 230, 250)));
704 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lavenderblush"), Color(255, 240, 245)));
705 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lawngreen"), Color(124, 252, 0)));
706 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lemonchiffon"), Color(255, 250, 205)));
707 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightblue"), Color(173, 216, 230)));
708 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightcoral"), Color(240, 128, 128)));
709 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightcyan"), Color(224, 255, 255)));
710 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightgoldenrodyellow"), Color(250, 250, 210)));
711 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightgray"), Color(211, 211, 211)));
712 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightgreen"), Color(144, 238, 144)));
713 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightgrey"), Color(211, 211, 211)));
714 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightpink"), Color(255, 182, 193)));
715 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightsalmon"), Color(255, 160, 122)));
716 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightseagreen"), Color( 32, 178, 170)));
717 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightskyblue"), Color(135, 206, 250)));
718 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightslategray"), Color(119, 136, 153)));
719 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightslategrey"), Color(119, 136, 153)));
720 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightsteelblue"), Color(176, 196, 222)));
721 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lightyellow"), Color(255, 255, 224)));
722 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("lime"), Color( 0, 255, 0)));
723 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("limegreen"), Color( 50, 205, 50)));
724 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("linen"), Color(250, 240, 230)));
725 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("magenta"), Color(255, 0, 255)));
726 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("maroon"), Color(128, 0, 0)));
727 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumaquamarine"), Color(102, 205, 170)));
728 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumblue"), Color( 0, 0, 205)));
729 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumorchid"), Color(186, 85, 211)));
730 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumpurple"), Color(147, 112, 219)));
731 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumseagreen"), Color( 60, 179, 113)));
732 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumslateblue"), Color(123, 104, 238)));
733 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumspringgreen"), Color( 0, 250, 154)));
734 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumturquoise"), Color( 72, 209, 204)));
735 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mediumvioletred"), Color(199, 21, 133)));
736 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("midnightblue"), Color( 25, 25, 112)));
737 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mintcream"), Color(245, 255, 250)));
738 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("mistyrose"), Color(255, 228, 225)));
739 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("moccasin"), Color(255, 228, 181)));
740 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("navajowhite"), Color(255, 222, 173)));
741 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("navy"), Color( 0, 0, 128)));
742 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("oldlace"), Color(253, 245, 230)));
743 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("olive"), Color(128, 128, 0)));
744 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("olivedrab"), Color(107, 142, 35)));
745 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("orange"), Color(255, 165, 0)));
746 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("orangered"), Color(255, 69, 0)));
747 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("orchid"), Color(218, 112, 214)));
748 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("palegoldenrod"), Color(238, 232, 170)));
749 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("palegreen"), Color(152, 251, 152)));
750 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("paleturquoise"), Color(175, 238, 238)));
751 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("palevioletred"), Color(219, 112, 147)));
752 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("papayawhip"), Color(255, 239, 213)));
753 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("peachpuff"), Color(255, 218, 185)));
754 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("peru"), Color(205, 133, 63)));
755 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("pink"), Color(255, 192, 203)));
756 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("plum"), Color(221, 160, 221)));
757 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("powderblue"), Color(176, 224, 230)));
758 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("purple"), Color(128, 0, 128)));
759 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("red"), Color(255, 0, 0)));
760 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("rosybrown"), Color(188, 143, 143)));
761 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("royalblue"), Color( 65, 105, 225)));
762 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("saddlebrown"), Color(139, 69, 19)));
763 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("salmon"), Color(250, 128, 114)));
764 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("sandybrown"), Color(244, 164, 96)));
765 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("seagreen"), Color( 46, 139, 87)));
766 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("seashell"), Color(255, 245, 238)));
767 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("sienna"), Color(160, 82, 45)));
768 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("silver"), Color(192, 192, 192)));
769 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("skyblue"), Color(135, 206, 235)));
770 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("slateblue"), Color(106, 90, 205)));
771 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("slategray"), Color(112, 128, 144)));
772 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("slategrey"), Color(112, 128, 144)));
773 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("snow"), Color(255, 250, 250)));
774 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("springgreen"), Color( 0, 255, 127)));
775 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("steelblue"), Color( 70, 130, 180)));
776 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("tan"), Color(210, 180, 140)));
777 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("teal"), Color( 0, 128, 128)));
778 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("thistle"), Color(216, 191, 216)));
779 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("tomato"), Color(255, 99, 71)));
780 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("turquoise"), Color( 64, 224, 208)));
781 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("violet"), Color(238, 130, 238)));
782 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("wheat"), Color(245, 222, 179)));
783 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("white"), Color(255, 255, 255)));
784 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("whitesmoke"), Color(245, 245, 245)));
785 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("yellow"), Color(255, 255, 0)));
786 aColorTokenMapperList
.insert(ColorTokenValueType(OUString("yellowgreen"), Color(154, 205, 50)));
789 ColorTokenMapper::const_iterator
aResult(aColorTokenMapperList
.find(rName
));
791 if(bCaseIndependent
&& aResult
== aColorTokenMapperList
.end())
793 // also try case independent match (e.g. for Css styles)
794 aResult
= aColorTokenMapperList
.find(rName
.toAsciiLowerCase());
797 if(aResult
== aColorTokenMapperList
.end())
803 rColor
= aResult
->second
.getBColor();
808 bool read_color(const OUString
& rCandidate
, basegfx::BColor
& rColor
, bool bCaseIndependent
, SvgNumber
& rOpacity
)
810 const sal_Int32
nLen(rCandidate
.getLength());
814 const sal_Unicode
aChar(rCandidate
[0]);
815 const double fFactor(1.0 / 255.0);
823 copyHex(rCandidate
, nPos
, aNum
, nLen
);
824 const sal_Int32
nLength(aNum
.getLength());
828 const sal_Int32
nR(read_hex(aNum
[0]));
829 const sal_Int32
nG(read_hex(aNum
[1]));
830 const sal_Int32
nB(read_hex(aNum
[2]));
832 rColor
.setRed((nR
| (nR
<< 4)) * fFactor
);
833 rColor
.setGreen((nG
| (nG
<< 4)) * fFactor
);
834 rColor
.setBlue((nB
| (nB
<< 4)) * fFactor
);
838 else if(6 == nLength
)
840 const sal_Int32
nR1(read_hex(aNum
[0]));
841 const sal_Int32
nR2(read_hex(aNum
[1]));
842 const sal_Int32
nG1(read_hex(aNum
[2]));
843 const sal_Int32
nG2(read_hex(aNum
[3]));
844 const sal_Int32
nB1(read_hex(aNum
[4]));
845 const sal_Int32
nB2(read_hex(aNum
[5]));
847 rColor
.setRed((nR2
| (nR1
<< 4)) * fFactor
);
848 rColor
.setGreen((nG2
| (nG1
<< 4)) * fFactor
);
849 rColor
.setBlue((nB2
| (nB1
<< 4)) * fFactor
);
856 static const char aStrRgb
[] = "rgb";
858 if(rCandidate
.matchIgnoreAsciiCase(aStrRgb
, 0))
860 // rgb/rgba definition
861 sal_Int32
nPos(strlen(aStrRgb
));
862 bool bIsRGBA
= false;
864 if('a' == rCandidate
[nPos
])
866 //Delete the 'a' from 'rbga'
867 skip_char(rCandidate
, 'a', nPos
, nPos
+ 1);
871 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
874 if(readNumber(rCandidate
, nPos
, fR
, nLen
))
876 skip_char(rCandidate
, ' ', nPos
, nLen
);
880 const sal_Unicode
aPercentChar(rCandidate
[nPos
]);
881 const bool bIsPercent('%' == aPercentChar
);
886 skip_char(rCandidate
, '%', nPos
, nLen
);
889 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
891 if(readNumber(rCandidate
, nPos
, fG
, nLen
))
897 skip_char(rCandidate
, '%', nPos
, nLen
);
900 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
902 if(readNumber(rCandidate
, nPos
, fB
, nLen
))
908 skip_char(rCandidate
, '%', nPos
, nLen
);
911 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
913 if(readNumber(rCandidate
, nPos
, fA
, nLen
))
917 const double fFac(bIsPercent
? 0.01 : 1);
918 rOpacity
= SvgNumber(fA
* fFac
);
922 skip_char(rCandidate
, '%', nPos
, nLen
);
931 const double fFac(bIsPercent
? 0.01 : fFactor
);
933 rColor
.setRed(fR
* fFac
);
934 rColor
.setGreen(fG
* fFac
);
935 rColor
.setBlue(fB
* fFac
);
937 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
947 if(match_colorKeyword(rColor
, rCandidate
, bCaseIndependent
))
958 basegfx::B2DRange
readViewBox(const OUString
& rCandidate
, InfoProvider
const & rInfoProvider
)
960 const sal_Int32
nLen(rCandidate
.getLength());
966 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
968 if(readNumberAndUnit(rCandidate
, nPos
, aMinX
, nLen
))
971 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
973 if(readNumberAndUnit(rCandidate
, nPos
, aMinY
, nLen
))
976 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
978 if(readNumberAndUnit(rCandidate
, nPos
, aWidth
, nLen
))
981 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
983 if(readNumberAndUnit(rCandidate
, nPos
, aHeight
, nLen
))
985 double fX(aMinX
.solve(rInfoProvider
, xcoordinate
));
986 double fY(aMinY
.solve(rInfoProvider
, ycoordinate
));
987 double fW(aWidth
.solve(rInfoProvider
,xcoordinate
));
988 double fH(aHeight
.solve(rInfoProvider
,ycoordinate
));
989 return basegfx::B2DRange(fX
,fY
,fX
+fW
,fY
+fH
);
996 return basegfx::B2DRange();
999 basegfx::B2DHomMatrix
readTransform(const OUString
& rCandidate
, InfoProvider
const & rInfoProvider
)
1001 basegfx::B2DHomMatrix aMatrix
;
1002 const sal_Int32
nLen(rCandidate
.getLength());
1007 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1011 const sal_Unicode
aChar(rCandidate
[nPos
]);
1012 const sal_Int32
nInitPos(nPos
);
1013 static const char aStrMatrix
[] = "matrix";
1014 static const char aStrTranslate
[] = "translate";
1015 static const char aStrScale
[] = "scale";
1016 static const char aStrRotate
[] = "rotate";
1017 static const char aStrSkewX
[] = "skewX";
1018 static const char aStrSkewY
[] = "skewY";
1024 if(rCandidate
.match(aStrMatrix
, nPos
))
1027 nPos
+= strlen(aStrMatrix
);
1028 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1030 basegfx::B2DHomMatrix aNew
;
1032 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1034 aNew
.set(0, 0, aVal
.solve(rInfoProvider
)); // Element A
1035 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1037 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1039 aNew
.set(1, 0, aVal
.solve(rInfoProvider
)); // Element B
1040 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1042 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1044 aNew
.set(0, 1, aVal
.solve(rInfoProvider
)); // Element C
1045 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1047 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1049 aNew
.set(1, 1, aVal
.solve(rInfoProvider
)); // Element D
1050 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1052 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1054 aNew
.set(0, 2, aVal
.solve(rInfoProvider
, xcoordinate
)); // Element E
1055 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1057 if(readNumberAndUnit(rCandidate
, nPos
, aVal
, nLen
))
1059 aNew
.set(1, 2, aVal
.solve(rInfoProvider
, ycoordinate
)); // Element F
1060 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1061 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1063 // caution: String is evaluated from left to right, but matrix multiplication
1064 // in SVG is right to left, so put the new transformation before the current
1065 // one by multiplicating from the right side
1066 aMatrix
= aMatrix
* aNew
;
1078 if(rCandidate
.match(aStrTranslate
, nPos
))
1080 // translate element
1081 nPos
+= strlen(aStrTranslate
);
1082 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1085 if(readNumberAndUnit(rCandidate
, nPos
, aTransX
, nLen
))
1087 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1089 readNumberAndUnit(rCandidate
, nPos
, aTransY
, nLen
);
1090 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1091 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1093 aMatrix
= aMatrix
* basegfx::utils::createTranslateB2DHomMatrix(
1094 aTransX
.solve(rInfoProvider
, xcoordinate
),
1095 aTransY
.solve(rInfoProvider
, ycoordinate
));
1102 if(rCandidate
.match(aStrScale
, nPos
))
1105 nPos
+= strlen(aStrScale
);
1106 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1109 if(readNumberAndUnit(rCandidate
, nPos
, aScaleX
, nLen
))
1111 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1112 SvgNumber
aScaleY(aScaleX
);
1113 readNumberAndUnit(rCandidate
, nPos
, aScaleY
, nLen
);
1114 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1115 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1117 aMatrix
= aMatrix
* basegfx::utils::createScaleB2DHomMatrix(
1118 aScaleX
.solve(rInfoProvider
),
1119 aScaleY
.solve(rInfoProvider
));
1122 else if(rCandidate
.match(aStrSkewX
, nPos
))
1125 nPos
+= strlen(aStrSkewX
);
1126 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1129 if(readAngle(rCandidate
, nPos
, fSkewX
, nLen
))
1131 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1132 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1134 aMatrix
= aMatrix
* basegfx::utils::createShearXB2DHomMatrix(tan(fSkewX
));
1137 else if(rCandidate
.match(aStrSkewY
, nPos
))
1140 nPos
+= strlen(aStrSkewY
);
1141 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1144 if(readAngle(rCandidate
, nPos
, fSkewY
, nLen
))
1146 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1147 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1149 aMatrix
= aMatrix
* basegfx::utils::createShearYB2DHomMatrix(tan(fSkewY
));
1156 if(rCandidate
.match(aStrRotate
, nPos
))
1159 nPos
+= strlen(aStrRotate
);
1160 skip_char(rCandidate
, ' ', '(', nPos
, nLen
);
1163 if(readAngle(rCandidate
, nPos
, fAngle
, nLen
))
1165 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1167 readNumberAndUnit(rCandidate
, nPos
, aX
, nLen
);
1168 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1170 readNumberAndUnit(rCandidate
, nPos
, aY
, nLen
);
1171 skip_char(rCandidate
, ' ', ')', nPos
, nLen
);
1172 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1174 const double fX(aX
.isSet() ? aX
.solve(rInfoProvider
, xcoordinate
) : 0.0);
1175 const double fY(aY
.isSet() ? aY
.solve(rInfoProvider
, ycoordinate
) : 0.0);
1177 if(!basegfx::fTools::equalZero(fX
) || !basegfx::fTools::equalZero(fY
))
1179 // rotate around point
1180 aMatrix
= aMatrix
* basegfx::utils::createRotateAroundPoint(fX
, fY
, fAngle
);
1185 aMatrix
= aMatrix
* basegfx::utils::createRotateB2DHomMatrix(fAngle
);
1193 if(nInitPos
== nPos
)
1195 OSL_ENSURE(false, "Could not interpret on current position (!)");
1204 bool readSingleNumber(const OUString
& rCandidate
, SvgNumber
& aNum
)
1206 const sal_Int32
nLen(rCandidate
.getLength());
1209 return readNumberAndUnit(rCandidate
, nPos
, aNum
, nLen
);
1212 bool readLocalUrl(const OUString
& rCandidate
, OUString
& rURL
)
1214 static const char aStrUrl
[] = "url";
1216 if(rCandidate
.startsWith(aStrUrl
))
1218 const sal_Int32
nLen(rCandidate
.getLength());
1219 sal_Int32
nPos(strlen(aStrUrl
));
1221 skip_char(rCandidate
, '(', '#', nPos
, nLen
);
1222 OUStringBuffer aTokenValue
;
1223 copyToLimiter(rCandidate
, ')', nPos
, aTokenValue
, nLen
);
1224 rURL
= aTokenValue
.makeStringAndClear();
1232 bool readSvgPaint(const OUString
& rCandidate
, SvgPaint
& rSvgPaint
,
1233 OUString
& rURL
, bool bCaseIndependent
, SvgNumber
& rOpacity
)
1235 if( !rCandidate
.isEmpty() )
1237 basegfx::BColor aColor
;
1239 if(read_color(rCandidate
, aColor
, bCaseIndependent
, rOpacity
))
1241 rSvgPaint
= SvgPaint(aColor
, true, true);
1246 if(rCandidate
.startsWith("none"))
1248 rSvgPaint
= SvgPaint(aColor
, true, false, false);
1251 else if(readLocalUrl(rCandidate
, rURL
))
1253 /// Url is copied to rURL, but needs to be solved outside this helper
1256 else if(rCandidate
.startsWith("currentColor"))
1258 rSvgPaint
= SvgPaint(aColor
, true, true, true);
1267 bool readSvgNumberVector(const OUString
& rCandidate
, SvgNumberVector
& rSvgNumberVector
)
1269 const sal_Int32
nLen(rCandidate
.getLength());
1270 rSvgNumberVector
.clear();
1276 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1278 while(readNumberAndUnit(rCandidate
, nPos
, aNum
, nLen
))
1280 rSvgNumberVector
.push_back(aNum
);
1281 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1284 return !rSvgNumberVector
.empty();
1290 SvgAspectRatio
readSvgAspectRatio(const OUString
& rCandidate
)
1292 const sal_Int32
nLen(rCandidate
.getLength());
1297 SvgAlign
aSvgAlign(Align_xMidYMid
);
1298 bool bMeetOrSlice(true);
1299 bool bChanged(false);
1303 const sal_Int32
nInitPos(nPos
);
1304 skip_char(rCandidate
, ' ', nPos
, nLen
);
1305 OUStringBuffer aTokenName
;
1306 copyString(rCandidate
, nPos
, aTokenName
, nLen
);
1308 if(!aTokenName
.isEmpty())
1310 switch(StrToSVGToken(aTokenName
.makeStringAndClear(), false))
1319 aSvgAlign
= Align_none
;
1323 case SVGTokenXMinYMin
:
1325 aSvgAlign
= Align_xMinYMin
;
1329 case SVGTokenXMidYMin
:
1331 aSvgAlign
= Align_xMidYMin
;
1335 case SVGTokenXMaxYMin
:
1337 aSvgAlign
= Align_xMaxYMin
;
1341 case SVGTokenXMinYMid
:
1343 aSvgAlign
= Align_xMinYMid
;
1347 case SVGTokenXMidYMid
:
1349 aSvgAlign
= Align_xMidYMid
;
1353 case SVGTokenXMaxYMid
:
1355 aSvgAlign
= Align_xMaxYMid
;
1359 case SVGTokenXMinYMax
:
1361 aSvgAlign
= Align_xMinYMax
;
1365 case SVGTokenXMidYMax
:
1367 aSvgAlign
= Align_xMidYMax
;
1371 case SVGTokenXMaxYMax
:
1373 aSvgAlign
= Align_xMaxYMax
;
1379 bMeetOrSlice
= true;
1385 bMeetOrSlice
= false;
1396 if(nInitPos
== nPos
)
1398 OSL_ENSURE(false, "Could not interpret on current position (!)");
1405 return SvgAspectRatio(aSvgAlign
, bMeetOrSlice
);
1409 return SvgAspectRatio();
1412 bool readSvgStringVector(const OUString
& rCandidate
, SvgStringVector
& rSvgStringVector
)
1414 rSvgStringVector
.clear();
1415 const sal_Int32
nLen(rCandidate
.getLength());
1420 OUStringBuffer aTokenValue
;
1421 skip_char(rCandidate
, ' ', ',', nPos
, nLen
);
1425 copyToLimiter(rCandidate
, ',', nPos
, aTokenValue
, nLen
);
1426 skip_char(rCandidate
, ',', ' ', nPos
, nLen
);
1427 const OUString aString
= aTokenValue
.makeStringAndClear();
1429 if(!aString
.isEmpty())
1431 rSvgStringVector
.push_back(aString
);
1436 return !rSvgStringVector
.empty();
1439 void readImageLink(const OUString
& rCandidate
, OUString
& rXLink
, OUString
& rUrl
, OUString
& rMimeType
, OUString
& rData
)
1446 if('#' == rCandidate
[0])
1449 rXLink
= rCandidate
.copy(1);
1453 static const char aStrData
[] = "data:";
1455 if(rCandidate
.match(aStrData
, 0))
1458 sal_Int32
nPos(strlen(aStrData
));
1459 sal_Int32
nLen(rCandidate
.getLength());
1460 OUStringBuffer aBuffer
;
1463 skip_char(rCandidate
, ' ', nPos
, nLen
);
1464 copyToLimiter(rCandidate
, ';', nPos
, aBuffer
, nLen
);
1465 skip_char(rCandidate
, ' ', ';', nPos
, nLen
);
1466 rMimeType
= aBuffer
.makeStringAndClear();
1468 if(!rMimeType
.isEmpty() && nPos
< nLen
)
1470 if(rMimeType
.startsWith("image"))
1473 OUString
aData(rCandidate
.copy(nPos
));
1474 static const char aStrBase64
[] = "base64";
1476 if(aData
.startsWith(aStrBase64
))
1479 nPos
= strlen(aStrBase64
);
1480 nLen
= aData
.getLength();
1482 skip_char(aData
, ' ', ',', nPos
, nLen
);
1486 rData
= aData
.copy(nPos
);
1494 // Url (path and filename)
1500 OUString
convert(const OUString
& rCandidate
, sal_Unicode nPattern
, sal_Unicode nNew
, bool bRemove
)
1502 const sal_Int32
nLen(rCandidate
.getLength());
1507 OUStringBuffer aBuffer
;
1508 bool bChanged(false);
1512 const sal_Unicode
aChar(rCandidate
[nPos
]);
1514 if(nPattern
== aChar
)
1520 aBuffer
.append(nNew
);
1525 aBuffer
.append(aChar
);
1533 return aBuffer
.makeStringAndClear();
1541 OUString
removeBlockComments(const OUString
& rCandidate
)
1543 const sal_Int32
nLen(rCandidate
.getLength());
1548 OUStringBuffer aBuffer
;
1549 bool bChanged(false);
1550 sal_Int32
nInsideComment(0);
1551 const sal_Unicode
aCommentSlash('/');
1552 const sal_Unicode
aCommentStar('*');
1556 const sal_Unicode
aChar(rCandidate
[nPos
]);
1557 const bool bStart(aCommentSlash
== aChar
&& nPos
+ 1 < nLen
&& aCommentStar
== rCandidate
[nPos
+ 1]);
1558 const bool bEnd(aCommentStar
== aChar
&& nPos
+ 1 < nLen
&& aCommentSlash
== rCandidate
[nPos
+ 1]);
1575 aBuffer
.append(aChar
);
1584 return aBuffer
.makeStringAndClear();
1591 OUString
consolidateContiguousSpace(const OUString
& rCandidate
)
1593 const sal_Int32
nLen(rCandidate
.getLength());
1598 OUStringBuffer aBuffer
;
1599 bool bInsideSpace(false);
1600 const sal_Unicode
aSpace(' ');
1604 const sal_Unicode
aChar(rCandidate
[nPos
]);
1608 bInsideSpace
= true;
1614 bInsideSpace
= false;
1615 aBuffer
.append(aSpace
);
1618 aBuffer
.append(aChar
);
1626 aBuffer
.append(aSpace
);
1629 if(aBuffer
.getLength() != nLen
)
1631 return aBuffer
.makeStringAndClear();
1638 OUString
whiteSpaceHandlingDefault(const OUString
& rCandidate
)
1640 const sal_Unicode
aNewline('\n');
1641 const sal_Unicode
aTab('\t');
1642 const sal_Unicode
aSpace(' ');
1644 // remove all newline characters
1645 OUString
aRetval(convert(rCandidate
, aNewline
, aNewline
, true));
1647 // convert tab to space
1648 aRetval
= convert(aRetval
, aTab
, aSpace
, false);
1650 // strip of all leading and trailing spaces
1651 aRetval
= aRetval
.trim();
1653 // consolidate contiguous space
1654 aRetval
= consolidateContiguousSpace(aRetval
);
1659 OUString
whiteSpaceHandlingPreserve(const OUString
& rCandidate
)
1661 const sal_Unicode
aNewline('\n');
1662 const sal_Unicode
aTab('\t');
1663 const sal_Unicode
aSpace(' ');
1665 // convert newline to space
1666 convert(rCandidate
, aNewline
, aSpace
, false);
1668 // convert tab to space
1669 convert(rCandidate
, aTab
, aSpace
, false);
1674 ::std::vector
< double > solveSvgNumberVector(const SvgNumberVector
& rInput
, const InfoProvider
& rInfoProvider
)
1676 ::std::vector
< double > aRetval
;
1680 const double nCount(rInput
.size());
1681 aRetval
.reserve(nCount
);
1683 for(sal_uInt32
a(0); a
< nCount
; a
++)
1685 aRetval
.push_back(rInput
[a
].solve(rInfoProvider
));
1692 } // end of namespace svgreader
1693 } // end of namespace svgio
1695 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */