Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / svgio / source / svgreader / svgstyleattributes.cxx
blob07845df8c931a7a44f6254eea73f263f28c29798
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svgio/svgreader/svgstyleattributes.hxx>
21 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
22 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
23 #include <svgio/svgreader/svgnode.hxx>
24 #include <svgio/svgreader/svgdocument.hxx>
25 #include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
26 #include <svgio/svgreader/svggradientnode.hxx>
27 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
28 #include <basegfx/vector/b2enums.hxx>
29 #include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
30 #include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
31 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
32 #include <svgio/svgreader/svgclippathnode.hxx>
33 #include <svgio/svgreader/svgmasknode.hxx>
34 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
35 #include <basegfx/polygon/b2dpolypolygontools.hxx>
36 #include <svgio/svgreader/svgmarkernode.hxx>
37 #include <basegfx/curve/b2dcubicbezier.hxx>
38 #include <svgio/svgreader/svgpatternnode.hxx>
39 #include <drawinglayer/primitive2d/patternfillprimitive2d.hxx>
40 #include <basegfx/polygon/b2dpolygontools.hxx>
41 #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
43 //////////////////////////////////////////////////////////////////////////////
45 namespace svgio
47 namespace svgreader
49 basegfx::B2DLineJoin StrokeLinejoinToB2DLineJoin(StrokeLinejoin aStrokeLinejoin)
51 if(StrokeLinejoin_round == aStrokeLinejoin)
53 return basegfx::B2DLINEJOIN_ROUND;
55 else if(StrokeLinejoin_bevel == aStrokeLinejoin)
57 return basegfx::B2DLINEJOIN_BEVEL;
60 return basegfx::B2DLINEJOIN_MITER;
63 com::sun::star::drawing::LineCap StrokeLinecapToDrawingLineCap(StrokeLinecap aStrokeLinecap)
65 switch(aStrokeLinecap)
67 default: /* StrokeLinecap_notset, StrokeLinecap_butt */
69 return com::sun::star::drawing::LineCap_BUTT;
70 break;
72 case StrokeLinecap_round:
74 return com::sun::star::drawing::LineCap_ROUND;
75 break;
77 case StrokeLinecap_square:
79 return com::sun::star::drawing::LineCap_SQUARE;
80 break;
85 FontStretch getWider(FontStretch aSource)
87 switch(aSource)
89 case FontStretch_ultra_condensed: aSource = FontStretch_extra_condensed; break;
90 case FontStretch_extra_condensed: aSource = FontStretch_condensed; break;
91 case FontStretch_condensed: aSource = FontStretch_semi_condensed; break;
92 case FontStretch_semi_condensed: aSource = FontStretch_normal; break;
93 case FontStretch_normal: aSource = FontStretch_semi_expanded; break;
94 case FontStretch_semi_expanded: aSource = FontStretch_expanded; break;
95 case FontStretch_expanded: aSource = FontStretch_extra_expanded; break;
96 case FontStretch_extra_expanded: aSource = FontStretch_ultra_expanded; break;
97 default: break;
100 return aSource;
103 FontStretch getNarrower(FontStretch aSource)
105 switch(aSource)
107 case FontStretch_extra_condensed: aSource = FontStretch_ultra_condensed; break;
108 case FontStretch_condensed: aSource = FontStretch_extra_condensed; break;
109 case FontStretch_semi_condensed: aSource = FontStretch_condensed; break;
110 case FontStretch_normal: aSource = FontStretch_semi_condensed; break;
111 case FontStretch_semi_expanded: aSource = FontStretch_normal; break;
112 case FontStretch_expanded: aSource = FontStretch_semi_expanded; break;
113 case FontStretch_extra_expanded: aSource = FontStretch_expanded; break;
114 case FontStretch_ultra_expanded: aSource = FontStretch_extra_expanded; break;
115 default: break;
118 return aSource;
121 FontWeight getBolder(FontWeight aSource)
123 switch(aSource)
125 case FontWeight_100: aSource = FontWeight_200; break;
126 case FontWeight_200: aSource = FontWeight_300; break;
127 case FontWeight_300: aSource = FontWeight_400; break;
128 case FontWeight_400: aSource = FontWeight_500; break;
129 case FontWeight_500: aSource = FontWeight_600; break;
130 case FontWeight_600: aSource = FontWeight_700; break;
131 case FontWeight_700: aSource = FontWeight_800; break;
132 case FontWeight_800: aSource = FontWeight_900; break;
133 default: break;
136 return aSource;
139 FontWeight getLighter(FontWeight aSource)
141 switch(aSource)
143 case FontWeight_200: aSource = FontWeight_100; break;
144 case FontWeight_300: aSource = FontWeight_200; break;
145 case FontWeight_400: aSource = FontWeight_300; break;
146 case FontWeight_500: aSource = FontWeight_400; break;
147 case FontWeight_600: aSource = FontWeight_500; break;
148 case FontWeight_700: aSource = FontWeight_600; break;
149 case FontWeight_800: aSource = FontWeight_700; break;
150 case FontWeight_900: aSource = FontWeight_800; break;
151 default: break;
154 return aSource;
157 ::FontWeight getVclFontWeight(FontWeight aSource)
159 ::FontWeight nRetval(WEIGHT_NORMAL);
161 switch(aSource)
163 case FontWeight_100: nRetval = WEIGHT_ULTRALIGHT; break;
164 case FontWeight_200: nRetval = WEIGHT_LIGHT; break;
165 case FontWeight_300: nRetval = WEIGHT_SEMILIGHT; break;
166 case FontWeight_400: nRetval = WEIGHT_NORMAL; break;
167 case FontWeight_500: nRetval = WEIGHT_MEDIUM; break;
168 case FontWeight_600: nRetval = WEIGHT_SEMIBOLD; break;
169 case FontWeight_700: nRetval = WEIGHT_BOLD; break;
170 case FontWeight_800: nRetval = WEIGHT_ULTRABOLD; break;
171 case FontWeight_900: nRetval = WEIGHT_BLACK; break;
172 default: break;
175 return nRetval;
178 void SvgStyleAttributes::readStyle(const rtl::OUString& rCandidate)
180 const sal_Int32 nLen(rCandidate.getLength());
181 sal_Int32 nPos(0);
183 while(nPos < nLen)
185 const sal_Int32 nInitPos(nPos);
186 skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
187 rtl::OUStringBuffer aTokenName;
188 copyString(rCandidate, nPos, aTokenName, nLen);
190 if(aTokenName.getLength())
192 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(':'), nPos, nLen);
193 rtl::OUStringBuffer aTokenValue;
194 copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aTokenValue, nLen);
195 skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen);
196 const rtl::OUString aOUTokenName(aTokenName.makeStringAndClear());
197 const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
199 parseStyleAttribute(aOUTokenName, StrToSVGToken(aOUTokenName), aOUTokenValue);
202 if(nInitPos == nPos)
204 OSL_ENSURE(false, "Could not interpret on current position (!)");
205 nPos++;
210 void SvgStyleAttributes::checkForCssStyle(const rtl::OUString& rClassStr) const
212 if(!mpCssStyleParent)
214 const SvgDocument& rDocument = mrOwner.getDocument();
215 const SvgStyleAttributes* pNew = 0;
217 if(rDocument.hasSvgStyleAttributesById())
219 if(mrOwner.getClass())
221 rtl::OUString aId(rtl::OUString::createFromAscii("."));
222 aId = aId + *mrOwner.getClass();
223 pNew = rDocument.findSvgStyleAttributesById(aId);
225 if(!pNew && rClassStr.getLength())
227 aId = rClassStr + aId;
229 pNew = rDocument.findSvgStyleAttributesById(aId);
233 if(!pNew && mrOwner.getId())
235 pNew = rDocument.findSvgStyleAttributesById(*mrOwner.getId());
238 if(!pNew && rClassStr.getLength())
240 pNew = rDocument.findSvgStyleAttributesById(rClassStr);
243 if(pNew)
245 // found css style, set as parent
246 const_cast< SvgStyleAttributes* >(this)->mpCssStyleParent = pNew;
252 const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const
254 if(mpCssStyleParent)
256 return mpCssStyleParent;
259 if(mrOwner.getParent())
261 return mrOwner.getParent()->getSvgStyleAttributes();
264 return 0;
267 void SvgStyleAttributes::add_text(
268 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
269 drawinglayer::primitive2d::Primitive2DSequence& rSource) const
271 if(rSource.hasElements())
273 // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D
274 // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill())
275 // set. When another fill is used and also evtl. stroke is set it gets necessary to
276 // dismantle to geometry and add needed primitives
277 const basegfx::BColor* pFill = getFill();
278 const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
279 const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
280 const basegfx::BColor* pStroke = getStroke();
281 const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
282 const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
283 basegfx::B2DPolyPolygon aMergedArea;
285 if(pFillGradient || pFillPattern || pStroke || pStrokeGradient || pStrokePattern)
287 // text geometry is needed, create
288 // use neutral ViewInformation and create LineGeometryExtractor2D
289 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
290 drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
292 // proccess
293 aExtractor.process(rSource);
295 // get results
296 const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
297 const sal_uInt32 nResultCount(rResult.size());
298 basegfx::B2DPolyPolygonVector aTextFillVector;
299 aTextFillVector.reserve(nResultCount);
301 for(sal_uInt32 a(0); a < nResultCount; a++)
303 const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
305 if(rCandidate.getIsFilled())
307 aTextFillVector.push_back(rCandidate.getB2DPolyPolygon());
311 if(!aTextFillVector.empty())
313 aMergedArea = basegfx::tools::mergeToSinglePolyPolygon(aTextFillVector);
317 const bool bStrokeUsed(pStroke || pStrokeGradient || pStrokePattern);
319 // add fill. Use geometry even for simple color fill when stroke
320 // is used, else text rendering and the geometry-based stroke will
321 // normally not really match optically due to divrese system text
322 // renderers
323 if(aMergedArea.count() && (pFillGradient || pFillPattern || bStrokeUsed))
325 // create text fill content based on geometry
326 add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange());
328 else if(pFill)
330 // add the already prepared primitives for single color fill
331 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, rSource);
334 // add stroke
335 if(aMergedArea.count() && bStrokeUsed)
337 // create text stroke content
338 add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange());
343 void SvgStyleAttributes::add_fillGradient(
344 const basegfx::B2DPolyPolygon& rPath,
345 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
346 const SvgGradientNode& rFillGradient,
347 const basegfx::B2DRange& rGeoRange) const
349 // create fill content
350 drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector;
352 // get the color stops
353 rFillGradient.collectGradientEntries(aSvgGradientEntryVector);
355 if(!aSvgGradientEntryVector.empty())
357 basegfx::B2DHomMatrix aGeoToUnit;
359 if(rFillGradient.getGradientTransform())
361 aGeoToUnit = *rFillGradient.getGradientTransform();
364 if(userSpaceOnUse == rFillGradient.getGradientUnits())
366 aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY());
367 aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight());
370 if(SVGTokenLinearGradient == rFillGradient.getType())
372 basegfx::B2DPoint aStart(0.0, 0.0);
373 basegfx::B2DPoint aEnd(1.0, 0.0);
375 if(userSpaceOnUse == rFillGradient.getGradientUnits())
377 // all possible units
378 aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate));
379 aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate));
380 aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate));
381 aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate));
383 else
385 // fractions or percent relative to object bounds
386 const SvgNumber X1(rFillGradient.getX1());
387 const SvgNumber Y1(rFillGradient.getY1());
388 const SvgNumber X2(rFillGradient.getX2());
389 const SvgNumber Y2(rFillGradient.getY2());
391 aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber());
392 aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber());
393 aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber());
394 aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber());
397 if(!aGeoToUnit.isIdentity())
399 aStart *= aGeoToUnit;
400 aEnd *= aGeoToUnit;
403 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
404 rTarget,
405 new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
406 rPath,
407 aSvgGradientEntryVector,
408 aStart,
409 aEnd,
410 rFillGradient.getSpreadMethod()));
412 else
414 basegfx::B2DPoint aStart(0.5, 0.5);
415 basegfx::B2DPoint aFocal;
416 double fRadius(0.5);
417 const SvgNumber* pFx = rFillGradient.getFx();
418 const SvgNumber* pFy = rFillGradient.getFy();
419 const bool bFocal(pFx || pFy);
421 if(userSpaceOnUse == rFillGradient.getGradientUnits())
423 // all possible units
424 aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate));
425 aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate));
426 fRadius = rFillGradient.getR().solve(mrOwner, length);
428 if(bFocal)
430 aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX());
431 aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY());
434 else
436 // fractions or percent relative to object bounds
437 const SvgNumber Cx(rFillGradient.getCx());
438 const SvgNumber Cy(rFillGradient.getCy());
439 const SvgNumber R(rFillGradient.getR());
441 aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber());
442 aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber());
443 fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber();
445 if(bFocal)
447 aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX());
448 aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY());
452 if(!aGeoToUnit.isIdentity())
454 aStart *= aGeoToUnit;
455 fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength();
457 if(bFocal)
459 aFocal *= aGeoToUnit;
463 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
464 rTarget,
465 new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
466 rPath,
467 aSvgGradientEntryVector,
468 aStart,
469 fRadius,
470 rFillGradient.getSpreadMethod(),
471 bFocal ? &aFocal : 0));
476 void SvgStyleAttributes::add_fillPatternTransform(
477 const basegfx::B2DPolyPolygon& rPath,
478 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
479 const SvgPatternNode& rFillPattern,
480 const basegfx::B2DRange& rGeoRange) const
482 // prepare fill polyPolygon with given pattern, check for patternTransform
483 if(rFillPattern.getPatternTransform() && !rFillPattern.getPatternTransform()->isIdentity())
485 // PatternTransform is active; Handle by filling the inverse transformed
486 // path and back-transforming the result
487 basegfx::B2DPolyPolygon aPath(rPath);
488 basegfx::B2DHomMatrix aInv(*rFillPattern.getPatternTransform());
489 drawinglayer::primitive2d::Primitive2DSequence aNewTarget;
491 aInv.invert();
492 aPath.transform(aInv);
493 add_fillPattern(aPath, aNewTarget, rFillPattern, aPath.getB2DRange());
495 if(aNewTarget.hasElements())
497 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
498 rTarget,
499 new drawinglayer::primitive2d::TransformPrimitive2D(
500 *rFillPattern.getPatternTransform(),
501 aNewTarget));
504 else
506 // no patternTransform, create fillPattern directly
507 add_fillPattern(rPath, rTarget, rFillPattern, rGeoRange);
511 void SvgStyleAttributes::add_fillPattern(
512 const basegfx::B2DPolyPolygon& rPath,
513 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
514 const SvgPatternNode& rFillPattern,
515 const basegfx::B2DRange& rGeoRange) const
517 // fill polyPolygon with given pattern
518 const drawinglayer::primitive2d::Primitive2DSequence& rPrimitives = rFillPattern.getPatternPrimitives();
520 if(rPrimitives.hasElements())
522 double fTargetWidth(rGeoRange.getWidth());
523 double fTargetHeight(rGeoRange.getHeight());
525 if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
527 // get relative values from pattern
528 double fX(0.0);
529 double fY(0.0);
530 double fW(0.0);
531 double fH(0.0);
533 rFillPattern.getValuesRelative(fX, fY, fW, fH, rGeoRange, mrOwner);
535 if(fW > 0.0 && fH > 0.0)
537 // build the reference range relative to the rGeoRange
538 const basegfx::B2DRange aReferenceRange(fX, fY, fX + fW, fY + fH);
540 // find out how the content is mapped to the reference range
541 basegfx::B2DHomMatrix aMapPrimitivesToUnitRange;
542 const basegfx::B2DRange* pViewBox = rFillPattern.getViewBox();
544 if(pViewBox)
546 // use viewBox/preserveAspectRatio
547 const SvgAspectRatio& rRatio = rFillPattern.getSvgAspectRatio();
548 const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
550 if(rRatio.isSet())
552 // let mapping be created from SvgAspectRatio
553 aMapPrimitivesToUnitRange = rRatio.createMapping(aUnitRange, *pViewBox);
555 else
557 // choose default mapping
558 aMapPrimitivesToUnitRange = rRatio.createLinearMapping(aUnitRange, *pViewBox);
561 else
563 // use patternContentUnits
564 const SvgUnits aPatternContentUnits(rFillPattern.getPatternContentUnits() ? *rFillPattern.getPatternContentUnits() : userSpaceOnUse);
566 if(userSpaceOnUse == aPatternContentUnits)
568 // create relative mapping to unit coordinates
569 aMapPrimitivesToUnitRange.scale(1.0 / (fW * fTargetWidth), 1.0 / (fH * fTargetHeight));
571 else
573 aMapPrimitivesToUnitRange.scale(1.0 / fW, 1.0 / fH);
577 // apply aMapPrimitivesToUnitRange to content when used
578 drawinglayer::primitive2d::Primitive2DSequence aPrimitives(rPrimitives);
580 if(!aMapPrimitivesToUnitRange.isIdentity())
582 const drawinglayer::primitive2d::Primitive2DReference xRef(
583 new drawinglayer::primitive2d::TransformPrimitive2D(
584 aMapPrimitivesToUnitRange,
585 aPrimitives));
587 aPrimitives = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
590 // embed in PatternFillPrimitive2D
591 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
592 rTarget,
593 new drawinglayer::primitive2d::PatternFillPrimitive2D(
594 rPath,
595 aPrimitives,
596 aReferenceRange));
602 void SvgStyleAttributes::add_fill(
603 const basegfx::B2DPolyPolygon& rPath,
604 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
605 const basegfx::B2DRange& rGeoRange) const
607 const basegfx::BColor* pFill = getFill();
608 const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
609 const SvgPatternNode* pFillPattern = getSvgPatternNodeFill();
611 if(pFill || pFillGradient || pFillPattern)
613 const double fFillOpacity(getFillOpacity().solve(mrOwner, length));
615 if(basegfx::fTools::more(fFillOpacity, 0.0))
617 drawinglayer::primitive2d::Primitive2DSequence aNewFill;
619 if(pFillGradient)
621 // create fill content with SVG gradient primitive
622 add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange);
624 else if(pFillPattern)
626 // create fill content with SVG pattern primitive
627 add_fillPatternTransform(rPath, aNewFill, *pFillPattern, rGeoRange);
629 else // if(pFill)
631 // create fill content
632 aNewFill.realloc(1);
633 aNewFill[0] = new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
634 rPath,
635 *pFill);
638 if(aNewFill.hasElements())
640 if(basegfx::fTools::less(fFillOpacity, 1.0))
642 // embed in UnifiedTransparencePrimitive2D
643 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
644 rTarget,
645 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
646 aNewFill,
647 1.0 - fFillOpacity));
649 else
651 // append
652 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewFill);
659 void SvgStyleAttributes::add_stroke(
660 const basegfx::B2DPolyPolygon& rPath,
661 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
662 const basegfx::B2DRange& rGeoRange) const
664 const basegfx::BColor* pStroke = getStroke();
665 const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
666 const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke();
668 if(pStroke || pStrokeGradient || pStrokePattern)
670 drawinglayer::primitive2d::Primitive2DSequence aNewStroke;
671 const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner, length));
673 if(basegfx::fTools::more(fStrokeOpacity, 0.0))
675 // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all
676 const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
678 if(basegfx::fTools::more(fStrokeWidth, 0.0))
680 // get LineJoin, LineCap and stroke array
681 const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin()));
682 const com::sun::star::drawing::LineCap aLineCap(StrokeLinecapToDrawingLineCap(getStrokeLinecap()));
683 ::std::vector< double > aDashArray;
685 if(!getStrokeDasharray().empty())
687 aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner, length);
690 // todo: Handle getStrokeDashOffset()
692 // prepare line attribute
693 drawinglayer::primitive2d::Primitive2DReference aNewLinePrimitive;
694 const drawinglayer::attribute::LineAttribute aLineAttribute(
695 pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0),
696 fStrokeWidth,
697 aB2DLineJoin,
698 aLineCap);
700 if(aDashArray.empty())
702 aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
703 rPath,
704 aLineAttribute);
706 else
708 const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray);
710 aNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
711 rPath,
712 aLineAttribute,
713 aStrokeAttribute);
716 if(pStrokeGradient || pStrokePattern)
718 // put primitive into Primitive2DReference and Primitive2DSequence
719 const drawinglayer::primitive2d::Primitive2DSequence aSeq(&aNewLinePrimitive, 1);
721 // use neutral ViewInformation and create LineGeometryExtractor2D
722 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
723 drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
725 // proccess
726 aExtractor.process(aSeq);
728 // check for fill rsults
729 const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills());
731 if(!rLineFillVector.empty())
733 const basegfx::B2DPolyPolygon aMergedArea(
734 basegfx::tools::mergeToSinglePolyPolygon(
735 rLineFillVector));
737 if(aMergedArea.count())
739 if(pStrokeGradient)
741 // create fill content with SVG gradient primitive. Use original GeoRange,
742 // e.g. from circle without LineWidth
743 add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange);
745 else // if(pStrokePattern)
747 // create fill content with SVG pattern primitive. Use GeoRange
748 // from the expanded data, e.g. circle with extended geo by half linewidth
749 add_fillPatternTransform(aMergedArea, aNewStroke, *pStrokePattern, aMergedArea.getB2DRange());
754 else // if(pStroke)
756 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(aNewStroke, aNewLinePrimitive);
759 if(aNewStroke.hasElements())
761 if(basegfx::fTools::less(fStrokeOpacity, 1.0))
763 // embed in UnifiedTransparencePrimitive2D
764 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(
765 rTarget,
766 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
767 aNewStroke,
768 1.0 - fStrokeOpacity));
770 else
772 // append
773 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aNewStroke);
781 double get_markerRotation(
782 const SvgMarkerNode& rMarker,
783 const basegfx::B2DPolygon& rPolygon,
784 const sal_uInt32 nIndex)
786 double fAngle(0.0);
787 const sal_uInt32 nPointCount(rPolygon.count());
789 if(nPointCount)
791 if(rMarker.getOrientAuto())
793 const bool bPrev(rPolygon.isClosed() || nIndex > 0);
794 basegfx::B2DCubicBezier aSegment;
795 basegfx::B2DVector aPrev;
796 basegfx::B2DVector aNext;
798 if(bPrev)
800 rPolygon.getBezierSegment((nIndex - 1) % nPointCount, aSegment);
801 aPrev = aSegment.getTangent(1.0);
804 const bool bNext(rPolygon.isClosed() || nIndex + 1 < nPointCount);
806 if(bNext)
808 rPolygon.getBezierSegment(nIndex % nPointCount, aSegment);
809 aNext = aSegment.getTangent(0.0);
812 if(bPrev && bNext)
814 fAngle = atan2(aPrev.getY() + aNext.getY(), aPrev.getX() + aNext.getX());
816 else if(bPrev)
818 fAngle = atan2(aPrev.getY(), aPrev.getX());
820 else if(bNext)
822 fAngle = atan2(aNext.getY(), aNext.getX());
825 else
827 fAngle = rMarker.getAngle();
831 return fAngle;
834 bool SvgStyleAttributes::prepare_singleMarker(
835 drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
836 basegfx::B2DHomMatrix& rMarkerTransform,
837 basegfx::B2DRange& rClipRange,
838 const SvgMarkerNode& rMarker) const
840 // reset return values
841 rMarkerTransform.identity();
842 rClipRange.reset();
844 // get marker primitive representation
845 rMarkerPrimitives = rMarker.getMarkerPrimitives();
847 if(rMarkerPrimitives.hasElements())
849 basegfx::B2DRange aPrimitiveRange(0.0, 0.0, 1.0, 1.0);
850 const basegfx::B2DRange* pViewBox = rMarker.getViewBox();
852 if(pViewBox)
854 aPrimitiveRange = *pViewBox;
857 if(aPrimitiveRange.getWidth() > 0.0 && aPrimitiveRange.getHeight() > 0.0)
859 double fTargetWidth(rMarker.getMarkerWidth().isSet() ? rMarker.getMarkerWidth().solve(mrOwner, xcoordinate) : 3.0);
860 double fTargetHeight(rMarker.getMarkerHeight().isSet() ? rMarker.getMarkerHeight().solve(mrOwner, xcoordinate) : 3.0);
861 const bool bStrokeWidth(SvgMarkerNode::strokeWidth == rMarker.getMarkerUnits());
862 const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
864 if(bStrokeWidth)
866 // relative to strokeWidth
867 fTargetWidth *= fStrokeWidth;
868 fTargetHeight *= fStrokeWidth;
871 if(fTargetWidth > 0.0 && fTargetHeight > 0.0)
873 // create mapping
874 const basegfx::B2DRange aTargetRange(0.0, 0.0, fTargetWidth, fTargetHeight);
875 const SvgAspectRatio& rRatio = rMarker.getSvgAspectRatio();
877 if(rRatio.isSet())
879 // let mapping be created from SvgAspectRatio
880 rMarkerTransform = rRatio.createMapping(aTargetRange, aPrimitiveRange);
882 if(rRatio.isMeetOrSlice())
884 // need to clip
885 rClipRange = aPrimitiveRange;
888 else
890 if(!pViewBox)
892 if(bStrokeWidth)
894 // adapt to strokewidth if needed
895 rMarkerTransform.scale(fStrokeWidth, fStrokeWidth);
898 else
900 // choose default mapping
901 rMarkerTransform = rRatio.createLinearMapping(aTargetRange, aPrimitiveRange);
905 // get and apply reference point. Initially it's in marker local coordinate system
906 basegfx::B2DPoint aRefPoint(
907 rMarker.getRefX().isSet() ? rMarker.getRefX().solve(mrOwner, xcoordinate) : 0.0,
908 rMarker.getRefY().isSet() ? rMarker.getRefY().solve(mrOwner, ycoordinate) : 0.0);
910 // apply MarkerTransform to have it in mapped coordinates
911 aRefPoint *= rMarkerTransform;
913 // apply by moving RepPoint to (0.0)
914 rMarkerTransform.translate(-aRefPoint.getX(), -aRefPoint.getY());
916 return true;
921 return false;
924 void SvgStyleAttributes::add_singleMarker(
925 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
926 const drawinglayer::primitive2d::Primitive2DSequence& rMarkerPrimitives,
927 const basegfx::B2DHomMatrix& rMarkerTransform,
928 const basegfx::B2DRange& rClipRange,
929 const SvgMarkerNode& rMarker,
930 const basegfx::B2DPolygon& rCandidate,
931 const sal_uInt32 nIndex) const
933 const sal_uInt32 nPointCount(rCandidate.count());
935 if(nPointCount)
937 // get and apply rotation
938 basegfx::B2DHomMatrix aCombinedTransform(rMarkerTransform);
939 aCombinedTransform.rotate(get_markerRotation(rMarker, rCandidate, nIndex));
941 // get and apply target position
942 const basegfx::B2DPoint aPoint(rCandidate.getB2DPoint(nIndex % nPointCount));
943 aCombinedTransform.translate(aPoint.getX(), aPoint.getY());
945 // prepare marker
946 drawinglayer::primitive2d::Primitive2DReference xMarker(
947 new drawinglayer::primitive2d::TransformPrimitive2D(
948 aCombinedTransform,
949 rMarkerPrimitives));
951 if(!rClipRange.isEmpty())
953 // marker needs to be clipped, it's bigger as the mapping
954 basegfx::B2DPolyPolygon aClipPolygon(basegfx::tools::createPolygonFromRect(rClipRange));
956 aClipPolygon.transform(aCombinedTransform);
957 xMarker = new drawinglayer::primitive2d::MaskPrimitive2D(
958 aClipPolygon,
959 drawinglayer::primitive2d::Primitive2DSequence(&xMarker, 1));
962 // add marker
963 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(rTarget, xMarker);
967 void SvgStyleAttributes::add_markers(
968 const basegfx::B2DPolyPolygon& rPath,
969 drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
971 // try to access linked markers
972 const SvgMarkerNode* pStart = accessMarkerStartXLink();
973 const SvgMarkerNode* pMid = accessMarkerMidXLink();
974 const SvgMarkerNode* pEnd = accessMarkerEndXLink();
976 if(pStart || pMid || pEnd)
978 const sal_uInt32 nCount(rPath.count());
980 for (sal_uInt32 a(0); a < nCount; a++)
982 const basegfx::B2DPolygon aCandidate(rPath.getB2DPolygon(a));
983 const sal_uInt32 nPointCount(aCandidate.count());
985 if(nPointCount)
987 const sal_uInt32 nMarkerCount(aCandidate.isClosed() ? nPointCount + 1 : nPointCount);
988 drawinglayer::primitive2d::Primitive2DSequence aMarkerPrimitives;
989 basegfx::B2DHomMatrix aMarkerTransform;
990 basegfx::B2DRange aClipRange;
991 const SvgMarkerNode* pPrepared = 0;
993 if(pStart)
995 if(prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pStart))
997 pPrepared = pStart;
998 add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, 0);
1002 if(pMid && nMarkerCount > 2)
1004 if(pMid == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pMid))
1006 pPrepared = pMid;
1008 for(sal_uInt32 b(1); b < nMarkerCount - 1; b++)
1010 add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, b);
1015 if(pEnd)
1017 if(pEnd == pPrepared || prepare_singleMarker(aMarkerPrimitives, aMarkerTransform, aClipRange, *pEnd))
1019 pPrepared = pEnd;
1020 add_singleMarker(rTarget, aMarkerPrimitives, aMarkerTransform, aClipRange, *pPrepared, aCandidate, nMarkerCount - 1);
1028 void SvgStyleAttributes::add_path(
1029 const basegfx::B2DPolyPolygon& rPath,
1030 drawinglayer::primitive2d::Primitive2DSequence& rTarget) const
1032 const bool bIsLine(1 == rPath.count()
1033 && !rPath.areControlPointsUsed()
1034 && 2 == rPath.getB2DPolygon(0).count());
1036 if(!rPath.count())
1038 return;
1041 const basegfx::B2DRange aGeoRange(rPath.getB2DRange());
1043 if(aGeoRange.isEmpty())
1045 return;
1048 if(!bIsLine && // not for lines
1049 (basegfx::fTools::equalZero(aGeoRange.getWidth())
1050 || basegfx::fTools::equalZero(aGeoRange.getHeight())))
1052 return;
1055 const double fOpacity(getOpacity().getNumber());
1057 if(basegfx::fTools::equalZero(fOpacity))
1059 return;
1062 if(!bIsLine)
1064 basegfx::B2DPolyPolygon aPath(rPath);
1065 const bool bNeedToCheckClipRule(SVGTokenPath == mrOwner.getType() || SVGTokenPolygon == mrOwner.getType());
1066 const bool bClipPathIsNonzero(!bIsLine && bNeedToCheckClipRule && mbIsClipPathContent && mbClipRule);
1067 const bool bFillRuleIsNonzero(!bIsLine && bNeedToCheckClipRule && !mbIsClipPathContent && getFillRule());
1069 if(bClipPathIsNonzero || bFillRuleIsNonzero)
1071 // nonzero is wanted, solve geometrically (see description on basegfx)
1072 aPath = basegfx::tools::createNonzeroConform(aPath);
1075 add_fill(aPath, rTarget, aGeoRange);
1078 add_stroke(rPath, rTarget, aGeoRange);
1080 // Svg supports markers for path, polygon, polyline and line
1081 if(SVGTokenPath == mrOwner.getType() || // path
1082 SVGTokenPolygon == mrOwner.getType() || // polygon, polyline
1083 SVGTokenLine == mrOwner.getType()) // line
1085 // try to add markers
1086 add_markers(rPath, rTarget);
1090 void SvgStyleAttributes::add_postProcess(
1091 drawinglayer::primitive2d::Primitive2DSequence& rTarget,
1092 const drawinglayer::primitive2d::Primitive2DSequence& rSource,
1093 const basegfx::B2DHomMatrix* pTransform) const
1095 if(rSource.hasElements())
1097 const double fOpacity(getOpacity().getNumber());
1099 if(basegfx::fTools::equalZero(fOpacity))
1101 return;
1104 drawinglayer::primitive2d::Primitive2DSequence aSource(rSource);
1106 if(basegfx::fTools::less(fOpacity, 1.0))
1108 // embed in UnifiedTransparencePrimitive2D
1109 const drawinglayer::primitive2d::Primitive2DReference xRef(
1110 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
1111 aSource,
1112 1.0 - fOpacity));
1114 aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
1117 if(getClipPathXLink().getLength())
1119 // try to access linked ClipPath
1120 const SvgClipPathNode* mpClip = dynamic_cast< const SvgClipPathNode* >(mrOwner.getDocument().findSvgNodeById(getClipPathXLink()));
1122 if(mpClip)
1124 mpClip->apply(aSource);
1128 if(aSource.hasElements()) // test again, applied clipPath may have lead to empty geometry
1130 if(getMaskXLink().getLength())
1132 // try to access linked Mask
1133 const SvgMaskNode* mpMask = dynamic_cast< const SvgMaskNode* >(mrOwner.getDocument().findSvgNodeById(getMaskXLink()));
1135 if(mpMask)
1137 mpMask->apply(aSource);
1141 if(aSource.hasElements()) // test again, applied mask may have lead to empty geometry
1143 if(pTransform)
1145 // create embedding group element with transformation
1146 const drawinglayer::primitive2d::Primitive2DReference xRef(
1147 new drawinglayer::primitive2d::TransformPrimitive2D(
1148 *pTransform,
1149 aSource));
1151 aSource = drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1);
1154 // append to current target
1155 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(rTarget, aSource);
1161 SvgStyleAttributes::SvgStyleAttributes(SvgNode& rOwner)
1162 : mrOwner(rOwner),
1163 mpCssStyleParent(0),
1164 maFill(),
1165 maStroke(),
1166 maStopColor(basegfx::BColor(0.0, 0.0, 0.0), true),
1167 maStrokeWidth(),
1168 maStopOpacity(),
1169 mpSvgGradientNodeFill(0),
1170 mpSvgGradientNodeStroke(0),
1171 mpSvgPatternNodeFill(0),
1172 mpSvgPatternNodeStroke(0),
1173 maFillOpacity(),
1174 maStrokeDasharray(),
1175 maStrokeDashOffset(),
1176 maStrokeLinecap(StrokeLinecap_notset),
1177 maStrokeLinejoin(StrokeLinejoin_notset),
1178 maStrokeMiterLimit(),
1179 maStrokeOpacity(),
1180 maFontFamily(),
1181 maFontSize(),
1182 maFontStretch(FontStretch_notset),
1183 maFontStyle(FontStyle_notset),
1184 maFontVariant(FontVariant_notset),
1185 maFontWeight(FontWeight_notset),
1186 maTextAlign(TextAlign_notset),
1187 maTextDecoration(TextDecoration_notset),
1188 maTextAnchor(TextAnchor_notset),
1189 maColor(),
1190 maOpacity(1.0),
1191 maClipPathXLink(),
1192 maMaskXLink(),
1193 maMarkerStartXLink(),
1194 mpMarkerStartXLink(0),
1195 maMarkerMidXLink(),
1196 mpMarkerMidXLink(0),
1197 maMarkerEndXLink(),
1198 mpMarkerEndXLink(0),
1199 maFillRule(true),
1200 maFillRuleSet(false),
1201 mbIsClipPathContent(SVGTokenClipPathNode == mrOwner.getType()),
1202 mbClipRule(true)
1204 if(!mbIsClipPathContent)
1206 const SvgStyleAttributes* pParentStyle = getParentStyle();
1208 if(pParentStyle)
1210 mbIsClipPathContent = pParentStyle->mbIsClipPathContent;
1215 SvgStyleAttributes::~SvgStyleAttributes()
1219 void SvgStyleAttributes::parseStyleAttribute(const rtl::OUString& /*rTokenName*/, SVGToken aSVGToken, const rtl::OUString& aContent)
1221 switch(aSVGToken)
1223 case SVGTokenFill:
1225 SvgPaint aSvgPaint;
1226 rtl::OUString aURL;
1228 if(readSvgPaint(aContent, aSvgPaint, aURL))
1230 setFill(aSvgPaint);
1232 else if(aURL.getLength())
1234 const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
1236 if(pNode)
1238 if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType())
1240 setSvgGradientNodeFill(static_cast< const SvgGradientNode* >(pNode));
1242 else if(SVGTokenPattern == pNode->getType())
1244 setSvgPatternNodeFill(static_cast< const SvgPatternNode* >(pNode));
1248 break;
1250 case SVGTokenFillOpacity:
1252 SvgNumber aNum;
1254 if(readSingleNumber(aContent, aNum))
1256 if(aNum.isPositive())
1258 setFillOpacity(aNum);
1261 break;
1263 case SVGTokenFillRule:
1265 if(aContent.getLength())
1267 if(aContent.match(commonStrings::aStrNonzero))
1269 maFillRule = true;
1270 maFillRuleSet = true;
1272 else if(aContent.match(commonStrings::aStrEvenOdd))
1274 maFillRule = false;
1275 maFillRuleSet = true;
1278 break;
1280 case SVGTokenStroke:
1282 SvgPaint aSvgPaint;
1283 rtl::OUString aURL;
1285 if(readSvgPaint(aContent, aSvgPaint, aURL))
1287 setStroke(aSvgPaint);
1289 else if(aURL.getLength())
1291 const SvgNode* pNode = mrOwner.getDocument().findSvgNodeById(aURL);
1293 if(pNode)
1295 if(SVGTokenLinearGradient == pNode->getType() || SVGTokenRadialGradient == pNode->getType())
1297 setSvgGradientNodeStroke(static_cast< const SvgGradientNode* >(pNode));
1299 else if(SVGTokenPattern == pNode->getType())
1301 setSvgPatternNodeStroke(static_cast< const SvgPatternNode* >(pNode));
1305 break;
1307 case SVGTokenStrokeDasharray:
1309 if(aContent.getLength())
1311 SvgNumberVector aVector;
1313 if(readSvgNumberVector(aContent, aVector))
1315 setStrokeDasharray(aVector);
1318 break;
1320 case SVGTokenStrokeDashoffset:
1322 SvgNumber aNum;
1324 if(readSingleNumber(aContent, aNum))
1326 if(aNum.isPositive())
1328 setStrokeDashOffset(aNum);
1331 break;
1333 case SVGTokenStrokeLinecap:
1335 if(aContent.getLength())
1337 static rtl::OUString aStrButt(rtl::OUString::createFromAscii("butt"));
1338 static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
1339 static rtl::OUString aStrSquare(rtl::OUString::createFromAscii("square"));
1341 if(aContent.match(aStrButt))
1343 setStrokeLinecap(StrokeLinecap_butt);
1345 else if(aContent.match(aStrRound))
1347 setStrokeLinecap(StrokeLinecap_round);
1349 else if(aContent.match(aStrSquare))
1351 setStrokeLinecap(StrokeLinecap_square);
1354 break;
1356 case SVGTokenStrokeLinejoin:
1358 if(aContent.getLength())
1360 static rtl::OUString aStrMiter(rtl::OUString::createFromAscii("miter"));
1361 static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
1362 static rtl::OUString aStrBevel(rtl::OUString::createFromAscii("bevel"));
1364 if(aContent.match(aStrMiter))
1366 setStrokeLinejoin(StrokeLinejoin_miter);
1368 else if(aContent.match(aStrRound))
1370 setStrokeLinejoin(StrokeLinejoin_round);
1372 else if(aContent.match(aStrBevel))
1374 setStrokeLinejoin(StrokeLinejoin_bevel);
1377 break;
1379 case SVGTokenStrokeMiterlimit:
1381 SvgNumber aNum;
1383 if(readSingleNumber(aContent, aNum))
1385 if(aNum.isPositive())
1387 setStrokeMiterLimit(aNum);
1390 break;
1392 case SVGTokenStrokeOpacity:
1394 SvgNumber aNum;
1396 if(readSingleNumber(aContent, aNum))
1398 if(aNum.isPositive())
1400 setStrokeOpacity(aNum);
1403 break;
1405 case SVGTokenStrokeWidth:
1407 SvgNumber aNum;
1409 if(readSingleNumber(aContent, aNum))
1411 if(aNum.isPositive())
1413 setStrokeWidth(aNum);
1416 break;
1418 case SVGTokenStopColor:
1420 SvgPaint aSvgPaint;
1421 rtl::OUString aURL;
1423 if(readSvgPaint(aContent, aSvgPaint, aURL))
1425 setStopColor(aSvgPaint);
1427 break;
1429 case SVGTokenStopOpacity:
1431 SvgNumber aNum;
1433 if(readSingleNumber(aContent, aNum))
1435 if(aNum.isPositive())
1437 setStopOpacity(aNum);
1440 break;
1442 case SVGTokenFont:
1444 break;
1446 case SVGTokenFontFamily:
1448 SvgStringVector aSvgStringVector;
1450 if(readSvgStringVector(aContent, aSvgStringVector))
1452 setFontFamily(aSvgStringVector);
1454 break;
1456 case SVGTokenFontSize:
1458 SvgNumber aNum;
1460 if(readSingleNumber(aContent, aNum))
1462 setFontSize(aNum);
1464 break;
1466 case SVGTokenFontSizeAdjust:
1468 break;
1470 case SVGTokenFontStretch:
1472 if(aContent.getLength())
1474 static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1475 static rtl::OUString aStrWider(rtl::OUString::createFromAscii("wider"));
1476 static rtl::OUString aStrNarrower(rtl::OUString::createFromAscii("narrower"));
1477 static rtl::OUString aStrUltra_condensed(rtl::OUString::createFromAscii("ultra-condensed"));
1478 static rtl::OUString aStrExtra_condensed(rtl::OUString::createFromAscii("extra-condensed"));
1479 static rtl::OUString aStrCondensed(rtl::OUString::createFromAscii("condensed"));
1480 static rtl::OUString aStrSemi_condensed(rtl::OUString::createFromAscii("semi-condensed"));
1481 static rtl::OUString aStrSemi_expanded(rtl::OUString::createFromAscii("semi-expanded"));
1482 static rtl::OUString aStrExpanded(rtl::OUString::createFromAscii("expanded"));
1483 static rtl::OUString aStrExtra_expanded(rtl::OUString::createFromAscii("extra-expanded"));
1484 static rtl::OUString aStrUltra_expanded(rtl::OUString::createFromAscii("ultra-expanded"));
1486 if(aContent.match(aStrNormal))
1488 setFontStretch(FontStretch_normal);
1490 else if(aContent.match(aStrWider))
1492 setFontStretch(FontStretch_wider);
1494 else if(aContent.match(aStrNarrower))
1496 setFontStretch(FontStretch_narrower);
1498 else if(aContent.match(aStrUltra_condensed))
1500 setFontStretch(FontStretch_ultra_condensed);
1502 else if(aContent.match(aStrExtra_condensed))
1504 setFontStretch(FontStretch_extra_condensed);
1506 else if(aContent.match(aStrCondensed))
1508 setFontStretch(FontStretch_condensed);
1510 else if(aContent.match(aStrSemi_condensed))
1512 setFontStretch(FontStretch_semi_condensed);
1514 else if(aContent.match(aStrSemi_expanded))
1516 setFontStretch(FontStretch_semi_expanded);
1518 else if(aContent.match(aStrExpanded))
1520 setFontStretch(FontStretch_expanded);
1522 else if(aContent.match(aStrExtra_expanded))
1524 setFontStretch(FontStretch_extra_expanded);
1526 else if(aContent.match(aStrUltra_expanded))
1528 setFontStretch(FontStretch_ultra_expanded);
1531 break;
1533 case SVGTokenFontStyle:
1535 if(aContent.getLength())
1537 static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1538 static rtl::OUString aStrItalic(rtl::OUString::createFromAscii("italic"));
1539 static rtl::OUString aStrOblique(rtl::OUString::createFromAscii("oblique"));
1541 if(aContent.match(aStrNormal))
1543 setFontStyle(FontStyle_normal);
1545 else if(aContent.match(aStrItalic))
1547 setFontStyle(FontStyle_italic);
1549 else if(aContent.match(aStrOblique))
1551 setFontStyle(FontStyle_oblique);
1554 break;
1556 case SVGTokenFontVariant:
1558 if(aContent.getLength())
1560 static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1561 static rtl::OUString aStrSmallCaps(rtl::OUString::createFromAscii("small-caps"));
1563 if(aContent.match(aStrNormal))
1565 setFontVariant(FontVariant_normal);
1567 else if(aContent.match(aStrSmallCaps))
1569 setFontVariant(FontVariant_small_caps);
1572 break;
1574 case SVGTokenFontWeight:
1576 if(aContent.getLength())
1578 static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
1579 static rtl::OUString aStrBold(rtl::OUString::createFromAscii("bold"));
1580 static rtl::OUString aStrBolder(rtl::OUString::createFromAscii("bolder"));
1581 static rtl::OUString aStrLighter(rtl::OUString::createFromAscii("lighter"));
1582 static rtl::OUString aStr100(rtl::OUString::createFromAscii("100"));
1583 static rtl::OUString aStr200(rtl::OUString::createFromAscii("200"));
1584 static rtl::OUString aStr300(rtl::OUString::createFromAscii("300"));
1585 static rtl::OUString aStr400(rtl::OUString::createFromAscii("400"));
1586 static rtl::OUString aStr500(rtl::OUString::createFromAscii("500"));
1587 static rtl::OUString aStr600(rtl::OUString::createFromAscii("600"));
1588 static rtl::OUString aStr700(rtl::OUString::createFromAscii("700"));
1589 static rtl::OUString aStr800(rtl::OUString::createFromAscii("800"));
1590 static rtl::OUString aStr900(rtl::OUString::createFromAscii("900"));
1592 if(aContent.match(aStr100))
1594 setFontWeight(FontWeight_100);
1596 else if(aContent.match(aStr200))
1598 setFontWeight(FontWeight_200);
1600 else if(aContent.match(aStr300))
1602 setFontWeight(FontWeight_300);
1604 else if(aContent.match(aStr400) || aContent.match(aStrNormal))
1606 setFontWeight(FontWeight_400);
1608 else if(aContent.match(aStr500))
1610 setFontWeight(FontWeight_500);
1612 else if(aContent.match(aStr600))
1614 setFontWeight(FontWeight_600);
1616 else if(aContent.match(aStr700) || aContent.match(aStrBold))
1618 setFontWeight(FontWeight_700);
1620 else if(aContent.match(aStr800))
1622 setFontWeight(FontWeight_800);
1624 else if(aContent.match(aStr900))
1626 setFontWeight(FontWeight_900);
1628 else if(aContent.match(aStrBolder))
1630 setFontWeight(FontWeight_bolder);
1632 else if(aContent.match(aStrLighter))
1634 setFontWeight(FontWeight_lighter);
1637 break;
1639 case SVGTokenDirection:
1641 break;
1643 case SVGTokenLetterSpacing:
1645 break;
1647 case SVGTokenTextDecoration:
1649 if(aContent.getLength())
1651 static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
1652 static rtl::OUString aStrUnderline(rtl::OUString::createFromAscii("underline"));
1653 static rtl::OUString aStrOverline(rtl::OUString::createFromAscii("overline"));
1654 static rtl::OUString aStrLineThrough(rtl::OUString::createFromAscii("line-through"));
1655 static rtl::OUString aStrBlink(rtl::OUString::createFromAscii("blink"));
1657 if(aContent.match(aStrNone))
1659 setTextDecoration(TextDecoration_none);
1661 else if(aContent.match(aStrUnderline))
1663 setTextDecoration(TextDecoration_underline);
1665 else if(aContent.match(aStrOverline))
1667 setTextDecoration(TextDecoration_overline);
1669 else if(aContent.match(aStrLineThrough))
1671 setTextDecoration(TextDecoration_line_through);
1673 else if(aContent.match(aStrBlink))
1675 setTextDecoration(TextDecoration_blink);
1678 break;
1680 case SVGTokenUnicodeBidi:
1682 break;
1684 case SVGTokenWordSpacing:
1686 break;
1688 case SVGTokenTextAnchor:
1690 if(aContent.getLength())
1692 static rtl::OUString aStrStart(rtl::OUString::createFromAscii("start"));
1693 static rtl::OUString aStrMiddle(rtl::OUString::createFromAscii("middle"));
1694 static rtl::OUString aStrEnd(rtl::OUString::createFromAscii("end"));
1696 if(aContent.match(aStrStart))
1698 setTextAnchor(TextAnchor_start);
1700 else if(aContent.match(aStrMiddle))
1702 setTextAnchor(TextAnchor_middle);
1704 else if(aContent.match(aStrEnd))
1706 setTextAnchor(TextAnchor_end);
1709 break;
1711 case SVGTokenTextAlign:
1713 if(aContent.getLength())
1715 static rtl::OUString aStrLeft(rtl::OUString::createFromAscii("left"));
1716 static rtl::OUString aStrRight(rtl::OUString::createFromAscii("right"));
1717 static rtl::OUString aStrCenter(rtl::OUString::createFromAscii("center"));
1718 static rtl::OUString aStrJustify(rtl::OUString::createFromAscii("justify"));
1720 if(aContent.match(aStrLeft))
1722 setTextAlign(TextAlign_left);
1724 else if(aContent.match(aStrRight))
1726 setTextAlign(TextAlign_right);
1728 else if(aContent.match(aStrCenter))
1730 setTextAlign(TextAlign_center);
1732 else if(aContent.match(aStrJustify))
1734 setTextAlign(TextAlign_justify);
1737 break;
1739 case SVGTokenColor:
1741 SvgPaint aSvgPaint;
1742 rtl::OUString aURL;
1744 if(readSvgPaint(aContent, aSvgPaint, aURL))
1746 setColor(aSvgPaint);
1748 break;
1750 case SVGTokenOpacity:
1752 SvgNumber aNum;
1754 if(readSingleNumber(aContent, aNum))
1756 setOpacity(SvgNumber(basegfx::clamp(aNum.getNumber(), 0.0, 1.0), aNum.getUnit(), aNum.isSet()));
1758 break;
1760 case SVGTokenClipPathProperty:
1762 readLocalUrl(aContent, maClipPathXLink);
1763 break;
1765 case SVGTokenMask:
1767 readLocalUrl(aContent, maMaskXLink);
1768 break;
1770 case SVGTokenClipRule:
1772 if(aContent.getLength())
1774 if(aContent.match(commonStrings::aStrNonzero))
1776 mbClipRule = true;
1778 else if(aContent.match(commonStrings::aStrEvenOdd))
1780 mbClipRule = false;
1783 break;
1785 case SVGTokenMarker:
1787 readLocalUrl(aContent, maMarkerEndXLink);
1788 maMarkerStartXLink = maMarkerMidXLink = maMarkerEndXLink;
1789 break;
1791 case SVGTokenMarkerStart:
1793 readLocalUrl(aContent, maMarkerStartXLink);
1794 break;
1796 case SVGTokenMarkerMid:
1798 readLocalUrl(aContent, maMarkerMidXLink);
1799 break;
1801 case SVGTokenMarkerEnd:
1803 readLocalUrl(aContent, maMarkerEndXLink);
1804 break;
1806 default:
1808 break;
1813 const basegfx::BColor* SvgStyleAttributes::getFill() const
1815 if(mbIsClipPathContent)
1817 static basegfx::BColor aBlack(0.0, 0.0, 0.0);
1819 return &aBlack;
1821 else if(maFill.isSet())
1823 if(maFill.isCurrent())
1825 return getColor();
1827 else if(maFill.isOn())
1829 return &maFill.getBColor();
1832 else
1834 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1836 if(pSvgStyleAttributes)
1838 return pSvgStyleAttributes->getFill();
1842 return 0;
1845 const basegfx::BColor* SvgStyleAttributes::getStroke() const
1847 if(mbIsClipPathContent)
1849 return 0;
1851 else if(maStroke.isSet())
1853 if(maStroke.isCurrent())
1855 return getColor();
1857 else if(maStroke.isOn())
1859 return &maStroke.getBColor();
1862 else
1864 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1866 if(pSvgStyleAttributes)
1868 return pSvgStyleAttributes->getStroke();
1872 return 0;
1875 const basegfx::BColor& SvgStyleAttributes::getStopColor() const
1877 if(maStopColor.isCurrent())
1879 return *getColor();
1881 else
1883 return maStopColor.getBColor();
1887 const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeFill() const
1889 if(mbIsClipPathContent)
1891 return 0;
1893 else if(mpSvgGradientNodeFill)
1895 return mpSvgGradientNodeFill;
1897 else
1899 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1901 if(pSvgStyleAttributes)
1903 return pSvgStyleAttributes->getSvgGradientNodeFill();
1907 return 0;
1910 const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeStroke() const
1912 if(mbIsClipPathContent)
1914 return 0;
1916 else if(mpSvgGradientNodeStroke)
1918 return mpSvgGradientNodeStroke;
1920 else
1922 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1924 if(pSvgStyleAttributes)
1926 return pSvgStyleAttributes->getSvgGradientNodeStroke();
1930 return 0;
1933 const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeFill() const
1935 if(mbIsClipPathContent)
1937 return 0;
1939 else if(mpSvgPatternNodeFill)
1941 return mpSvgPatternNodeFill;
1943 else
1945 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1947 if(pSvgStyleAttributes)
1949 return pSvgStyleAttributes->getSvgPatternNodeFill();
1953 return 0;
1956 const SvgPatternNode* SvgStyleAttributes::getSvgPatternNodeStroke() const
1958 if(mbIsClipPathContent)
1960 return 0;
1962 else if(mpSvgPatternNodeStroke)
1964 return mpSvgPatternNodeStroke;
1966 else
1968 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1970 if(pSvgStyleAttributes)
1972 return pSvgStyleAttributes->getSvgPatternNodeStroke();
1976 return 0;
1979 const SvgNumber SvgStyleAttributes::getStrokeWidth() const
1981 if(mbIsClipPathContent)
1983 return SvgNumber(0.0);
1985 else if(maStrokeWidth.isSet())
1987 return maStrokeWidth;
1990 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
1992 if(pSvgStyleAttributes)
1994 return pSvgStyleAttributes->getStrokeWidth();
1997 // default is 1
1998 return SvgNumber(1.0);
2001 const SvgNumber SvgStyleAttributes::getStopOpacity() const
2003 if(maStopOpacity.isSet())
2005 return maStopOpacity;
2008 // default is 1
2009 return SvgNumber(1.0);
2012 const SvgNumber SvgStyleAttributes::getFillOpacity() const
2014 if(mbIsClipPathContent)
2016 return SvgNumber(1.0);
2018 else if(maFillOpacity.isSet())
2020 return maFillOpacity;
2023 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2025 if(pSvgStyleAttributes)
2027 return pSvgStyleAttributes->getFillOpacity();
2030 // default is 1
2031 return SvgNumber(1.0);
2034 bool SvgStyleAttributes::getFillRule() const
2036 if(maFillRuleSet)
2038 return maFillRule;
2041 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2043 if(pSvgStyleAttributes)
2045 return pSvgStyleAttributes->getFillRule();
2048 // default is NonZero
2049 return true;
2052 const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
2054 if(!maStrokeDasharray.empty())
2056 return maStrokeDasharray;
2059 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2061 if(pSvgStyleAttributes)
2063 return pSvgStyleAttributes->getStrokeDasharray();
2066 // default empty
2067 return maStrokeDasharray;
2070 const SvgNumber SvgStyleAttributes::getStrokeDashOffset() const
2072 if(maStrokeDashOffset.isSet())
2074 return maStrokeDashOffset;
2077 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2079 if(pSvgStyleAttributes)
2081 return pSvgStyleAttributes->getStrokeDashOffset();
2084 // default is 0
2085 return SvgNumber(0.0);
2088 StrokeLinecap SvgStyleAttributes::getStrokeLinecap() const
2090 if(maStrokeLinecap != StrokeLinecap_notset)
2092 return maStrokeLinecap;
2095 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2097 if(pSvgStyleAttributes)
2099 return pSvgStyleAttributes->getStrokeLinecap();
2102 // default is StrokeLinecap_butt
2103 return StrokeLinecap_butt;
2106 StrokeLinejoin SvgStyleAttributes::getStrokeLinejoin() const
2108 if(maStrokeLinejoin != StrokeLinejoin_notset)
2110 return maStrokeLinejoin;
2113 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2115 if(pSvgStyleAttributes)
2117 return pSvgStyleAttributes->getStrokeLinejoin();
2120 // default is StrokeLinejoin_butt
2121 return StrokeLinejoin_miter;
2124 const SvgNumber SvgStyleAttributes::getStrokeMiterLimit() const
2126 if(maStrokeMiterLimit.isSet())
2128 return maStrokeMiterLimit;
2131 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2133 if(pSvgStyleAttributes)
2135 return pSvgStyleAttributes->getStrokeMiterLimit();
2138 // default is 4
2139 return SvgNumber(4.0);
2142 const SvgNumber SvgStyleAttributes::getStrokeOpacity() const
2144 if(maStrokeOpacity.isSet())
2146 return maStrokeOpacity;
2149 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2151 if(pSvgStyleAttributes)
2153 return pSvgStyleAttributes->getStrokeOpacity();
2156 // default is 1
2157 return SvgNumber(1.0);
2160 const SvgStringVector& SvgStyleAttributes::getFontFamily() const
2162 if(!maFontFamily.empty())
2164 return maFontFamily;
2167 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2169 if(pSvgStyleAttributes)
2171 return pSvgStyleAttributes->getFontFamily();
2174 // default is empty
2175 return maFontFamily;
2178 const SvgNumber SvgStyleAttributes::getFontSize() const
2180 if(maFontSize.isSet())
2182 return maFontSize;
2185 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2187 if(pSvgStyleAttributes)
2189 return pSvgStyleAttributes->getFontSize();
2192 // default is 'medium'
2193 return SvgNumber(12.0);
2196 FontStretch SvgStyleAttributes::getFontStretch() const
2198 if(maFontStretch != FontStretch_notset)
2200 if(FontStretch_wider != maFontStretch && FontStretch_narrower != maFontStretch)
2202 return maFontStretch;
2206 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2208 if(pSvgStyleAttributes)
2210 FontStretch aInherited = pSvgStyleAttributes->getFontStretch();
2212 if(FontStretch_wider == maFontStretch)
2214 aInherited = getWider(aInherited);
2216 else if(FontStretch_narrower == maFontStretch)
2218 aInherited = getNarrower(aInherited);
2221 return aInherited;
2224 // default is FontStretch_normal
2225 return FontStretch_normal;
2228 FontStyle SvgStyleAttributes::getFontStyle() const
2230 if(maFontStyle != FontStyle_notset)
2232 return maFontStyle;
2235 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2237 if(pSvgStyleAttributes)
2239 return pSvgStyleAttributes->getFontStyle();
2242 // default is FontStyle_normal
2243 return FontStyle_normal;
2246 FontWeight SvgStyleAttributes::getFontWeight() const
2248 if(maFontWeight != FontWeight_notset)
2250 if(FontWeight_bolder != maFontWeight && FontWeight_lighter != maFontWeight)
2252 return maFontWeight;
2256 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2258 if(pSvgStyleAttributes)
2260 FontWeight aInherited = pSvgStyleAttributes->getFontWeight();
2262 if(FontWeight_bolder == maFontWeight)
2264 aInherited = getBolder(aInherited);
2266 else if(FontWeight_lighter == maFontWeight)
2268 aInherited = getLighter(aInherited);
2271 return aInherited;
2274 // default is FontWeight_400 (FontWeight_normal)
2275 return FontWeight_400;
2278 TextAlign SvgStyleAttributes::getTextAlign() const
2280 if(maTextAlign != TextAlign_notset)
2282 return maTextAlign;
2285 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2287 if(pSvgStyleAttributes)
2289 return pSvgStyleAttributes->getTextAlign();
2292 // default is TextAlign_left
2293 return TextAlign_left;
2296 const SvgStyleAttributes* SvgStyleAttributes::getTextDecorationDefiningSvgStyleAttributes() const
2298 if(maTextDecoration != TextDecoration_notset)
2300 return this;
2303 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2305 if(pSvgStyleAttributes)
2307 return pSvgStyleAttributes->getTextDecorationDefiningSvgStyleAttributes();
2310 // default is 0
2311 return 0;
2314 TextDecoration SvgStyleAttributes::getTextDecoration() const
2316 const SvgStyleAttributes* pDefining = getTextDecorationDefiningSvgStyleAttributes();
2318 if(pDefining)
2320 return pDefining->maTextDecoration;
2322 else
2324 // default is TextDecoration_none
2325 return TextDecoration_none;
2329 TextAnchor SvgStyleAttributes::getTextAnchor() const
2331 if(maTextAnchor != TextAnchor_notset)
2333 return maTextAnchor;
2336 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2338 if(pSvgStyleAttributes)
2340 return pSvgStyleAttributes->getTextAnchor();
2343 // default is TextAnchor_start
2344 return TextAnchor_start;
2347 const basegfx::BColor* SvgStyleAttributes::getColor() const
2349 if(maColor.isSet())
2351 if(maColor.isCurrent())
2353 OSL_ENSURE(false, "Svg error: current color uses current color (!)");
2354 return 0;
2356 else if(maColor.isOn())
2358 return &maColor.getBColor();
2361 else
2363 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2365 if(pSvgStyleAttributes)
2367 return pSvgStyleAttributes->getColor();
2371 return 0;
2374 const rtl::OUString SvgStyleAttributes::getMarkerStartXLink() const
2376 if(maMarkerStartXLink.getLength())
2378 return maMarkerStartXLink;
2381 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2383 if(pSvgStyleAttributes)
2385 return pSvgStyleAttributes->getMarkerStartXLink();
2388 return rtl::OUString();
2391 const SvgMarkerNode* SvgStyleAttributes::accessMarkerStartXLink() const
2393 if(!mpMarkerStartXLink)
2395 const rtl::OUString aMarker(getMarkerStartXLink());
2397 if(aMarker.getLength())
2399 const_cast< SvgStyleAttributes* >(this)->mpMarkerStartXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerStartXLink()));
2403 return mpMarkerStartXLink;
2406 const rtl::OUString SvgStyleAttributes::getMarkerMidXLink() const
2408 if(maMarkerMidXLink.getLength())
2410 return maMarkerMidXLink;
2413 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2415 if(pSvgStyleAttributes)
2417 return pSvgStyleAttributes->getMarkerMidXLink();
2420 return rtl::OUString();
2423 const SvgMarkerNode* SvgStyleAttributes::accessMarkerMidXLink() const
2425 if(!mpMarkerMidXLink)
2427 const rtl::OUString aMarker(getMarkerMidXLink());
2429 if(aMarker.getLength())
2431 const_cast< SvgStyleAttributes* >(this)->mpMarkerMidXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerMidXLink()));
2435 return mpMarkerMidXLink;
2438 const rtl::OUString SvgStyleAttributes::getMarkerEndXLink() const
2440 if(maMarkerEndXLink.getLength())
2442 return maMarkerEndXLink;
2445 const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
2447 if(pSvgStyleAttributes)
2449 return pSvgStyleAttributes->getMarkerEndXLink();
2452 return rtl::OUString();
2455 const SvgMarkerNode* SvgStyleAttributes::accessMarkerEndXLink() const
2457 if(!mpMarkerEndXLink)
2459 const rtl::OUString aMarker(getMarkerEndXLink());
2461 if(aMarker.getLength())
2463 const_cast< SvgStyleAttributes* >(this)->mpMarkerEndXLink = dynamic_cast< const SvgMarkerNode* >(mrOwner.getDocument().findSvgNodeById(getMarkerEndXLink()));
2467 return mpMarkerEndXLink;
2470 } // end of namespace svgreader
2471 } // end of namespace svgio
2473 //////////////////////////////////////////////////////////////////////////////
2474 // eof
2476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */