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