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