1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svgio.hxx"
24 
25 #include <svgio/svgreader/svgtools.hxx>
26 #include <osl/thread.h>
27 #include <tools/color.hxx>
28 #include <basegfx/matrix/b2dhommatrix.hxx>
29 #include <basegfx/matrix/b2dhommatrixtools.hxx>
30 #include <svgio/svgreader/svgtoken.hxx>
31 #include <hash_map>
32 
33 //////////////////////////////////////////////////////////////////////////////
34 
35 namespace svgio
36 {
37     namespace svgreader
38     {
39 #ifdef DBG_UTIL
40         void myAssert(const rtl::OUString& rMessage)
41         {
42             rtl::OString aMessage2;
43 
44             rMessage.convertToString(&aMessage2, osl_getThreadTextEncoding(), RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR|RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR);
45             OSL_ENSURE(false, aMessage2.getStr());
46         }
47 #endif
48 
49         // common non-token strings
50         const rtl::OUString commonStrings::aStrUserSpaceOnUse(rtl::OUString::createFromAscii("userSpaceOnUse"));
51         const rtl::OUString commonStrings::aStrObjectBoundingBox(rtl::OUString::createFromAscii("objectBoundingBox"));
52         const rtl::OUString commonStrings::aStrNonzero(rtl::OUString::createFromAscii("nonzero"));
53         const rtl::OUString commonStrings::aStrEvenOdd(rtl::OUString::createFromAscii("evenodd"));
54 
55         basegfx::B2DHomMatrix SvgAspectRatio::createLinearMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource)
56         {
57             basegfx::B2DHomMatrix aRetval;
58             const double fSWidth(rSource.getWidth());
59             const double fSHeight(rSource.getHeight());
60             const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
61             const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
62 
63             // transform from source state to unit range
64             aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
65             aRetval.scale(
66                 (bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth(),
67                 (bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
68 
69             // transform from unit rage to target range
70             aRetval.translate(rTarget.getMinX(), rTarget.getMinY());
71 
72             return aRetval;
73         }
74 
75         basegfx::B2DHomMatrix SvgAspectRatio::createMapping(const basegfx::B2DRange& rTarget, const basegfx::B2DRange& rSource) const
76         {
77             if(!isSet() || Align_none == getSvgAlign())
78             {
79                 // create linear mapping (default)
80                 return createLinearMapping(rTarget, rSource);
81             }
82 
83             basegfx::B2DHomMatrix aRetval;
84 
85             const double fSWidth(rSource.getWidth());
86             const double fSHeight(rSource.getHeight());
87             const bool bNoSWidth(basegfx::fTools::equalZero(fSWidth));
88             const bool bNoSHeight(basegfx::fTools::equalZero(fSHeight));
89             const double fScaleX((bNoSWidth ? 1.0 : 1.0 / fSWidth) * rTarget.getWidth());
90             const double fScaleY((bNoSHeight ? 1.0 : 1.0 / fSHeight) * rTarget.getHeight());
91             const double fScale(isMeetOrSlice() ? std::min(fScaleX, fScaleY) : std::max(fScaleX, fScaleY));
92 
93             // remove source translation, apply scale
94             aRetval.translate(-rSource.getMinX(), -rSource.getMinY());
95             aRetval.scale(fScale, fScale);
96 
97             // evaluate horizontal alignment
98             const double fNewWidth(fSWidth * fScale);
99             double fTransX(0.0);
100 
101             switch(getSvgAlign())
102             {
103                 case Align_xMidYMin:
104                 case Align_xMidYMid:
105                 case Align_xMidYMax:
106                 {
107                     // centerX
108                     const double fFreeSpace(rTarget.getWidth() - fNewWidth);
109                     fTransX = fFreeSpace * 0.5;
110                     break;
111                 }
112                 case Align_xMaxYMin:
113                 case Align_xMaxYMid:
114                 case Align_xMaxYMax:
115                 {
116                     // Right align
117                     const double fFreeSpace(rTarget.getWidth() - fNewWidth);
118                     fTransX = fFreeSpace;
119                     break;
120                 }
121                 default: break;
122             }
123 
124             // evaluate vertical alignment
125             const double fNewHeight(fSHeight * fScale);
126             double fTransY(0.0);
127 
128             switch(getSvgAlign())
129             {
130                 case Align_xMinYMid:
131                 case Align_xMidYMid:
132                 case Align_xMaxYMid:
133                 {
134                     // centerY
135                     const double fFreeSpace(rTarget.getHeight() - fNewHeight);
136                     fTransY = fFreeSpace * 0.5;
137                     break;
138                 }
139                 case Align_xMinYMax:
140                 case Align_xMidYMax:
141                 case Align_xMaxYMax:
142                 {
143                     // Bottom align
144                     const double fFreeSpace(rTarget.getHeight() - fNewHeight);
145                     fTransY = fFreeSpace;
146                     break;
147                 }
148                 default: break;
149             }
150 
151             // add target translation
152             aRetval.translate(
153                 rTarget.getMinX() + fTransX,
154                 rTarget.getMinY() + fTransY);
155 
156             return aRetval;
157         }
158 
159         double SvgNumber::solveNonPercentage(const InfoProvider& rInfoProvider) const
160         {
161             if(isSet())
162             {
163                 switch(meUnit)
164                 {
165                     case Unit_em:
166                     {
167                         return mfNumber * rInfoProvider.getCurrentFontSize();
168                         break;
169                     }
170                     case Unit_ex:
171                     {
172                         return mfNumber * rInfoProvider.getCurrentXHeight() * 0.5;
173                         break;
174                     }
175                     case Unit_px:
176                     {
177                         return mfNumber;
178                         break;
179                     }
180                     case Unit_pt:
181                     case Unit_pc:
182                     case Unit_cm:
183                     case Unit_mm:
184                     case Unit_in:
185                     {
186                         double fRetval(mfNumber);
187 
188                         switch(meUnit)
189                         {
190                             case Unit_pt: fRetval *= F_SVG_PIXEL_PER_INCH / 72.0; break;
191                             case Unit_pc: fRetval *= F_SVG_PIXEL_PER_INCH / 6.0; break;
192                             case Unit_cm: fRetval *= F_SVG_PIXEL_PER_INCH / 2.54; break;
193                             case Unit_mm: fRetval *= 0.1 * F_SVG_PIXEL_PER_INCH / 2.54; break;
194                             case Unit_in: fRetval *= F_SVG_PIXEL_PER_INCH; break;
195                             default: break;
196                         }
197 
198                         return fRetval;
199                         break;
200                     }
201                     default:
202                     {
203                         OSL_ENSURE(false, "Do not use with percentage! ");
204                         return 0.0;
205                         break;
206                     }
207                 }
208             }
209 
210             /// not set
211             OSL_ENSURE(false, "SvgNumber not set (!)");
212             return 0.0;
213         }
214 
215         double SvgNumber::solve(const InfoProvider& rInfoProvider, NumberType aNumberType) const
216         {
217             if(isSet())
218             {
219                 switch(meUnit)
220                 {
221                     case Unit_px:
222                     {
223                         return mfNumber;
224                         break;
225                     }
226                     case Unit_pt:
227                     case Unit_pc:
228                     case Unit_cm:
229                     case Unit_mm:
230                     case Unit_in:
231                     case Unit_em:
232                     case Unit_ex:
233                     {
234                         return solveNonPercentage( rInfoProvider);
235                         break;
236                     }
237                     case Unit_percent:
238                     {
239                         double fRetval(mfNumber * 0.01);
240                         const basegfx::B2DRange* pViewPort = rInfoProvider.getCurrentViewPort();
241 
242                         if(!pViewPort)
243                         {
244 #ifdef DBG_UTIL
245                             myAssert(rtl::OUString::createFromAscii("Design error, this case should have been handled in the caller"));
246 #endif
247                             // no viewPort, assume a normal page size (A4)
248                             static basegfx::B2DRange aDinA4Range(
249                                 0.0,
250                                 0.0,
251                                 210.0 * F_SVG_PIXEL_PER_INCH / 2.54,
252                                 297.0 * F_SVG_PIXEL_PER_INCH / 2.54);
253 
254                             pViewPort = &aDinA4Range;
255                         }
256 
257                         if(pViewPort)
258                         {
259                             if(xcoordinate == aNumberType)
260                             {
261                                 // it's a x-coordinate, relative to current width (w)
262                                 fRetval *= pViewPort->getWidth();
263                             }
264                             else if(ycoordinate == aNumberType)
265                             {
266                                 // it's a y-coordinate, relative to current height (h)
267                                 fRetval *= pViewPort->getHeight();
268                             }
269                             else // length
270                             {
271                                 // it's a length, relative to sqrt(w*w + h*h)/sqrt(2)
272                                 const double fCurrentWidth(pViewPort->getWidth());
273                                 const double fCurrentHeight(pViewPort->getHeight());
274                                 const double fCurrentLength(
275                                     sqrt(fCurrentWidth * fCurrentWidth + fCurrentHeight * fCurrentHeight)/sqrt(2.0));
276 
277                                 fRetval *= fCurrentLength;
278                             }
279                         }
280 
281                         return fRetval;
282                         break;
283                     }
284                     default:
285                     {
286                         break;
287                     }
288                 }
289             }
290 
291             /// not set
292             OSL_ENSURE(false, "SvgNumber not set (!)");
293             return 0.0;
294         }
295 
296         bool SvgNumber::isPositive() const
297         {
298             return basegfx::fTools::moreOrEqual(mfNumber, 0.0);
299         }
300 
301         void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rChar, sal_Int32& nPos, const sal_Int32 nLen)
302         {
303             while(nPos < nLen && rChar == rCandidate[nPos])
304             {
305                 nPos++;
306             }
307         }
308 
309         void skip_char(const rtl::OUString& rCandidate, const sal_Unicode& rCharA, const sal_Unicode& rCharB, sal_Int32& nPos, const sal_Int32 nLen)
310         {
311             while(nPos < nLen && (rCharA == rCandidate[nPos] || rCharB == rCandidate[nPos]))
312             {
313                 nPos++;
314             }
315         }
316 
317         void copySign(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
318         {
319             if(nPos < nLen)
320             {
321                 const sal_Unicode aChar(rCandidate[nPos]);
322 
323                 if(sal_Unicode('+') == aChar || sal_Unicode('-') == aChar)
324                 {
325                     rTarget.append(aChar);
326                     nPos++;
327                 }
328             }
329         }
330 
331         void copyNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
332         {
333             bool bOnNumber(true);
334 
335             while(bOnNumber && nPos < nLen)
336             {
337                 const sal_Unicode aChar(rCandidate[nPos]);
338 
339                 bOnNumber = (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar) || sal_Unicode('.') == aChar;
340 
341                 if(bOnNumber)
342                 {
343                     rTarget.append(aChar);
344                     nPos++;
345                 }
346             }
347         }
348 
349         void copyHex(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
350         {
351             bool bOnHex(true);
352 
353             while(bOnHex && nPos < nLen)
354             {
355                 const sal_Unicode aChar(rCandidate[nPos]);
356 
357                 bOnHex = (sal_Unicode('0') <= aChar && sal_Unicode('9') >= aChar)
358                     || (sal_Unicode('A') <= aChar && sal_Unicode('F') >= aChar)
359                     || (sal_Unicode('a') <= aChar && sal_Unicode('f') >= aChar);
360 
361                 if(bOnHex)
362                 {
363                     rTarget.append(aChar);
364                     nPos++;
365                 }
366             }
367         }
368 
369         void copyString(const rtl::OUString& rCandidate, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
370         {
371             bool bOnChar(true);
372 
373             while(bOnChar && nPos < nLen)
374             {
375                 const sal_Unicode aChar(rCandidate[nPos]);
376 
377                 bOnChar = (sal_Unicode('a') <= aChar && sal_Unicode('z') >= aChar)
378                     || (sal_Unicode('A') <= aChar && sal_Unicode('Z') >= aChar)
379                     || sal_Unicode('-') == aChar;
380 
381                 if(bOnChar)
382                 {
383                     rTarget.append(aChar);
384                     nPos++;
385                 }
386             }
387         }
388 
389         void copyToLimiter(const rtl::OUString& rCandidate, const sal_Unicode& rLimiter, sal_Int32& nPos, rtl::OUStringBuffer& rTarget, const sal_Int32 nLen)
390         {
391             while(nPos < nLen && rLimiter != rCandidate[nPos])
392             {
393                 rTarget.append(rCandidate[nPos]);
394                 nPos++;
395             }
396         }
397 
398         bool readNumber(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fNum, const sal_Int32 nLen)
399         {
400             if(nPos < nLen)
401             {
402                 rtl::OUStringBuffer aNum;
403 
404                 copySign(rCandidate, nPos, aNum, nLen);
405                 copyNumber(rCandidate, nPos, aNum, nLen);
406 
407                 if(nPos < nLen)
408                 {
409                     const sal_Unicode aChar(rCandidate[nPos]);
410 
411                     if(sal_Unicode('e') == aChar || sal_Unicode('E') == aChar)
412                     {
413                         // try to read exponential number, but be careful. I had
414                         // a case where dx="2em" was used, thus the 'e' was consumed
415                         // by error. First try if there are numbers after the 'e',
416                         // safe current state
417                         nPos++;
418                         const rtl::OUStringBuffer aNum2(aNum);
419                         const sal_Int32 nPosAfterE(nPos);
420 
421                         aNum.append(aChar);
422                         copySign(rCandidate, nPos, aNum, nLen);
423                         copyNumber(rCandidate, nPos, aNum, nLen);
424 
425                         if(nPosAfterE == nPos)
426                         {
427                             // no number after 'e', go back. Do not
428                             // return false, it's still a valid integer number
429                             aNum = aNum2;
430                             nPos--;
431                         }
432                     }
433                 }
434 
435                 if(aNum.getLength())
436                 {
437                     rtl_math_ConversionStatus eStatus;
438 
439                     fNum = rtl::math::stringToDouble(
440                         aNum.makeStringAndClear(), (sal_Unicode)('.'), (sal_Unicode)(','),
441                         &eStatus, 0);
442 
443                     return eStatus == rtl_math_ConversionStatus_Ok;
444                 }
445             }
446 
447             return false;
448         }
449 
450         SvgUnit readUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, const sal_Int32 nLen)
451         {
452             SvgUnit aRetval(Unit_px);
453 
454             if(nPos < nLen)
455             {
456                 const sal_Unicode aCharA(rCandidate[nPos]);
457 
458                 if(nPos + 1 < nLen)
459                 {
460                     const sal_Unicode aCharB(rCandidate[nPos + 1]);
461                     bool bTwoCharValid(false);
462 
463                     switch(aCharA)
464                     {
465                         case sal_Unicode('e') :
466                         {
467                             if(sal_Unicode('m') == aCharB)
468                             {
469                                 // 'em' Relative to current font size
470                                 aRetval = Unit_em;
471                                 bTwoCharValid = true;
472                             }
473                             else if(sal_Unicode('x') == aCharB)
474                             {
475                                 // 'ex' Relative to current font x-height
476                                 aRetval = Unit_ex;
477                                 bTwoCharValid = true;
478                             }
479                             break;
480                         }
481                         case sal_Unicode('p') :
482                         {
483                             if(sal_Unicode('x') == aCharB)
484                             {
485                                 // 'px' UserUnit (default)
486                                 bTwoCharValid = true;
487                             }
488                             else if(sal_Unicode('t') == aCharB)
489                             {
490                                 // 'pt' == 1.25 px
491                                 aRetval = Unit_pt;
492                                 bTwoCharValid = true;
493                             }
494                             else if(sal_Unicode('c') == aCharB)
495                             {
496                                 // 'pc' == 15 px
497                                 aRetval = Unit_pc;
498                                 bTwoCharValid = true;
499                             }
500                             break;
501                         }
502                         case sal_Unicode('i') :
503                         {
504                             if(sal_Unicode('n') == aCharB)
505                             {
506                                 // 'in' == 90 px
507                                 aRetval = Unit_in;
508                                 bTwoCharValid = true;
509                             }
510                             break;
511                         }
512                         case sal_Unicode('c') :
513                         {
514                             if(sal_Unicode('m') == aCharB)
515                             {
516                                 // 'cm' == 35.43307 px
517                                 aRetval = Unit_cm;
518                                 bTwoCharValid = true;
519                             }
520                             break;
521                         }
522                         case sal_Unicode('m') :
523                         {
524                             if(sal_Unicode('m') == aCharB)
525                             {
526                                 // 'mm' == 3.543307 px
527                                 aRetval = Unit_mm;
528                                 bTwoCharValid = true;
529                             }
530                             break;
531                         }
532                     }
533 
534                     if(bTwoCharValid)
535                     {
536                         nPos += 2;
537                     }
538                 }
539                 else
540                 {
541                     if(sal_Unicode('%') == aCharA)
542                     {
543                         // percent used, relative to current
544                         nPos++;
545                         aRetval = Unit_percent;
546                     }
547                 }
548             }
549 
550             return aRetval;
551         }
552 
553         bool readNumberAndUnit(const rtl::OUString& rCandidate, sal_Int32& nPos, SvgNumber& aNum, const sal_Int32 nLen)
554         {
555             double fNum(0.0);
556 
557             if(readNumber(rCandidate, nPos, fNum, nLen))
558             {
559                 skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
560                 aNum = SvgNumber(fNum, readUnit(rCandidate, nPos, nLen));
561 
562                 return true;
563             }
564 
565             return false;
566         }
567 
568         bool readAngle(const rtl::OUString& rCandidate, sal_Int32& nPos, double& fAngle, const sal_Int32 nLen)
569         {
570             if(readNumber(rCandidate, nPos, fAngle, nLen))
571             {
572                 skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
573 
574                 enum DegreeType
575                 {
576                     deg,
577                     grad,
578                     rad
579                 } aType(deg); // degrees is default
580 
581                 if(nPos < nLen)
582                 {
583                     const sal_Unicode aChar(rCandidate[nPos]);
584                     static rtl::OUString aStrGrad(rtl::OUString::createFromAscii("grad"));
585                     static rtl::OUString aStrRad(rtl::OUString::createFromAscii("rad"));
586 
587                     switch(aChar)
588                     {
589                         case sal_Unicode('g') :
590                         case sal_Unicode('G') :
591                         {
592                             if(rCandidate.matchIgnoreAsciiCase(aStrGrad, nPos))
593                             {
594                                 // angle in grad
595                                 nPos += aStrGrad.getLength();
596                             }
597                             break;
598                         }
599                         case sal_Unicode('r') :
600                         case sal_Unicode('R') :
601                         {
602                             if(rCandidate.matchIgnoreAsciiCase(aStrRad, nPos))
603                             {
604                                 // angle in radians
605                                 nPos += aStrRad.getLength();
606                             }
607                             break;
608                         }
609                     }
610                 }
611 
612                 // convert to radians
613                 if(deg == aType)
614                 {
615                     fAngle *= F_PI / 180.0;
616                 }
617                 else if(grad == aType)
618                 {
619                     // looks like 100 grad is 90 degrees
620                     fAngle *= F_PI / 200.0;
621                 }
622 
623                 return true;
624             }
625 
626             return false;
627         }
628 
629         sal_Int32 read_hex(const sal_Unicode& rChar)
630         {
631             if(rChar >= sal_Unicode('0') && rChar <=sal_Unicode('9'))
632             {
633                 return sal_Int32(rChar - sal_Unicode('0'));
634             }
635             else if(rChar >= sal_Unicode('A') && rChar <=sal_Unicode('F'))
636             {
637                 return 10 + sal_Int32(rChar - sal_Unicode('A'));
638             }
639             else if(rChar >= sal_Unicode('a') && rChar <=sal_Unicode('f'))
640             {
641                 return 10 + sal_Int32(rChar - sal_Unicode('a'));
642             }
643             else
644             {
645                 // error
646                 return 0;
647             }
648         }
649 
650         bool match_colorKeyword(basegfx::BColor& rColor, const rtl::OUString& rName)
651         {
652             typedef std::hash_map< rtl::OUString, Color, rtl::OUStringHash > ColorTokenMapper;
653             typedef std::pair< rtl::OUString, Color > ColorTokenValueType;
654             ColorTokenMapper aColorTokenMapperList;
655 
656             if(aColorTokenMapperList.empty())
657             {
658                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aliceblue"), Color(240, 248, 255)));
659                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("antiquewhite"), Color(250, 235, 215)));
660                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aqua"), Color( 0, 255, 255)));
661                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("aquamarine"), Color(127, 255, 212)));
662                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("azure"), Color(240, 255, 255)));
663                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("beige"), Color(245, 245, 220)));
664                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("bisque"), Color(255, 228, 196)));
665                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("black"), Color( 0, 0, 0)));
666                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blanchedalmond"), Color(255, 235, 205)));
667                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blue"), Color( 0, 0, 255)));
668                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("blueviolet"), Color(138, 43, 226)));
669                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("brown"), Color(165, 42, 42)));
670                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("burlywood"), Color(222, 184, 135)));
671                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cadetblue"), Color( 95, 158, 160)));
672                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("chartreuse"), Color(127, 255, 0)));
673                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("chocolate"), Color(210, 105, 30)));
674                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("coral"), Color(255, 127, 80)));
675                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cornflowerblue"), Color(100, 149, 237)));
676                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cornsilk"), Color(255, 248, 220)));
677                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("crimson"), Color(220, 20, 60)));
678                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("cyan"), Color( 0, 255, 255)));
679                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkblue"), Color( 0, 0, 139)));
680                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkcyan"), Color( 0, 139, 139)));
681                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgoldenrod"), Color(184, 134, 11)));
682                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgray"), Color(169, 169, 169)));
683                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgreen"), Color( 0, 100, 0)));
684                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkgrey"), Color(169, 169, 169)));
685                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkkhaki"), Color(189, 183, 107)));
686                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkmagenta"), Color(139, 0, 139)));
687                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkolivegreen"), Color( 85, 107, 47)));
688                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkorange"), Color(255, 140, 0)));
689                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkorchid"), Color(153, 50, 204)));
690                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkred"), Color(139, 0, 0)));
691                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darksalmon"), Color(233, 150, 122)));
692                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkseagreen"), Color(143, 188, 143)));
693                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslateblue"), Color( 72, 61, 139)));
694                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslategray"), Color( 47, 79, 79)));
695                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkslategrey"), Color( 47, 79, 79)));
696                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkturquoise"), Color( 0, 206, 209)));
697                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("darkviolet"), Color(148, 0, 211)));
698                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("deeppink"), Color(255, 20, 147)));
699                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("deepskyblue"), Color( 0, 191, 255)));
700                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dimgray"), Color(105, 105, 105)));
701                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dimgrey"), Color(105, 105, 105)));
702                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("dodgerblue"), Color( 30, 144, 255)));
703                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("firebrick"), Color(178, 34, 34)));
704                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("floralwhite"), Color(255, 250, 240)));
705                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("forestgreen"), Color( 34, 139, 34)));
706                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("fuchsia"), Color(255, 0, 255)));
707                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gainsboro"), Color(220, 220, 220)));
708                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("ghostwhite"), Color(248, 248, 255)));
709                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gold"), Color(255, 215, 0)));
710                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("goldenrod"), Color(218, 165, 32)));
711                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("gray"), Color(128, 128, 128)));
712                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("grey"), Color(128, 128, 128)));
713                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("green"), Color(0, 128, 0)));
714                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("greenyellow"), Color(173, 255, 47)));
715                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("honeydew"), Color(240, 255, 240)));
716                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("hotpink"), Color(255, 105, 180)));
717                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("indianred"), Color(205, 92, 92)));
718                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("indigo"), Color( 75, 0, 130)));
719                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("ivory"), Color(255, 255, 240)));
720                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("khaki"), Color(240, 230, 140)));
721                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lavender"), Color(230, 230, 250)));
722                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lavenderblush"), Color(255, 240, 245)));
723                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lawngreen"), Color(124, 252, 0)));
724                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lemonchiffon"), Color(255, 250, 205)));
725                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightblue"), Color(173, 216, 230)));
726                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightcoral"), Color(240, 128, 128)));
727                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightcyan"), Color(224, 255, 255)));
728                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgoldenrodyellow"), Color(250, 250, 210)));
729                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgray"), Color(211, 211, 211)));
730                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgreen"), Color(144, 238, 144)));
731                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightgrey"), Color(211, 211, 211)));
732                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightpink"), Color(255, 182, 193)));
733                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightsalmon"), Color(255, 160, 122)));
734                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightseagreen"), Color( 32, 178, 170)));
735                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightskyblue"), Color(135, 206, 250)));
736                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightslategray"), Color(119, 136, 153)));
737                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightslategrey"), Color(119, 136, 153)));
738                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightsteelblue"), Color(176, 196, 222)));
739                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lightyellow"), Color(255, 255, 224)));
740                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("lime"), Color( 0, 255, 0)));
741                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("limegreen"), Color( 50, 205, 50)));
742                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("linen"), Color(250, 240, 230)));
743                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("magenta"), Color(255, 0, 255)));
744                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("maroon"), Color(128, 0, 0)));
745                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumaquamarine"), Color(102, 205, 170)));
746                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumblue"), Color( 0, 0, 205)));
747                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumorchid"), Color(186, 85, 211)));
748                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumpurple"), Color(147, 112, 219)));
749                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumseagreen"), Color( 60, 179, 113)));
750                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumslateblue"), Color(123, 104, 238)));
751                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumspringgreen"), Color( 0, 250, 154)));
752                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumturquoise"), Color( 72, 209, 204)));
753                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mediumvioletred"), Color(199, 21, 133)));
754                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("midnightblue"), Color( 25, 25, 112)));
755                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mintcream"), Color(245, 255, 250)));
756                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("mistyrose"), Color(255, 228, 225)));
757                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("moccasin"), Color(255, 228, 181)));
758                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("navajowhite"), Color(255, 222, 173)));
759                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("navy"), Color( 0, 0, 128)));
760                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("oldlace"), Color(253, 245, 230)));
761                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("olive"), Color(128, 128, 0)));
762                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("olivedrab"), Color(107, 142, 35)));
763                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orange"), Color(255, 165, 0)));
764                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orangered"), Color(255, 69, 0)));
765                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("orchid"), Color(218, 112, 214)));
766                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palegoldenrod"), Color(238, 232, 170)));
767                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palegreen"), Color(152, 251, 152)));
768                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("paleturquoise"), Color(175, 238, 238)));
769                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("palevioletred"), Color(219, 112, 147)));
770                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("papayawhip"), Color(255, 239, 213)));
771                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("peachpuff"), Color(255, 218, 185)));
772                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("peru"), Color(205, 133, 63)));
773                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("pink"), Color(255, 192, 203)));
774                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("plum"), Color(221, 160, 221)));
775                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("powderblue"), Color(176, 224, 230)));
776                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("purple"), Color(128, 0, 128)));
777                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("red"), Color(255, 0, 0)));
778                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("rosybrown"), Color(188, 143, 143)));
779                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("royalblue"), Color( 65, 105, 225)));
780                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("saddlebrown"), Color(139, 69, 19)));
781                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("salmon"), Color(250, 128, 114)));
782                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("sandybrown"), Color(244, 164, 96)));
783                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("seagreen"), Color( 46, 139, 87)));
784                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("seashell"), Color(255, 245, 238)));
785                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("sienna"), Color(160, 82, 45)));
786                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("silver"), Color(192, 192, 192)));
787                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("skyblue"), Color(135, 206, 235)));
788                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slateblue"), Color(106, 90, 205)));
789                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slategray"), Color(112, 128, 144)));
790                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("slategrey"), Color(112, 128, 144)));
791                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("snow"), Color(255, 250, 250)));
792                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("springgreen"), Color( 0, 255, 127)));
793                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("steelblue"), Color( 70, 130, 180)));
794                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("tan"), Color(210, 180, 140)));
795                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("teal"), Color( 0, 128, 128)));
796                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("thistle"), Color(216, 191, 216)));
797                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("tomato"), Color(255, 99, 71)));
798                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("turquoise"), Color( 64, 224, 208)));
799                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("violet"), Color(238, 130, 238)));
800                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("wheat"), Color(245, 222, 179)));
801                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("white"), Color(255, 255, 255)));
802                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("whitesmoke"), Color(245, 245, 245)));
803                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("yellow"), Color(255, 255, 0)));
804                 aColorTokenMapperList.insert(ColorTokenValueType(rtl::OUString::createFromAscii("yellowgreen"), Color(154, 205, 50)));
805             }
806 
807             const ColorTokenMapper::const_iterator aResult(aColorTokenMapperList.find(rName));
808 
809             if(aResult == aColorTokenMapperList.end())
810             {
811                 return false;
812             }
813             else
814             {
815                 rColor = aResult->second.getBColor();
816                 return true;
817             }
818         }
819 
820         bool read_color(const rtl::OUString& rCandidate, basegfx::BColor& rColor)
821         {
822             const sal_Int32 nLen(rCandidate.getLength());
823 
824             if(nLen)
825             {
826                 const sal_Unicode aChar(rCandidate[0]);
827                 const double fFactor(1.0 / 255.0);
828 
829                 if(aChar == sal_Unicode('#'))
830                 {
831                     // hex definition
832                     rtl::OUStringBuffer aNum;
833                     sal_Int32 nPos(1);
834 
835                     copyHex(rCandidate, nPos, aNum, nLen);
836                     const sal_Int32 nLength(aNum.getLength());
837 
838                     if(3 == nLength)
839                     {
840                         const sal_Int32 nR(read_hex(aNum.charAt(0)));
841                         const sal_Int32 nG(read_hex(aNum.charAt(1)));
842                         const sal_Int32 nB(read_hex(aNum.charAt(2)));
843 
844                         rColor.setRed((nR | (nR << 4)) * fFactor);
845                         rColor.setGreen((nG | (nG << 4)) * fFactor);
846                         rColor.setBlue((nB | (nB << 4)) * fFactor);
847 
848                         return true;
849                     }
850                     else if(6 == nLength)
851                     {
852                         const sal_Int32 nR1(read_hex(aNum.charAt(0)));
853                         const sal_Int32 nR2(read_hex(aNum.charAt(1)));
854                         const sal_Int32 nG1(read_hex(aNum.charAt(2)));
855                         const sal_Int32 nG2(read_hex(aNum.charAt(3)));
856                         const sal_Int32 nB1(read_hex(aNum.charAt(4)));
857                         const sal_Int32 nB2(read_hex(aNum.charAt(5)));
858 
859                         rColor.setRed((nR2 | (nR1 << 4)) * fFactor);
860                         rColor.setGreen((nG2 | (nG1 << 4)) * fFactor);
861                         rColor.setBlue((nB2 | (nB1 << 4)) * fFactor);
862 
863                         return true;
864                     }
865                 }
866                 else
867                 {
868                     static rtl::OUString aStrRgb(rtl::OUString::createFromAscii("rgb"));
869 
870                     if(rCandidate.matchIgnoreAsciiCase(aStrRgb, 0))
871                     {
872                         // rgb definition
873                         sal_Int32 nPos(aStrRgb.getLength());
874                         skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
875                         double fR(0.0);
876 
877                         if(readNumber(rCandidate, nPos, fR, nLen))
878                         {
879                             skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
880 
881                             if(nPos < nLen)
882                             {
883                                 const sal_Unicode aPercentChar(rCandidate[nPos]);
884                                 const bool bIsPercent(sal_Unicode('%') == aPercentChar);
885                                 double fG(0.0);
886 
887                                 if(bIsPercent)
888                                 {
889                                     skip_char(rCandidate, sal_Unicode('%'), nPos, nLen);
890                                 }
891 
892                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
893 
894                                 if(readNumber(rCandidate, nPos, fG, nLen))
895                                 {
896                                     double fB(0.0);
897 
898                                     if(bIsPercent)
899                                     {
900                                         skip_char(rCandidate, sal_Unicode('%'), nPos, nLen);
901                                     }
902 
903                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
904 
905                                     if(readNumber(rCandidate, nPos, fB, nLen))
906                                     {
907                                         const double fFac(bIsPercent ? 0.01 : fFactor);
908 
909                                         rColor.setRed(fR * fFac);
910                                         rColor.setGreen(fG * fFac);
911                                         rColor.setBlue(fB * fFac);
912 
913                                         if(bIsPercent)
914                                         {
915                                             skip_char(rCandidate, sal_Unicode('%'), nPos, nLen);
916                                         }
917 
918                                         skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
919                                         return true;
920                                     }
921                                 }
922                             }
923                         }
924                     }
925                     else
926                     {
927                         // color keyword
928                         if(match_colorKeyword(rColor, rCandidate))
929                         {
930                             return true;
931                         }
932                     }
933                 }
934             }
935 
936             return false;
937         }
938 
939         basegfx::B2DRange readViewBox(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider)
940         {
941             const sal_Int32 nLen(rCandidate.getLength());
942 
943             if(nLen)
944             {
945                 sal_Int32 nPos(0);
946                 SvgNumber aMinX;
947                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
948 
949                 if(readNumberAndUnit(rCandidate, nPos, aMinX, nLen))
950                 {
951                     SvgNumber aMinY;
952                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
953 
954                     if(readNumberAndUnit(rCandidate, nPos, aMinY, nLen))
955                     {
956                         SvgNumber aWidth;
957                         skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
958 
959                         if(readNumberAndUnit(rCandidate, nPos, aWidth, nLen))
960                         {
961                             SvgNumber aHeight;
962                             skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
963 
964                             if(readNumberAndUnit(rCandidate, nPos, aHeight, nLen))
965                             {
966                                 double fX(aMinX.solve(rInfoProvider, xcoordinate));
967                                 double fY(aMinY.solve(rInfoProvider, ycoordinate));
968                                 double fW(aWidth.solve(rInfoProvider,xcoordinate));
969                                 double fH(aHeight.solve(rInfoProvider,ycoordinate));
970                                 return basegfx::B2DRange(fX,fY,fX+fW,fY+fH);
971                             }
972                         }
973                     }
974                 }
975             }
976 
977             return basegfx::B2DRange();
978         }
979 
980         basegfx::B2DHomMatrix readTransform(const rtl::OUString& rCandidate, InfoProvider& rInfoProvider)
981         {
982             basegfx::B2DHomMatrix aMatrix;
983             const sal_Int32 nLen(rCandidate.getLength());
984 
985             if(nLen)
986             {
987                 sal_Int32 nPos(0);
988                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
989 
990                 while(nPos < nLen)
991                 {
992                     const sal_Unicode aChar(rCandidate[nPos]);
993                     const sal_Int32 nInitPos(nPos);
994                     static rtl::OUString aStrMatrix(rtl::OUString::createFromAscii("matrix"));
995                     static rtl::OUString aStrTranslate(rtl::OUString::createFromAscii("translate"));
996                     static rtl::OUString aStrScale(rtl::OUString::createFromAscii("scale"));
997                     static rtl::OUString aStrRotate(rtl::OUString::createFromAscii("rotate"));
998                     static rtl::OUString aStrSkewX(rtl::OUString::createFromAscii("skewX"));
999                     static rtl::OUString aStrSkewY(rtl::OUString::createFromAscii("skewY"));
1000 
1001                     switch(aChar)
1002                     {
1003                         case sal_Unicode('m') :
1004                         {
1005                             if(rCandidate.match(aStrMatrix, nPos))
1006                             {
1007                                 // matrix element
1008                                 nPos += aStrMatrix.getLength();
1009                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
1010                                 SvgNumber aVal;
1011                                 basegfx::B2DHomMatrix aNew;
1012 
1013                                 if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
1014                                 {
1015                                     aNew.set(0, 0, aVal.solve(rInfoProvider)); // Element A
1016                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1017 
1018                                     if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
1019                                     {
1020                                         aNew.set(1, 0, aVal.solve(rInfoProvider)); // Element B
1021                                         skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1022 
1023                                         if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
1024                                         {
1025                                             aNew.set(0, 1, aVal.solve(rInfoProvider)); // Element C
1026                                             skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1027 
1028                                             if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
1029                                             {
1030                                                 aNew.set(1, 1, aVal.solve(rInfoProvider)); // Element D
1031                                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1032 
1033                                                 if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
1034                                                 {
1035                                                     aNew.set(0, 2, aVal.solve(rInfoProvider, xcoordinate)); // Element E
1036                                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1037 
1038                                                     if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
1039                                                     {
1040                                                         aNew.set(1, 2, aVal.solve(rInfoProvider, ycoordinate)); // Element F
1041                                                         skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
1042                                                         skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1043 
1044                                                         // caution: String is evaluated from left to right, but matrix multiplication
1045                                                         // in SVG is right to left, so put the new transformation before the current
1046                                                         // one by multiplicating from the right side
1047                                                         aMatrix = aMatrix * aNew;
1048                                                     }
1049                                                 }
1050                                             }
1051                                         }
1052                                     }
1053                                 }
1054                             }
1055                             break;
1056                         }
1057                         case sal_Unicode('t') :
1058                         {
1059                             if(rCandidate.match(aStrTranslate, nPos))
1060                             {
1061                                 // translate element
1062                                 nPos += aStrTranslate.getLength();
1063                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
1064                                 SvgNumber aTransX;
1065 
1066                                 if(readNumberAndUnit(rCandidate, nPos, aTransX, nLen))
1067                                 {
1068                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1069                                     SvgNumber aTransY;
1070                                     readNumberAndUnit(rCandidate, nPos, aTransY, nLen);
1071                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
1072                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1073 
1074                                     aMatrix = aMatrix * basegfx::tools::createTranslateB2DHomMatrix(
1075                                         aTransX.solve(rInfoProvider, xcoordinate),
1076                                         aTransY.solve(rInfoProvider, ycoordinate));
1077                                 }
1078                             }
1079                             break;
1080                         }
1081                         case sal_Unicode('s') :
1082                         {
1083                             if(rCandidate.match(aStrScale, nPos))
1084                             {
1085                                 // scale element
1086                                 nPos += aStrScale.getLength();
1087                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
1088                                 SvgNumber aScaleX;
1089 
1090                                 if(readNumberAndUnit(rCandidate, nPos, aScaleX, nLen))
1091                                 {
1092                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1093                                     SvgNumber aScaleY(aScaleX);
1094                                     readNumberAndUnit(rCandidate, nPos, aScaleY, nLen);
1095                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
1096                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1097 
1098                                     aMatrix = aMatrix * basegfx::tools::createScaleB2DHomMatrix(
1099                                         aScaleX.solve(rInfoProvider),
1100                                         aScaleY.solve(rInfoProvider));
1101                                 }
1102                             }
1103                             else if(rCandidate.match(aStrSkewX, nPos))
1104                             {
1105                                 // skewx element
1106                                 nPos += aStrSkewX.getLength();
1107                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
1108                                 double fSkewX(0.0);
1109 
1110                                 if(readAngle(rCandidate, nPos, fSkewX, nLen))
1111                                 {
1112                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
1113                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1114 
1115                                     aMatrix = aMatrix * basegfx::tools::createShearXB2DHomMatrix(tan(fSkewX));
1116                                 }
1117                             }
1118                             else if(rCandidate.match(aStrSkewY, nPos))
1119                             {
1120                                 // skewy element
1121                                 nPos += aStrSkewY.getLength();
1122                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
1123                                 double fSkewY(0.0);
1124 
1125                                 if(readAngle(rCandidate, nPos, fSkewY, nLen))
1126                                 {
1127                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
1128                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1129 
1130                                     aMatrix = aMatrix * basegfx::tools::createShearYB2DHomMatrix(tan(fSkewY));
1131                                 }
1132                             }
1133                             break;
1134                         }
1135                         case sal_Unicode('r') :
1136                         {
1137                             if(rCandidate.match(aStrRotate, nPos))
1138                             {
1139                                 // rotate element
1140                                 nPos += aStrRotate.getLength();
1141                                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode('('), nPos, nLen);
1142                                 double fAngle(0.0);
1143 
1144                                 if(readAngle(rCandidate, nPos, fAngle, nLen))
1145                                 {
1146                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1147                                     SvgNumber aX;
1148                                     readNumberAndUnit(rCandidate, nPos, aX, nLen);
1149                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1150                                     SvgNumber aY;
1151                                     readNumberAndUnit(rCandidate, nPos, aY, nLen);
1152                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(')'), nPos, nLen);
1153                                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1154 
1155                                     const double fX(aX.isSet() ? aX.solve(rInfoProvider, xcoordinate) : 0.0);
1156                                     const double fY(aY.isSet() ? aY.solve(rInfoProvider, ycoordinate) : 0.0);
1157 
1158                                     if(!basegfx::fTools::equalZero(fX) || !basegfx::fTools::equalZero(fY))
1159                                     {
1160                                         // rotate around point
1161                                         aMatrix = aMatrix * basegfx::tools::createRotateAroundPoint(fX, fY, fAngle);
1162                                     }
1163                                     else
1164                                     {
1165                                         // rotate
1166                                         aMatrix = aMatrix * basegfx::tools::createRotateB2DHomMatrix(fAngle);
1167                                     }
1168                                 }
1169                             }
1170                             break;
1171                         }
1172                     }
1173 
1174                     if(nInitPos == nPos)
1175                     {
1176                         OSL_ENSURE(false, "Could not interpret on current position (!)");
1177                         nPos++;
1178                     }
1179                 }
1180             }
1181 
1182             return aMatrix;
1183         }
1184 
1185         bool readSingleNumber(const rtl::OUString& rCandidate, SvgNumber& aNum)
1186         {
1187             const sal_Int32 nLen(rCandidate.getLength());
1188             sal_Int32 nPos(0);
1189 
1190             return readNumberAndUnit(rCandidate, nPos, aNum, nLen);
1191         }
1192 
1193         bool readLocalUrl(const rtl::OUString& rCandidate, rtl::OUString& rURL)
1194         {
1195             static rtl::OUString aStrUrl(rtl::OUString::createFromAscii("url"));
1196 
1197             if(rCandidate.match(aStrUrl, 0))
1198             {
1199                 const sal_Int32 nLen(rCandidate.getLength());
1200                 sal_Int32 nPos(aStrUrl.getLength());
1201 
1202                 skip_char(rCandidate, sal_Unicode('('), sal_Unicode('#'), nPos, nLen);
1203                 rtl::OUStringBuffer aTokenValue;
1204                 copyToLimiter(rCandidate, sal_Unicode(')'), nPos, aTokenValue, nLen);
1205                 rURL = aTokenValue.makeStringAndClear();
1206 
1207                 return true;
1208             }
1209 
1210             return false;
1211         }
1212 
1213         bool readSvgPaint(const rtl::OUString& rCandidate, SvgPaint& rSvgPaint, rtl::OUString& rURL)
1214         {
1215             const sal_Int32 nLen(rCandidate.getLength());
1216 
1217             if(nLen)
1218             {
1219                 basegfx::BColor aColor;
1220 
1221                 if(read_color(rCandidate, aColor))
1222                 {
1223                     rSvgPaint = SvgPaint(aColor, true, true);
1224                     return true;
1225                 }
1226                 else
1227                 {
1228                     static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
1229                     static rtl::OUString aStrCurrentColor(rtl::OUString::createFromAscii("currentColor"));
1230 
1231                     if(rCandidate.match(aStrNone, 0))
1232                     {
1233                         rSvgPaint = SvgPaint(aColor, true, false, false);
1234                         return true;
1235                     }
1236                     else if(readLocalUrl(rCandidate, rURL))
1237                     {
1238                         /// Url is copied to rURL, but needs to be solved outside this helper
1239                         return false;
1240                     }
1241                     else if(rCandidate.match(aStrCurrentColor, 0))
1242                     {
1243                         rSvgPaint = SvgPaint(aColor, true, true, true);
1244                         return true;
1245                     }
1246                 }
1247             }
1248 
1249             return false;
1250         }
1251 
1252         bool readSvgNumberVector(const rtl::OUString& rCandidate, SvgNumberVector& rSvgNumberVector)
1253         {
1254             const sal_Int32 nLen(rCandidate.getLength());
1255             rSvgNumberVector.clear();
1256 
1257             if(nLen)
1258             {
1259                 sal_Int32 nPos(0);
1260                 SvgNumber aNum;
1261                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1262 
1263                 while(readNumberAndUnit(rCandidate, nPos, aNum, nLen))
1264                 {
1265                     rSvgNumberVector.push_back(aNum);
1266                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1267                 }
1268 
1269                 return !rSvgNumberVector.empty();
1270             }
1271 
1272             return false;
1273         }
1274 
1275         SvgAspectRatio readSvgAspectRatio(const rtl::OUString& rCandidate)
1276         {
1277             const sal_Int32 nLen(rCandidate.getLength());
1278 
1279             if(nLen)
1280             {
1281                 sal_Int32 nPos(0);
1282                 SvgAlign aSvgAlign(Align_xMidYMid);
1283                 bool bDefer(false);
1284                 bool bMeetOrSlice(true);
1285                 bool bChanged(false);
1286 
1287                 while(nPos < nLen)
1288                 {
1289                     const sal_Int32 nInitPos(nPos);
1290                     skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
1291                     rtl::OUStringBuffer aTokenName;
1292                     copyString(rCandidate, nPos, aTokenName, nLen);
1293 
1294                     if(aTokenName.getLength())
1295                     {
1296                         switch(StrToSVGToken(aTokenName.makeStringAndClear()))
1297                         {
1298                             case SVGTokenDefer:
1299                             {
1300                                 bDefer = true;
1301                                 bChanged = true;
1302                                 break;
1303                             }
1304                             case SVGTokenNone:
1305                             {
1306                                 aSvgAlign = Align_none;
1307                                 bChanged = true;
1308                                 break;
1309                             }
1310                             case SVGTokenXMinYMin:
1311                             {
1312                                 aSvgAlign = Align_xMinYMin;
1313                                 bChanged = true;
1314                                 break;
1315                             }
1316                             case SVGTokenXMidYMin:
1317                             {
1318                                 aSvgAlign = Align_xMidYMin;
1319                                 bChanged = true;
1320                                 break;
1321                             }
1322                             case SVGTokenXMaxYMin:
1323                             {
1324                                 aSvgAlign = Align_xMaxYMin;
1325                                 bChanged = true;
1326                                 break;
1327                             }
1328                             case SVGTokenXMinYMid:
1329                             {
1330                                 aSvgAlign = Align_xMinYMid;
1331                                 bChanged = true;
1332                                 break;
1333                             }
1334                             case SVGTokenXMidYMid:
1335                             {
1336                                 aSvgAlign = Align_xMidYMid;
1337                                 bChanged = true;
1338                                 break;
1339                             }
1340                             case SVGTokenXMaxYMid:
1341                             {
1342                                 aSvgAlign = Align_xMaxYMid;
1343                                 bChanged = true;
1344                                 break;
1345                             }
1346                             case SVGTokenXMinYMax:
1347                             {
1348                                 aSvgAlign = Align_xMinYMax;
1349                                 bChanged = true;
1350                                 break;
1351                             }
1352                             case SVGTokenXMidYMax:
1353                             {
1354                                 aSvgAlign = Align_xMidYMax;
1355                                 bChanged = true;
1356                                 break;
1357                             }
1358                             case SVGTokenXMaxYMax:
1359                             {
1360                                 aSvgAlign = Align_xMaxYMax;
1361                                 bChanged = true;
1362                                 break;
1363                             }
1364                             case SVGTokenMeet:
1365                             {
1366                                 bMeetOrSlice = true;
1367                                 bChanged = true;
1368                                 break;
1369                             }
1370                             case SVGTokenSlice:
1371                             {
1372                                 bMeetOrSlice = false;
1373                                 bChanged = true;
1374                                 break;
1375                             }
1376                             default:
1377                             {
1378                                 break;
1379                             }
1380                         }
1381                     }
1382 
1383                     if(nInitPos == nPos)
1384                     {
1385                         OSL_ENSURE(false, "Could not interpret on current position (!)");
1386                         nPos++;
1387                     }
1388                 }
1389 
1390                 if(bChanged)
1391                 {
1392                     return SvgAspectRatio(aSvgAlign, bDefer, bMeetOrSlice);
1393                 }
1394             }
1395 
1396             return SvgAspectRatio();
1397         }
1398 
1399         bool readSvgStringVector(const rtl::OUString& rCandidate, SvgStringVector& rSvgStringVector)
1400         {
1401             rSvgStringVector.clear();
1402             const sal_Int32 nLen(rCandidate.getLength());
1403 
1404             if(nLen)
1405             {
1406                 sal_Int32 nPos(0);
1407                 rtl::OUStringBuffer aTokenValue;
1408                 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1409 
1410                 while(nPos < nLen)
1411                 {
1412                     copyToLimiter(rCandidate, sal_Unicode(','), nPos, aTokenValue, nLen);
1413                     skip_char(rCandidate, sal_Unicode(','), sal_Unicode(' '), nPos, nLen);
1414                     const rtl::OUString aString = aTokenValue.makeStringAndClear();
1415 
1416                     if(aString.getLength())
1417                     {
1418                         rSvgStringVector.push_back(aString);
1419                     }
1420                 }
1421             }
1422 
1423             return !rSvgStringVector.empty();
1424         }
1425 
1426         void readImageLink(const rtl::OUString& rCandidate, rtl::OUString& rXLink, rtl::OUString& rUrl, rtl::OUString& rMimeType, rtl::OUString& rData)
1427         {
1428             rXLink = rUrl = rMimeType = rData = rtl::OUString();
1429 
1430             if(sal_Unicode('#') == rCandidate[0])
1431             {
1432                 // local link
1433                 rXLink = rCandidate.copy(1);
1434             }
1435             else
1436             {
1437                 static rtl::OUString aStrData(rtl::OUString::createFromAscii("data:"));
1438 
1439                 if(rCandidate.match(aStrData, 0))
1440                 {
1441                     // embedded data
1442                     sal_Int32 nPos(aStrData.getLength());
1443                     sal_Int32 nLen(rCandidate.getLength());
1444                     rtl::OUStringBuffer aBuffer;
1445 
1446                     // read mime type
1447                     skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
1448                     copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aBuffer, nLen);
1449                     skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen);
1450                     rMimeType = aBuffer.makeStringAndClear();
1451 
1452                     if(rMimeType.getLength() && nPos < nLen)
1453                     {
1454                         static rtl::OUString aStrImage(rtl::OUString::createFromAscii("image"));
1455 
1456                         if(rMimeType.match(aStrImage, 0))
1457                         {
1458                             // image data
1459                             rtl::OUString aData(rCandidate.copy(nPos));
1460                             static rtl::OUString aStrBase64(rtl::OUString::createFromAscii("base64"));
1461 
1462                             if(aData.match(aStrBase64, 0))
1463                             {
1464                                 // base64 encoded
1465                                 nPos = aStrBase64.getLength();
1466                                 nLen = aData.getLength();
1467 
1468                                 skip_char(aData, sal_Unicode(' '), sal_Unicode(','), nPos, nLen);
1469 
1470                                 if(nPos < nLen)
1471                                 {
1472                                     rData = aData.copy(nPos);
1473                                 }
1474                             }
1475                         }
1476                     }
1477                 }
1478                 else
1479                 {
1480                     // Url (path and filename)
1481                     rUrl = rCandidate;
1482                 }
1483             }
1484         }
1485 
1486         rtl::OUString convert(const rtl::OUString& rCandidate, const sal_Unicode& rPattern, const sal_Unicode& rNew, bool bRemove)
1487         {
1488             const sal_Int32 nLen(rCandidate.getLength());
1489 
1490             if(nLen)
1491             {
1492                 sal_Int32 nPos(0);
1493                 rtl::OUStringBuffer aBuffer;
1494                 bool bChanged(false);
1495 
1496                 while(nPos < nLen)
1497                 {
1498                     const sal_Unicode aChar(rCandidate[nPos]);
1499 
1500                     if(rPattern == aChar)
1501                     {
1502                         bChanged = true;
1503 
1504                         if(!bRemove)
1505                         {
1506                             aBuffer.append(rNew);
1507                         }
1508                     }
1509                     else
1510                     {
1511                         aBuffer.append(aChar);
1512                     }
1513 
1514                     nPos++;
1515                 }
1516 
1517                 if(bChanged)
1518                 {
1519                     return aBuffer.makeStringAndClear();
1520                 }
1521             }
1522 
1523             return rCandidate;
1524         }
1525 
1526         rtl::OUString consolidateContiguosSpace(const rtl::OUString& rCandidate)
1527         {
1528             const sal_Int32 nLen(rCandidate.getLength());
1529 
1530             if(nLen)
1531             {
1532                 sal_Int32 nPos(0);
1533                 rtl::OUStringBuffer aBuffer;
1534                 bool bInsideSpace(false);
1535                 const sal_Unicode aSpace(' ');
1536 
1537                 while(nPos < nLen)
1538                 {
1539                     const sal_Unicode aChar(rCandidate[nPos]);
1540 
1541                     if(aSpace == aChar)
1542                     {
1543                         bInsideSpace = true;
1544                     }
1545                     else
1546                     {
1547                         if(bInsideSpace)
1548                         {
1549                             bInsideSpace = false;
1550                             aBuffer.append(aSpace);
1551                         }
1552 
1553                         aBuffer.append(aChar);
1554                     }
1555 
1556                     nPos++;
1557                 }
1558 
1559                 if(bInsideSpace)
1560                 {
1561                     aBuffer.append(aSpace);
1562                 }
1563 
1564                 if(aBuffer.getLength() != nLen)
1565                 {
1566                     return aBuffer.makeStringAndClear();
1567                 }
1568             }
1569 
1570             return rCandidate;
1571         }
1572 
1573         rtl::OUString whiteSpaceHandlingDefault(const rtl::OUString& rCandidate)
1574         {
1575             const sal_Unicode aNewline('\n');
1576             const sal_Unicode aTab('\t');
1577             const sal_Unicode aSpace(' ');
1578 
1579             // remove all newline characters
1580             rtl::OUString aRetval(convert(rCandidate, aNewline, aNewline, true));
1581 
1582             // convert tab to space
1583             aRetval = convert(aRetval, aTab, aSpace, false);
1584 
1585             // strip of all leading and trailing spaces
1586             aRetval = aRetval.trim();
1587 
1588             // consolidate contiguos space
1589             aRetval = consolidateContiguosSpace(aRetval);
1590 
1591             return aRetval;
1592         }
1593 
1594         rtl::OUString whiteSpaceHandlingPreserve(const rtl::OUString& rCandidate)
1595         {
1596             const sal_Unicode aNewline('\n');
1597             const sal_Unicode aTab('\t');
1598             const sal_Unicode aSpace(' ');
1599 
1600             // convert newline to space
1601             rtl::OUString aRetval(convert(rCandidate, aNewline, aSpace, false));
1602 
1603             // convert tab to space
1604             aRetval = convert(rCandidate, aTab, aSpace, false);
1605 
1606             return rCandidate;
1607         }
1608 
1609         ::std::vector< double > solveSvgNumberVector(const SvgNumberVector& rInput, const InfoProvider& rInfoProvider, NumberType aNumberType)
1610         {
1611             ::std::vector< double > aRetval;
1612 
1613             if(!rInput.empty())
1614             {
1615                 const double nCount(rInput.size());
1616                 aRetval.reserve(nCount);
1617 
1618                 for(sal_uInt32 a(0); a < nCount; a++)
1619                 {
1620                     aRetval.push_back(rInput[a].solve(rInfoProvider, aNumberType));
1621                 }
1622             }
1623 
1624             return aRetval;
1625         }
1626 
1627     } // end of namespace svgreader
1628 } // end of namespace svgio
1629 
1630 //////////////////////////////////////////////////////////////////////////////
1631 // eof
1632