You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by al...@apache.org on 2011/12/01 17:26:53 UTC
svn commit: r1209140 [7/11] - in
/incubator/ooo/branches/alg/svgreplacement/main: ./
basegfx/inc/basegfx/matrix/ basegfx/inc/basegfx/polygon/
basegfx/source/polygon/ cppcanvas/source/mtfrenderer/ drawinglayer/
drawinglayer/inc/drawinglayer/primitive2d/...
Added: incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstyleattributes.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstyleattributes.cxx?rev=1209140&view=auto
==============================================================================
--- incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstyleattributes.cxx (added)
+++ incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstyleattributes.cxx Thu Dec 1 16:25:17 2011
@@ -0,0 +1,1655 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svgio.hxx"
+
+#include <svgio/svgreader/svgstyleattributes.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <svgio/svgreader/svgnode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+#include <drawinglayer/primitive2d/svggradientprimitive2d.hxx>
+#include <svgio/svgreader/svggradientnode.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <drawinglayer/processor2d/linegeometryextractor2d.hxx>
+#include <drawinglayer/processor2d/textaspolygonextractor2d.hxx>
+#include <basegfx/polygon/b2dpolypolygoncutter.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ basegfx::B2DLineJoin StrokeLinejoinToB2DLineJoin(StrokeLinejoin aStrokeLinejoin)
+ {
+ if(StrokeLinejoin_round == aStrokeLinejoin)
+ {
+ return basegfx::B2DLINEJOIN_ROUND;
+ }
+ else if(StrokeLinejoin_bevel == aStrokeLinejoin)
+ {
+ return basegfx::B2DLINEJOIN_BEVEL;
+ }
+
+ return basegfx::B2DLINEJOIN_MITER;
+ }
+
+ FontStretch getWider(FontStretch aSource)
+ {
+ switch(aSource)
+ {
+ case FontStretch_ultra_condensed: aSource = FontStretch_extra_condensed; break;
+ case FontStretch_extra_condensed: aSource = FontStretch_condensed; break;
+ case FontStretch_condensed: aSource = FontStretch_semi_condensed; break;
+ case FontStretch_semi_condensed: aSource = FontStretch_normal; break;
+ case FontStretch_normal: aSource = FontStretch_semi_expanded; break;
+ case FontStretch_semi_expanded: aSource = FontStretch_expanded; break;
+ case FontStretch_expanded: aSource = FontStretch_extra_expanded; break;
+ case FontStretch_extra_expanded: aSource = FontStretch_ultra_expanded; break;
+ }
+
+ return aSource;
+ }
+
+ FontStretch getNarrower(FontStretch aSource)
+ {
+ switch(aSource)
+ {
+ case FontStretch_extra_condensed: aSource = FontStretch_ultra_condensed; break;
+ case FontStretch_condensed: aSource = FontStretch_extra_condensed; break;
+ case FontStretch_semi_condensed: aSource = FontStretch_condensed; break;
+ case FontStretch_normal: aSource = FontStretch_semi_condensed; break;
+ case FontStretch_semi_expanded: aSource = FontStretch_normal; break;
+ case FontStretch_expanded: aSource = FontStretch_semi_expanded; break;
+ case FontStretch_extra_expanded: aSource = FontStretch_expanded; break;
+ case FontStretch_ultra_expanded: aSource = FontStretch_extra_expanded; break;
+ }
+
+ return aSource;
+ }
+
+ FontWeight getBolder(FontWeight aSource)
+ {
+ switch(aSource)
+ {
+ case FontWeight_100: aSource = FontWeight_200; break;
+ case FontWeight_200: aSource = FontWeight_300; break;
+ case FontWeight_300: aSource = FontWeight_400; break;
+ case FontWeight_400: aSource = FontWeight_500; break;
+ case FontWeight_500: aSource = FontWeight_600; break;
+ case FontWeight_600: aSource = FontWeight_700; break;
+ case FontWeight_700: aSource = FontWeight_800; break;
+ case FontWeight_800: aSource = FontWeight_900; break;
+ }
+
+ return aSource;
+ }
+
+ FontWeight getLighter(FontWeight aSource)
+ {
+ switch(aSource)
+ {
+ case FontWeight_200: aSource = FontWeight_100; break;
+ case FontWeight_300: aSource = FontWeight_200; break;
+ case FontWeight_400: aSource = FontWeight_300; break;
+ case FontWeight_500: aSource = FontWeight_400; break;
+ case FontWeight_600: aSource = FontWeight_500; break;
+ case FontWeight_700: aSource = FontWeight_600; break;
+ case FontWeight_800: aSource = FontWeight_700; break;
+ case FontWeight_900: aSource = FontWeight_800; break;
+ }
+
+ return aSource;
+ }
+
+ ::FontWeight getVclFontWeight(FontWeight aSource)
+ {
+ ::FontWeight nRetval(WEIGHT_NORMAL);
+
+ switch(aSource)
+ {
+ case FontWeight_100: nRetval = WEIGHT_ULTRALIGHT; break;
+ case FontWeight_200: nRetval = WEIGHT_LIGHT; break;
+ case FontWeight_300: nRetval = WEIGHT_SEMILIGHT; break;
+ case FontWeight_400: nRetval = WEIGHT_NORMAL; break;
+ case FontWeight_500: nRetval = WEIGHT_MEDIUM; break;
+ case FontWeight_600: nRetval = WEIGHT_SEMIBOLD; break;
+ case FontWeight_700: nRetval = WEIGHT_BOLD; break;
+ case FontWeight_800: nRetval = WEIGHT_ULTRABOLD; break;
+ case FontWeight_900: nRetval = WEIGHT_BLACK; break;
+ }
+
+ return nRetval;
+ }
+
+ void SvgStyleAttributes::readStyle(const rtl::OUString& rCandidate)
+ {
+ const sal_Int32 nLen(rCandidate.getLength());
+ sal_Int32 nPos(0);
+
+ while(nPos < nLen)
+ {
+ const sal_Int32 nInitPos(nPos);
+ skip_char(rCandidate, sal_Unicode(' '), nPos, nLen);
+ rtl::OUStringBuffer aTokenName;
+ copyString(rCandidate, nPos, aTokenName, nLen);
+
+ if(aTokenName.getLength())
+ {
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(':'), nPos, nLen);
+ rtl::OUStringBuffer aTokenValue;
+ copyToLimiter(rCandidate, sal_Unicode(';'), nPos, aTokenValue, nLen);
+ skip_char(rCandidate, sal_Unicode(' '), sal_Unicode(';'), nPos, nLen);
+ const rtl::OUString aOUTokenName(aTokenName.makeStringAndClear());
+ const rtl::OUString aOUTokenValue(aTokenValue.makeStringAndClear());
+
+ parseStyleAttribute(aOUTokenName, StrToSVGToken(aOUTokenName), aOUTokenValue);
+ }
+
+ if(nInitPos == nPos)
+ {
+ OSL_ENSURE(false, "Could not interpret on current position (!)");
+ nPos++;
+ }
+ }
+ }
+
+ void SvgStyleAttributes::checkForCssStyle(const rtl::OUString& rClassStr) const
+ {
+ if(!mpCssStyleParent && mrOwner.getClass())
+ {
+ const SvgDocument& rDocument = mrOwner.getDocument();
+
+ if(rDocument.hasSvgStyleAttributesById())
+ {
+ rtl::OUString aId(rtl::OUString::createFromAscii("."));
+ aId = aId + *mrOwner.getClass();
+
+ const SvgStyleAttributes* pNew = rDocument.findSvgStyleAttributesById(aId);
+
+ if(!pNew)
+ {
+ aId = rClassStr + aId;
+
+ pNew = rDocument.findSvgStyleAttributesById(aId);
+ }
+
+ if(pNew)
+ {
+ // found css style, set as parent
+ const_cast< SvgStyleAttributes* >(this)->mpCssStyleParent = pNew;
+ }
+ }
+ }
+ }
+
+ const SvgStyleAttributes* SvgStyleAttributes::getParentStyle() const
+ {
+ if(mpCssStyleParent)
+ {
+ return mpCssStyleParent;
+ }
+
+ if(mrOwner.getParent())
+ {
+ return mrOwner.getParent()->getSvgStyleAttributes();
+ }
+
+ return 0;
+ }
+
+ void SvgStyleAttributes::add_text(
+ drawinglayer::primitive2d::Primitive2DVector& rTarget,
+ drawinglayer::primitive2d::Primitive2DVector& rSource) const
+ {
+ if(!rSource.empty())
+ {
+ // at this point the primitives in rSource are of type TextSimplePortionPrimitive2D
+ // or TextDecoratedPortionPrimitive2D and have the Fill Color (pAttributes->getFill())
+ // set. When another fill is used and also evtl. stroke is set it gets necessary to
+ // dismantle to geometry and add needed primitives
+ const basegfx::BColor* pFill = getFill();
+ const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
+ const basegfx::BColor* pStroke = getStroke();
+ const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
+ basegfx::B2DPolyPolygon aMergedArea;
+
+ // put primitives into Primitive2DSequence to have clear owner definitions
+ const drawinglayer::primitive2d::Primitive2DSequence aSeq(drawinglayer::primitive2d::Primitive2DVectorToPrimitive2DSequence(rSource));
+
+ if(pFillGradient || pStroke || pStrokeGradient)
+ {
+ // text geometry is needed, create
+ // use neutral ViewInformation and create LineGeometryExtractor2D
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::TextAsPolygonExtractor2D aExtractor(aViewInformation2D);
+
+ // proccess
+ aExtractor.process(aSeq);
+
+ // get results
+ const drawinglayer::processor2d::TextAsPolygonDataNodeVector& rResult = aExtractor.getTarget();
+ const sal_uInt32 nResultCount(rResult.size());
+ basegfx::B2DPolyPolygonVector aTextFillVector;
+ aTextFillVector.reserve(nResultCount);
+
+ for(sal_uInt32 a(0); a < nResultCount; a++)
+ {
+ const drawinglayer::processor2d::TextAsPolygonDataNode& rCandidate = rResult[a];
+
+ if(rCandidate.getIsFilled())
+ {
+ aTextFillVector.push_back(rCandidate.getB2DPolyPolygon());
+ }
+ }
+
+ if(!aTextFillVector.empty())
+ {
+ aMergedArea = basegfx::tools::mergeToSinglePolyPolygon(aTextFillVector);
+ }
+ }
+
+ const bool bStrokeUsed(pStroke || pStrokeGradient);
+
+ // add fill. Use geometry even for simple color fill when stroke
+ // is used, else text rendering and the geometry-based stroke will
+ // normally not really match optically due to divrese system text
+ // renderers
+ if(aMergedArea.count() && (pFillGradient || bStrokeUsed))
+ {
+ // create text fill content based on geometry
+ add_fill(aMergedArea, rTarget, aMergedArea.getB2DRange());
+ }
+ else if(pFill)
+ {
+ // add the already prepared primitives for single color fill
+ rTarget.push_back(new drawinglayer::primitive2d::GroupPrimitive2D(aSeq));
+ }
+
+ // add stroke
+ if(aMergedArea.count() && bStrokeUsed)
+ {
+ // create text stroke content
+ add_stroke(aMergedArea, rTarget, aMergedArea.getB2DRange());
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_fillGradient(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DVector& rTarget,
+ const SvgGradientNode& rFillGradient,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ // create fill content
+ drawinglayer::primitive2d::SvgGradientEntryVector aSvgGradientEntryVector;
+
+ // get the color stops
+ rFillGradient.collectGradientEntries(aSvgGradientEntryVector);
+
+ if(!aSvgGradientEntryVector.empty())
+ {
+ basegfx::B2DHomMatrix aGeoToUnit;
+
+ if(rFillGradient.getGradientTransform())
+ {
+ aGeoToUnit = *rFillGradient.getGradientTransform();
+ }
+
+ if(userSpaceOnUse == rFillGradient.getGradientUnits())
+ {
+ aGeoToUnit.translate(-rGeoRange.getMinX(), -rGeoRange.getMinY());
+ aGeoToUnit.scale(1.0 / rGeoRange.getWidth(), 1.0 / rGeoRange.getHeight());
+ }
+
+ if(SVGTokenLinearGradient == rFillGradient.getType())
+ {
+ basegfx::B2DPoint aStart(0.0, 0.0);
+ basegfx::B2DPoint aEnd(1.0, 0.0);
+
+ if(userSpaceOnUse == rFillGradient.getGradientUnits())
+ {
+ // all possible units
+ aStart.setX(rFillGradient.getX1().solve(mrOwner, xcoordinate));
+ aStart.setY(rFillGradient.getY1().solve(mrOwner, ycoordinate));
+ aEnd.setX(rFillGradient.getX2().solve(mrOwner, xcoordinate));
+ aEnd.setY(rFillGradient.getY2().solve(mrOwner, ycoordinate));
+ }
+ else
+ {
+ // fractions or percent relative to object bounds
+ const SvgNumber X1(rFillGradient.getX1());
+ const SvgNumber Y1(rFillGradient.getY1());
+ const SvgNumber X2(rFillGradient.getX2());
+ const SvgNumber Y2(rFillGradient.getY2());
+
+ aStart.setX(Unit_percent == X1.getUnit() ? X1.getNumber() * 0.01 : X1.getNumber());
+ aStart.setY(Unit_percent == Y1.getUnit() ? Y1.getNumber() * 0.01 : Y1.getNumber());
+ aEnd.setX(Unit_percent == X2.getUnit() ? X2.getNumber() * 0.01 : X2.getNumber());
+ aEnd.setY(Unit_percent == Y2.getUnit() ? Y2.getNumber() * 0.01 : Y2.getNumber());
+ }
+
+ if(!aGeoToUnit.isIdentity())
+ {
+ aStart *= aGeoToUnit;
+ aEnd *= aGeoToUnit;
+ }
+
+ rTarget.push_back(
+ new drawinglayer::primitive2d::SvgLinearGradientPrimitive2D(
+ rPath,
+ aSvgGradientEntryVector,
+ aStart,
+ aEnd,
+ rFillGradient.getSpreadMethod()));
+ }
+ else
+ {
+ basegfx::B2DPoint aStart(0.5, 0.5);
+ basegfx::B2DPoint aFocal;
+ double fRadius(0.5);
+ const SvgNumber* pFx = rFillGradient.getFx();
+ const SvgNumber* pFy = rFillGradient.getFy();
+ const bool bFocal(pFx || pFy);
+
+ if(userSpaceOnUse == rFillGradient.getGradientUnits())
+ {
+ // all possible units
+ aStart.setX(rFillGradient.getCx().solve(mrOwner, xcoordinate));
+ aStart.setY(rFillGradient.getCy().solve(mrOwner, ycoordinate));
+ fRadius = rFillGradient.getR().solve(mrOwner, length);
+
+ if(bFocal)
+ {
+ aFocal.setX(pFx ? pFx->solve(mrOwner, xcoordinate) : aStart.getX());
+ aFocal.setY(pFy ? pFy->solve(mrOwner, ycoordinate) : aStart.getY());
+ }
+ }
+ else
+ {
+ // fractions or percent relative to object bounds
+ const SvgNumber Cx(rFillGradient.getCx());
+ const SvgNumber Cy(rFillGradient.getCy());
+ const SvgNumber R(rFillGradient.getR());
+
+ aStart.setX(Unit_percent == Cx.getUnit() ? Cx.getNumber() * 0.01 : Cx.getNumber());
+ aStart.setY(Unit_percent == Cy.getUnit() ? Cy.getNumber() * 0.01 : Cy.getNumber());
+ fRadius = (Unit_percent == R.getUnit()) ? R.getNumber() * 0.01 : R.getNumber();
+
+ if(bFocal)
+ {
+ aFocal.setX(pFx ? (Unit_percent == pFx->getUnit() ? pFx->getNumber() * 0.01 : pFx->getNumber()) : aStart.getX());
+ aFocal.setY(pFy ? (Unit_percent == pFy->getUnit() ? pFy->getNumber() * 0.01 : pFy->getNumber()) : aStart.getY());
+ }
+ }
+
+ if(!aGeoToUnit.isIdentity())
+ {
+ aStart *= aGeoToUnit;
+ fRadius = (aGeoToUnit * basegfx::B2DVector(fRadius, 0.0)).getLength();
+
+ if(bFocal)
+ {
+ aFocal *= aGeoToUnit;
+ }
+ }
+
+ rTarget.push_back(
+ new drawinglayer::primitive2d::SvgRadialGradientPrimitive2D(
+ rPath,
+ aSvgGradientEntryVector,
+ aStart,
+ fRadius,
+ rFillGradient.getSpreadMethod(),
+ bFocal ? &aFocal : 0));
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_fill(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DVector& rTarget,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ const basegfx::BColor* pFill = getFill();
+ const SvgGradientNode* pFillGradient = getSvgGradientNodeFill();
+
+ if(pFill || pFillGradient)
+ {
+ const double fFillOpacity(getFillOpacity().solve(mrOwner, length));
+
+ if(basegfx::fTools::more(fFillOpacity, 0.0))
+ {
+ drawinglayer::primitive2d::Primitive2DVector aNewFill;
+
+ if(pFillGradient)
+ {
+ // create fill content with SVG gradient primitive
+ add_fillGradient(rPath, aNewFill, *pFillGradient, rGeoRange);
+ }
+ else // if(pFill)
+ {
+ // create fill content
+ aNewFill.push_back(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
+ rPath,
+ *pFill));
+ }
+
+ if(!aNewFill.empty())
+ {
+ if(basegfx::fTools::less(fFillOpacity, 1.0))
+ {
+ // embed in UnifiedTransparencePrimitive2D
+ rTarget.push_back(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ Primitive2DVectorToPrimitive2DSequence(aNewFill),
+ 1.0 - fFillOpacity));
+ }
+ else
+ {
+ // append
+ rTarget.insert(rTarget.end(), aNewFill.begin(), aNewFill.end());
+ }
+ }
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_stroke(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DVector& rTarget,
+ const basegfx::B2DRange& rGeoRange) const
+ {
+ const basegfx::BColor* pStroke = getStroke();
+ const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke();
+
+ if(pStroke || pStrokeGradient)
+ {
+ drawinglayer::primitive2d::Primitive2DVector aNewStroke;
+ const double fStrokeOpacity(getStrokeOpacity().solve(mrOwner, length));
+
+ if(basegfx::fTools::more(fStrokeOpacity, 0.0))
+ {
+ // get stroke width; SVG does not use 0.0 == hairline, so 0.0 is no line at all
+ const double fStrokeWidth(getStrokeWidth().isSet() ? getStrokeWidth().solve(mrOwner, length) : 1.0);
+
+ if(basegfx::fTools::more(fStrokeWidth, 0.0))
+ {
+ // get LineJoin and stroke array
+ const basegfx::B2DLineJoin aB2DLineJoin(StrokeLinejoinToB2DLineJoin(getStrokeLinejoin()));
+ ::std::vector< double > aDashArray;
+
+ if(!getStrokeDasharray().empty())
+ {
+ aDashArray = solveSvgNumberVector(getStrokeDasharray(), mrOwner, length);
+ }
+
+ // todo: Handle getStrokeDashOffset()
+ // todo: Handle getStrokeLinecap()
+
+ // prepare line attribute
+ drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D* pNewLinePrimitive = 0;
+ const drawinglayer::attribute::LineAttribute aLineAttribute(
+ pStroke ? *pStroke : basegfx::BColor(0.0, 0.0, 0.0),
+ fStrokeWidth,
+ aB2DLineJoin);
+
+ if(aDashArray.empty())
+ {
+ pNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ rPath,
+ aLineAttribute);
+ }
+ else
+ {
+ const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashArray);
+
+ pNewLinePrimitive = new drawinglayer::primitive2d::PolyPolygonStrokePrimitive2D(
+ rPath,
+ aLineAttribute,
+ aDashArray);
+ }
+
+ if(pStrokeGradient)
+ {
+ // put primitive into Primitive2DReference and Primitive2DSequence
+ const drawinglayer::primitive2d::Primitive2DReference aRef(pNewLinePrimitive);
+ const drawinglayer::primitive2d::Primitive2DSequence aSeq(&aRef, 1);
+
+ // use neutral ViewInformation and create LineGeometryExtractor2D
+ const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::LineGeometryExtractor2D aExtractor(aViewInformation2D);
+
+ // proccess
+ aExtractor.process(aSeq);
+
+ // check for fill rsults
+ const basegfx::B2DPolyPolygonVector& rLineFillVector(aExtractor.getExtractedLineFills());
+
+ if(!aExtractor.getExtractedLineFills().empty())
+ {
+ const basegfx::B2DPolyPolygon aMergedArea(
+ basegfx::tools::mergeToSinglePolyPolygon(
+ aExtractor.getExtractedLineFills()));
+
+ if(aMergedArea.count())
+ {
+ // create fill content with SVG gradient primitive
+ add_fillGradient(aMergedArea, aNewStroke, *pStrokeGradient, rGeoRange);
+ }
+ }
+ }
+ else // if(pStroke)
+ {
+ aNewStroke.push_back(pNewLinePrimitive);
+ }
+
+ if(!aNewStroke.empty())
+ {
+ if(basegfx::fTools::less(fStrokeOpacity, 1.0))
+ {
+ // embed in UnifiedTransparencePrimitive2D
+ rTarget.push_back(
+ new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
+ Primitive2DVectorToPrimitive2DSequence(aNewStroke),
+ 1.0 - fStrokeOpacity));
+ }
+ else
+ {
+ // append
+ rTarget.insert(rTarget.end(), aNewStroke.begin(), aNewStroke.end());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void SvgStyleAttributes::add_path(
+ const basegfx::B2DPolyPolygon& rPath,
+ drawinglayer::primitive2d::Primitive2DVector& rTarget,
+ const basegfx::B2DHomMatrix* pTransform) const
+ {
+ const bool bIsLine(1 == rPath.count()
+ && !rPath.areControlPointsUsed()
+ && 2 == rPath.getB2DPolygon(0).count());
+
+ if(!rPath.count())
+ {
+ return;
+ }
+
+ const basegfx::B2DRange aGeoRange(rPath.getB2DRange());
+
+ if(aGeoRange.isEmpty())
+ {
+ return;
+ }
+
+ if(!bIsLine && // not for lines
+ (basegfx::fTools::equalZero(aGeoRange.getWidth())
+ || basegfx::fTools::equalZero(aGeoRange.getHeight())))
+ {
+ return;
+ }
+
+ drawinglayer::primitive2d::Primitive2DVector aNewPrimitives;
+
+ if(!bIsLine)
+ {
+ add_fill(rPath, aNewPrimitives, aGeoRange);
+ }
+
+ add_stroke(rPath, aNewPrimitives, aGeoRange);
+
+ if(pTransform && !aNewPrimitives.empty())
+ {
+ // embed in transformation
+ rTarget.push_back(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ *pTransform,
+ Primitive2DVectorToPrimitive2DSequence(aNewPrimitives)));
+ }
+ else
+ {
+ // just append
+ rTarget.insert(rTarget.end(), aNewPrimitives.begin(), aNewPrimitives.end());
+ }
+ }
+
+ SvgStyleAttributes::SvgStyleAttributes(SvgNode& rOwner)
+ : mrOwner(rOwner),
+ mpCssStyleParent(0),
+ maFill(),
+ maStroke(),
+ maStopColor(basegfx::BColor(0.0, 0.0, 0.0), true),
+ maStrokeWidth(),
+ maStopOpacity(),
+ mpSvgGradientNodeFill(0),
+ mpSvgGradientNodeStroke(0),
+ maFillOpacity(),
+ maStrokeDasharray(),
+ maStrokeDashOffset(),
+ maStrokeLinecap(StrokeLinecap_notset),
+ maStrokeLinejoin(StrokeLinejoin_notset),
+ maStrokeMiterLimit(),
+ maStrokeOpacity(),
+ maFontFamily(),
+ maFontSize(),
+ maFontStretch(FontStretch_notset),
+ maFontStyle(FontStyle_notset),
+ maFontVariant(FontVariant_notset),
+ maFontWeight(FontWeight_notset),
+ maTextAlign(TextAlign_notset),
+ maTextDecoration(TextDecoration_notset),
+ maTextAnchor(TextAnchor_notset),
+
+ maFillRule(true),
+ maFillRuleSet(false)
+ {
+ }
+
+ SvgStyleAttributes::~SvgStyleAttributes()
+ {
+ }
+
+ void SvgStyleAttributes::parseStyleAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ switch(aSVGToken)
+ {
+ case SVGTokenFill:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setFill(aSvgPaint);
+ }
+ else if(aURL.getLength())
+ {
+ const SvgGradientNode* pNode = dynamic_cast< const SvgGradientNode* >(mrOwner.getDocument().findSvgNodeById(aURL));
+
+ if(pNode)
+ {
+ setSvgGradientNodeFill(pNode);
+ }
+ }
+ break;
+ }
+ case SVGTokenFillOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setFillOpacity(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenFillRule:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNonzero(rtl::OUString::createFromAscii("nonzero"));
+ static rtl::OUString aStrEvenOdd(rtl::OUString::createFromAscii("evenodd"));
+
+ if(aContent.match(aStrNonzero))
+ {
+ maFillRule = true;
+ maFillRuleSet = true;
+ }
+ else if(aContent.match(aStrEvenOdd))
+ {
+ maFillRule = false;
+ maFillRuleSet = true;
+ }
+ }
+ break;
+ }
+ case SVGTokenStroke:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setStroke(aSvgPaint);
+ }
+ else if(aURL.getLength())
+ {
+ const SvgGradientNode* pNode = dynamic_cast< const SvgGradientNode* >(mrOwner.getDocument().findSvgNodeById(aURL));
+
+ if(pNode)
+ {
+ setSvgGradientNodeStroke(pNode);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeDasharray:
+ {
+ if(aContent.getLength())
+ {
+ SvgNumberVector aVector;
+
+ if(readSvgNumberVector(aContent, aVector))
+ {
+ setStrokeDasharray(aVector);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeDashoffset:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeDashOffset(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeLinecap:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrButt(rtl::OUString::createFromAscii("butt"));
+ static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
+ static rtl::OUString aStrSquare(rtl::OUString::createFromAscii("square"));
+
+ if(aContent.match(aStrButt))
+ {
+ setStrokeLinecap(StrokeLinecap_butt);
+ }
+ else if(aContent.match(aStrRound))
+ {
+ setStrokeLinecap(StrokeLinecap_round);
+ }
+ else if(aContent.match(aStrSquare))
+ {
+ setStrokeLinecap(StrokeLinecap_square);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeLinejoin:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrMiter(rtl::OUString::createFromAscii("miter"));
+ static rtl::OUString aStrRound(rtl::OUString::createFromAscii("round"));
+ static rtl::OUString aStrBevel(rtl::OUString::createFromAscii("bevel"));
+
+ if(aContent.match(aStrMiter))
+ {
+ setStrokeLinejoin(StrokeLinejoin_miter);
+ }
+ else if(aContent.match(aStrRound))
+ {
+ setStrokeLinejoin(StrokeLinejoin_round);
+ }
+ else if(aContent.match(aStrBevel))
+ {
+ setStrokeLinejoin(StrokeLinejoin_bevel);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeMiterlimit:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeMiterLimit(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeOpacity(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStrokeWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStrokeWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenStopColor:
+ {
+ SvgPaint aSvgPaint;
+ rtl::OUString aURL;
+
+ if(readSvgPaint(aContent, aSvgPaint, aURL))
+ {
+ setStopColor(aSvgPaint);
+ }
+ break;
+ }
+ case SVGTokenStopOpacity:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setStopOpacity(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenFont:
+ {
+ bool bBla = true;
+ break;
+ }
+ case SVGTokenFontFamily:
+ {
+ SvgStringVector aSvgStringVector;
+
+ if(readSvgStringVector(aContent, aSvgStringVector))
+ {
+ setFontFamily(aSvgStringVector);
+ }
+ break;
+ }
+ case SVGTokenFontSize:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setFontSize(aNum);
+ }
+ break;
+ }
+ case SVGTokenFontSizeAdjust:
+ {
+ bool bBla = true;
+ break;
+ }
+ case SVGTokenFontStretch:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrWider(rtl::OUString::createFromAscii("wider"));
+ static rtl::OUString aStrNarrower(rtl::OUString::createFromAscii("narrower"));
+ static rtl::OUString aStrUltra_condensed(rtl::OUString::createFromAscii("ultra-condensed"));
+ static rtl::OUString aStrExtra_condensed(rtl::OUString::createFromAscii("extra-condensed"));
+ static rtl::OUString aStrCondensed(rtl::OUString::createFromAscii("condensed"));
+ static rtl::OUString aStrSemi_condensed(rtl::OUString::createFromAscii("semi-condensed"));
+ static rtl::OUString aStrSemi_expanded(rtl::OUString::createFromAscii("semi-expanded"));
+ static rtl::OUString aStrExpanded(rtl::OUString::createFromAscii("expanded"));
+ static rtl::OUString aStrExtra_expanded(rtl::OUString::createFromAscii("extra-expanded"));
+ static rtl::OUString aStrUltra_expanded(rtl::OUString::createFromAscii("ultra-expanded"));
+
+ if(aContent.match(aStrNormal))
+ {
+ setFontStretch(FontStretch_normal);
+ }
+ else if(aContent.match(aStrWider))
+ {
+ setFontStretch(FontStretch_wider);
+ }
+ else if(aContent.match(aStrNarrower))
+ {
+ setFontStretch(FontStretch_narrower);
+ }
+ else if(aContent.match(aStrUltra_condensed))
+ {
+ setFontStretch(FontStretch_ultra_condensed);
+ }
+ else if(aContent.match(aStrExtra_condensed))
+ {
+ setFontStretch(FontStretch_extra_condensed);
+ }
+ else if(aContent.match(aStrCondensed))
+ {
+ setFontStretch(FontStretch_condensed);
+ }
+ else if(aContent.match(aStrSemi_condensed))
+ {
+ setFontStretch(FontStretch_semi_condensed);
+ }
+ else if(aContent.match(aStrSemi_expanded))
+ {
+ setFontStretch(FontStretch_semi_expanded);
+ }
+ else if(aContent.match(aStrExpanded))
+ {
+ setFontStretch(FontStretch_expanded);
+ }
+ else if(aContent.match(aStrExtra_expanded))
+ {
+ setFontStretch(FontStretch_extra_expanded);
+ }
+ else if(aContent.match(aStrUltra_expanded))
+ {
+ setFontStretch(FontStretch_ultra_expanded);
+ }
+ }
+ break;
+ }
+ case SVGTokenFontStyle:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrItalic(rtl::OUString::createFromAscii("italic"));
+ static rtl::OUString aStrOblique(rtl::OUString::createFromAscii("oblique"));
+
+ if(aContent.match(aStrNormal))
+ {
+ setFontStyle(FontStyle_normal);
+ }
+ else if(aContent.match(aStrItalic))
+ {
+ setFontStyle(FontStyle_italic);
+ }
+ else if(aContent.match(aStrOblique))
+ {
+ setFontStyle(FontStyle_oblique);
+ }
+ }
+ break;
+ }
+ case SVGTokenFontVariant:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrSmallCaps(rtl::OUString::createFromAscii("small-caps"));
+
+ if(aContent.match(aStrNormal))
+ {
+ setFontVariant(FontVariant_normal);
+ }
+ else if(aContent.match(aStrSmallCaps))
+ {
+ setFontVariant(FontVariant_small_caps);
+ }
+ }
+ break;
+ }
+ case SVGTokenFontWeight:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNormal(rtl::OUString::createFromAscii("normal"));
+ static rtl::OUString aStrBold(rtl::OUString::createFromAscii("bold"));
+ static rtl::OUString aStrBolder(rtl::OUString::createFromAscii("bolder"));
+ static rtl::OUString aStrLighter(rtl::OUString::createFromAscii("lighter"));
+ static rtl::OUString aStr100(rtl::OUString::createFromAscii("100"));
+ static rtl::OUString aStr200(rtl::OUString::createFromAscii("200"));
+ static rtl::OUString aStr300(rtl::OUString::createFromAscii("300"));
+ static rtl::OUString aStr400(rtl::OUString::createFromAscii("400"));
+ static rtl::OUString aStr500(rtl::OUString::createFromAscii("500"));
+ static rtl::OUString aStr600(rtl::OUString::createFromAscii("600"));
+ static rtl::OUString aStr700(rtl::OUString::createFromAscii("700"));
+ static rtl::OUString aStr800(rtl::OUString::createFromAscii("800"));
+ static rtl::OUString aStr900(rtl::OUString::createFromAscii("900"));
+
+ if(aContent.match(aStr100))
+ {
+ setFontWeight(FontWeight_100);
+ }
+ else if(aContent.match(aStr200))
+ {
+ setFontWeight(FontWeight_200);
+ }
+ else if(aContent.match(aStr300))
+ {
+ setFontWeight(FontWeight_300);
+ }
+ else if(aContent.match(aStr400) || aContent.match(aStrNormal))
+ {
+ setFontWeight(FontWeight_400);
+ }
+ else if(aContent.match(aStr500))
+ {
+ setFontWeight(FontWeight_500);
+ }
+ else if(aContent.match(aStr600))
+ {
+ setFontWeight(FontWeight_600);
+ }
+ else if(aContent.match(aStr700) || aContent.match(aStrBold))
+ {
+ setFontWeight(FontWeight_700);
+ }
+ else if(aContent.match(aStr800))
+ {
+ setFontWeight(FontWeight_800);
+ }
+ else if(aContent.match(aStr900))
+ {
+ setFontWeight(FontWeight_900);
+ }
+ else if(aContent.match(aStrBolder))
+ {
+ setFontWeight(FontWeight_bolder);
+ }
+ else if(aContent.match(aStrLighter))
+ {
+ setFontWeight(FontWeight_lighter);
+ }
+ }
+ break;
+ }
+ case SVGTokenDirection:
+ {
+ bool bBla = true;
+ break;
+ }
+ case SVGTokenLetterSpacing:
+ {
+ bool bBla = true;
+ break;
+ }
+ case SVGTokenTextDecoration:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrNone(rtl::OUString::createFromAscii("none"));
+ static rtl::OUString aStrUnderline(rtl::OUString::createFromAscii("underline"));
+ static rtl::OUString aStrOverline(rtl::OUString::createFromAscii("overline"));
+ static rtl::OUString aStrLineThrough(rtl::OUString::createFromAscii("line-through"));
+ static rtl::OUString aStrBlink(rtl::OUString::createFromAscii("blink"));
+
+ if(aContent.match(aStrNone))
+ {
+ setTextDecoration(TextDecoration_none);
+ }
+ else if(aContent.match(aStrUnderline))
+ {
+ setTextDecoration(TextDecoration_underline);
+ }
+ else if(aContent.match(aStrOverline))
+ {
+ setTextDecoration(TextDecoration_overline);
+ }
+ else if(aContent.match(aStrLineThrough))
+ {
+ setTextDecoration(TextDecoration_line_through);
+ }
+ else if(aContent.match(aStrBlink))
+ {
+ setTextDecoration(TextDecoration_blink);
+ }
+ }
+ break;
+ }
+ case SVGTokenUnicodeBidi:
+ {
+ bool bBla = true;
+ break;
+ }
+ case SVGTokenWordSpacing:
+ {
+ bool bBla = true;
+ break;
+ }
+ case SVGTokenTextAnchor:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrStart(rtl::OUString::createFromAscii("start"));
+ static rtl::OUString aStrMiddle(rtl::OUString::createFromAscii("middle"));
+ static rtl::OUString aStrEnd(rtl::OUString::createFromAscii("end"));
+
+ if(aContent.match(aStrStart))
+ {
+ setTextAnchor(TextAnchor_start);
+ }
+ else if(aContent.match(aStrMiddle))
+ {
+ setTextAnchor(TextAnchor_middle);
+ }
+ else if(aContent.match(aStrEnd))
+ {
+ setTextAnchor(TextAnchor_end);
+ }
+ }
+ break;
+ }
+ case SVGTokenTextAlign:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrLeft(rtl::OUString::createFromAscii("left"));
+ static rtl::OUString aStrRight(rtl::OUString::createFromAscii("right"));
+ static rtl::OUString aStrCenter(rtl::OUString::createFromAscii("center"));
+ static rtl::OUString aStrJustify(rtl::OUString::createFromAscii("justify"));
+
+ if(aContent.match(aStrLeft))
+ {
+ setTextAlign(TextAlign_left);
+ }
+ else if(aContent.match(aStrRight))
+ {
+ setTextAlign(TextAlign_right);
+ }
+ else if(aContent.match(aStrCenter))
+ {
+ setTextAlign(TextAlign_center);
+ }
+ else if(aContent.match(aStrJustify))
+ {
+ setTextAlign(TextAlign_justify);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ const basegfx::BColor* SvgStyleAttributes::getFill() const
+ {
+ if(maFill.isSet())
+ {
+ if(maFill.isOn())
+ {
+ return &maFill.getBColor();
+ }
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFill();
+ }
+ }
+
+ return 0;
+ }
+
+ const basegfx::BColor* SvgStyleAttributes::getStroke() const
+ {
+ if(maStroke.isSet())
+ {
+ if(maStroke.isOn())
+ {
+ return &maStroke.getBColor();
+ }
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStroke();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeFill() const
+ {
+ if(mpSvgGradientNodeFill)
+ {
+ return mpSvgGradientNodeFill;
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getSvgGradientNodeFill();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgGradientNode* SvgStyleAttributes::getSvgGradientNodeStroke() const
+ {
+ if(mpSvgGradientNodeStroke)
+ {
+ return mpSvgGradientNodeStroke;
+ }
+ else
+ {
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getSvgGradientNodeStroke();
+ }
+ }
+
+ return 0;
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeWidth() const
+ {
+ if(maStrokeWidth.isSet())
+ {
+ return maStrokeWidth;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeWidth();
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ const SvgNumber SvgStyleAttributes::getStopOpacity() const
+ {
+ if(maStopOpacity.isSet())
+ {
+ return maStopOpacity;
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ const SvgNumber SvgStyleAttributes::getFillOpacity() const
+ {
+ if(maFillOpacity.isSet())
+ {
+ return maFillOpacity;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFillOpacity();
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ bool SvgStyleAttributes::getFillRule() const
+ {
+ if(maFillRuleSet)
+ {
+ return maFillRule;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFillRule();
+ }
+
+ // default is NonZero
+ return true;
+ }
+
+ void SvgStyleAttributes::setFillRule(const bool* pFillRule)
+ {
+ if(pFillRule)
+ {
+ maFillRuleSet = true;
+ maFillRule = *pFillRule;
+ }
+ else
+ {
+ maFillRuleSet = false;
+ }
+ }
+
+ const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
+ {
+ if(!maStrokeDasharray.empty())
+ {
+ return maStrokeDasharray;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeDasharray();
+ }
+
+ // default empty
+ return maStrokeDasharray;
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeDashOffset() const
+ {
+ if(maStrokeDashOffset.isSet())
+ {
+ return maStrokeDashOffset;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeDashOffset();
+ }
+
+ // default is 0
+ return SvgNumber(0.0);
+ }
+
+ const StrokeLinecap SvgStyleAttributes::getStrokeLinecap() const
+ {
+ if(maStrokeLinecap != StrokeLinecap_notset)
+ {
+ return maStrokeLinecap;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeLinecap();
+ }
+
+ // default is StrokeLinecap_butt
+ return StrokeLinecap_butt;
+ }
+
+ const StrokeLinejoin SvgStyleAttributes::getStrokeLinejoin() const
+ {
+ if(maStrokeLinejoin != StrokeLinejoin_notset)
+ {
+ return maStrokeLinejoin;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeLinejoin();
+ }
+
+ // default is StrokeLinejoin_butt
+ return StrokeLinejoin_miter;
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeMiterLimit() const
+ {
+ if(maStrokeMiterLimit.isSet())
+ {
+ return maStrokeMiterLimit;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeMiterLimit();
+ }
+
+ // default is 4
+ return SvgNumber(4.0);
+ }
+
+ const SvgNumber SvgStyleAttributes::getStrokeOpacity() const
+ {
+ if(maStrokeOpacity.isSet())
+ {
+ return maStrokeOpacity;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getStrokeOpacity();
+ }
+
+ // default is 1
+ return SvgNumber(1.0);
+ }
+
+ const SvgStringVector& SvgStyleAttributes::getFontFamily() const
+ {
+ if(!maFontFamily.empty())
+ {
+ return maFontFamily;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFontFamily();
+ }
+
+ // default is empty
+ return maFontFamily;
+ }
+
+ const SvgNumber SvgStyleAttributes::getFontSize() const
+ {
+ if(maFontSize.isSet())
+ {
+ return maFontSize;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFontSize();
+ }
+
+ // default is 'medium'
+ return SvgNumber(12.0);
+ }
+
+ const FontStretch SvgStyleAttributes::getFontStretch() const
+ {
+ if(maFontStretch != FontStretch_notset)
+ {
+ if(FontStretch_wider != maFontStretch && FontStretch_narrower != maFontStretch)
+ {
+ return maFontStretch;
+ }
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ FontStretch aInherited = pSvgStyleAttributes->getFontStretch();
+
+ if(FontStretch_wider == maFontStretch)
+ {
+ aInherited = getWider(aInherited);
+ }
+ else if(FontStretch_narrower == maFontStretch)
+ {
+ aInherited = getNarrower(aInherited);
+ }
+
+ return aInherited;
+ }
+
+ // default is FontStretch_normal
+ return FontStretch_normal;
+ }
+
+ const FontStyle SvgStyleAttributes::getFontStyle() const
+ {
+ if(maFontStyle != FontStyle_notset)
+ {
+ return maFontStyle;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getFontStyle();
+ }
+
+ // default is FontStyle_normal
+ return FontStyle_normal;
+ }
+
+ const FontWeight SvgStyleAttributes::getFontWeight() const
+ {
+ if(maFontWeight != FontWeight_notset)
+ {
+ if(FontWeight_bolder != maFontWeight && FontWeight_lighter != maFontWeight)
+ {
+ return maFontWeight;
+ }
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ FontWeight aInherited = pSvgStyleAttributes->getFontWeight();
+
+ if(FontWeight_bolder == maFontWeight)
+ {
+ aInherited = getBolder(aInherited);
+ }
+ else if(FontWeight_lighter == maFontWeight)
+ {
+ aInherited = getLighter(aInherited);
+ }
+
+ return aInherited;
+ }
+
+ // default is FontWeight_400 (FontWeight_normal)
+ return FontWeight_400;
+ }
+
+ const TextAlign SvgStyleAttributes::getTextAlign() const
+ {
+ if(maTextAlign != TextAlign_notset)
+ {
+ return maTextAlign;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getTextAlign();
+ }
+
+ // default is TextAlign_left
+ return TextAlign_left;
+ }
+
+ const SvgStyleAttributes* SvgStyleAttributes::getTextDecorationDefiningSvgStyleAttributes() const
+ {
+ if(maTextDecoration != TextDecoration_notset)
+ {
+ return this;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getTextDecorationDefiningSvgStyleAttributes();
+ }
+
+ // default is 0
+ return 0;
+ }
+
+ const TextDecoration SvgStyleAttributes::getTextDecoration() const
+ {
+ const SvgStyleAttributes* pDefining = getTextDecorationDefiningSvgStyleAttributes();
+
+ if(pDefining)
+ {
+ return pDefining->maTextDecoration;
+ }
+ else
+ {
+ // default is TextDecoration_none
+ return TextDecoration_none;
+ }
+ }
+
+ const TextAnchor SvgStyleAttributes::getTextAnchor() const
+ {
+ if(maTextAnchor != TextAnchor_notset)
+ {
+ return maTextAnchor;
+ }
+
+ const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+ if(pSvgStyleAttributes)
+ {
+ return pSvgStyleAttributes->getTextAnchor();
+ }
+
+ // default is TextAnchor_start
+ return TextAnchor_start;
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
Added: incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstylenode.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstylenode.cxx?rev=1209140&view=auto
==============================================================================
--- incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstylenode.cxx (added)
+++ incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgstylenode.cxx Thu Dec 1 16:25:17 2011
@@ -0,0 +1,114 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svgio.hxx"
+
+#include <svgio/svgreader/svgstylenode.hxx>
+#include <svgio/svgreader/svgdocument.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgStyleNode::SvgStyleNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenStyle, rDocument, pParent),
+ maSvgStyleAttributes(),
+ mbTextCss(false)
+ {
+ }
+
+ SvgStyleNode::~SvgStyleNode()
+ {
+ while(!maSvgStyleAttributes.empty())
+ {
+ delete *(maSvgStyleAttributes.end() - 1);
+ maSvgStyleAttributes.pop_back();
+ }
+ }
+
+ void SvgStyleNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenType:
+ {
+ if(aContent.getLength())
+ {
+ static rtl::OUString aStrTextCss(rtl::OUString::createFromAscii("text/css"));
+
+ if(aContent.match(aStrTextCss))
+ {
+ setTextCss(true);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ void SvgStyleNode::addCssStyleSheet(const rtl::OUString& aContent)
+ {
+ const sal_Int32 nLen(aContent.getLength());
+
+ if(nLen)
+ {
+ sal_Int32 nPos(0);
+ rtl::OUStringBuffer aTokenValue;
+
+ copyToLimiter(aContent, sal_Unicode('{'), nPos, aTokenValue, nLen);
+ const rtl::OUString aStyleName = aTokenValue.makeStringAndClear().trim();
+
+ if(aStyleName.getLength())
+ {
+ skip_char(aContent, sal_Unicode(' '), sal_Unicode('{'), nPos, nLen);
+ copyToLimiter(aContent, sal_Unicode('}'), nPos, aTokenValue, nLen);
+ const rtl::OUString aStyleContent = aTokenValue.makeStringAndClear().trim();
+
+ if(aStyleContent.getLength())
+ {
+ // create new style
+ SvgStyleAttributes* pNewStyle = new SvgStyleAttributes(*this);
+ maSvgStyleAttributes.push_back(pNewStyle);
+
+ // fill with content
+ pNewStyle->readStyle(aStyleContent);
+
+ // register new style at document
+ const_cast< SvgDocument& >(getDocument()).addSvgStyleAttributesToMapper(aStyleName, *pNewStyle);
+ }
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
Added: incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsvgnode.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsvgnode.cxx?rev=1209140&view=auto
==============================================================================
--- incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsvgnode.cxx (added)
+++ incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsvgnode.cxx Thu Dec 1 16:25:17 2011
@@ -0,0 +1,295 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svgio.hxx"
+
+#include <svgio/svgreader/svgsvgnode.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgSvgNode::SvgSvgNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenSvg, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpViewBox(0),
+ maSvgAspectRatio(),
+ maX(),
+ maY(),
+ maWidth(),
+ maHeight(),
+ maVersion()
+ {
+ if(!getParent())
+ {
+ // initial fill is black
+ maSvgStyleAttributes.setFill(SvgPaint(basegfx::BColor(0.0, 0.0, 0.0), true, true));
+ }
+ }
+
+ SvgSvgNode::~SvgSvgNode()
+ {
+ if(mpViewBox) delete mpViewBox;
+ }
+
+ const SvgStyleAttributes* SvgSvgNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgSvgNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenViewBox:
+ {
+ const basegfx::B2DRange aRange(readViewBox(aContent, *this));
+
+ if(!aRange.isEmpty())
+ {
+ setViewBox(&aRange);
+ }
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ case SVGTokenX:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setX(aNum);
+ }
+ break;
+ }
+ case SVGTokenY:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setY(aNum);
+ }
+ break;
+ }
+ case SVGTokenWidth:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setWidth(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenHeight:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ if(aNum.isPositive())
+ {
+ setHeight(aNum);
+ }
+ }
+ break;
+ }
+ case SVGTokenVersion:
+ {
+ SvgNumber aNum;
+
+ if(readSingleNumber(aContent, aNum))
+ {
+ setVersion(aNum);
+ }
+ break;
+ }
+ }
+ }
+
+ void SvgSvgNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DVector& rTarget, bool bReferenced) const
+ {
+ drawinglayer::primitive2d::Primitive2DVector aNewTarget;
+
+ // decompose childs
+ SvgNode::decomposeSvgNode(aNewTarget, bReferenced);
+
+ if(!aNewTarget.empty())
+ {
+ // pack into Primitive2DSequence to ensure ownership
+ const drawinglayer::primitive2d::Primitive2DSequence aSequence(Primitive2DVectorToPrimitive2DSequence(aNewTarget));
+
+ if(getParent())
+ {
+ if(getViewBox())
+ {
+ // Svg defines that with no width or no height the viewBox content is empty,
+ // so both need to exist
+ if(!basegfx::fTools::equalZero(getViewBox()->getWidth()) && !basegfx::fTools::equalZero(getViewBox()->getHeight()))
+ {
+ // create target range homing x,y, width and height as given
+ const double fX(getX().isSet() ? getX().solve(*this, xcoordinate) : 0.0);
+ const double fY(getY().isSet() ? getY().solve(*this, ycoordinate) : 0.0);
+ const double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : getViewBox()->getWidth());
+ const double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : getViewBox()->getHeight());
+ const basegfx::B2DRange aTarget(fX, fY, fX + fW, fY + fH);
+
+ if(aTarget.equal(*getViewBox()))
+ {
+ // no mapping needed, append
+ rTarget.push_back(
+ new drawinglayer::primitive2d::GroupPrimitive2D(
+ aSequence));
+ }
+ else
+ {
+ // create mapping
+ const SvgAspectRatio& rRatio = getSvgAspectRatio();
+
+ if(rRatio.isSet())
+ {
+ // let mapping be created from SvgAspectRatio
+ const basegfx::B2DHomMatrix aEmbeddingTransform(
+ rRatio.createMapping(aTarget, *getViewBox()));
+
+ // prepare embedding in transformation
+ drawinglayer::primitive2d::TransformPrimitive2D* pNew =
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbeddingTransform,
+ aSequence);
+
+ if(rRatio.isMeetOrSlice())
+ {
+ // embed in transformation
+ rTarget.push_back(pNew);
+ }
+ else
+ {
+ // need to embed in MaskPrimitive2D, too
+ const drawinglayer::primitive2d::Primitive2DReference xRef(pNew);
+
+ rTarget.push_back(
+ new drawinglayer::primitive2d::MaskPrimitive2D(
+ basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aTarget)),
+ drawinglayer::primitive2d::Primitive2DSequence(&xRef, 1)));
+ }
+ }
+ else
+ {
+ // choose default mapping
+ const basegfx::B2DHomMatrix aEmbeddingTransform(
+ rRatio.createLinearMapping(
+ aTarget, *getViewBox()));
+
+ // embed in transformation
+ rTarget.push_back(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aEmbeddingTransform,
+ aSequence));
+ }
+ }
+ }
+ }
+ else
+ {
+ // no viewBox, append
+ rTarget.push_back(
+ new drawinglayer::primitive2d::GroupPrimitive2D(
+ aSequence));
+ }
+ }
+ else
+ {
+ // Outermost SVG element; create target range homing width and height as given.
+ // SVG defines that x,y has no meanig for the outermost SVG element. Use a fallback
+ // width and height of 8x8 cm (8 * 35.43307px)
+ const double fFallbackMetric(8.0 * 35.43307);
+ double fW(getWidth().isSet() ? getWidth().solve(*this, xcoordinate) : fFallbackMetric);
+ double fH(getHeight().isSet() ? getHeight().solve(*this, ycoordinate) : fFallbackMetric);
+
+ // Svg defines that a negative value is an error and that 0.0 disables rendering
+ if(basegfx::fTools::more(fW, 0.0) && basegfx::fTools::more(fH, 0.0))
+ {
+ // append embedded in transform primitive to scale to 1/100th mm
+ // where 1 mm == 3.543307 px
+ const double fScaleTo100thmm(100.0 / 3.543307);
+ basegfx::B2DHomMatrix aTransform(
+ basegfx::tools::createScaleB2DHomMatrix(
+ fScaleTo100thmm,
+ fScaleTo100thmm));
+
+ rTarget.push_back(
+ new drawinglayer::primitive2d::TransformPrimitive2D(
+ aTransform,
+ aSequence));
+ }
+ }
+ }
+ }
+
+ const basegfx::B2DRange* SvgSvgNode::getCurrentViewPort() const
+ {
+ if(getViewBox())
+ {
+ return getViewBox();
+ }
+ else
+ {
+ return SvgNode::getCurrentViewPort();
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
Added: incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsymbolnode.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsymbolnode.cxx?rev=1209140&view=auto
==============================================================================
--- incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsymbolnode.cxx (added)
+++ incubator/ooo/branches/alg/svgreplacement/main/svgio/source/svgreader/svgsymbolnode.cxx Thu Dec 1 16:25:17 2011
@@ -0,0 +1,93 @@
+/**************************************************************
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ *************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_svgio.hxx"
+
+#include <svgio/svgreader/svgsymbolnode.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace svgio
+{
+ namespace svgreader
+ {
+ SvgSymbolNode::SvgSymbolNode(
+ SvgDocument& rDocument,
+ SvgNode* pParent)
+ : SvgNode(SVGTokenSvg, rDocument, pParent),
+ maSvgStyleAttributes(*this),
+ mpViewBox(0),
+ maSvgAspectRatio()
+ {
+ }
+
+ SvgSymbolNode::~SvgSymbolNode()
+ {
+ if(mpViewBox) delete mpViewBox;
+ }
+
+ const SvgStyleAttributes* SvgSymbolNode::getSvgStyleAttributes() const
+ {
+ return &maSvgStyleAttributes;
+ }
+
+ void SvgSymbolNode::parseAttribute(const rtl::OUString& rTokenName, SVGToken aSVGToken, const rtl::OUString& aContent)
+ {
+ // call parent
+ SvgNode::parseAttribute(rTokenName, aSVGToken, aContent);
+
+ // read style attributes
+ maSvgStyleAttributes.parseStyleAttribute(rTokenName, aSVGToken, aContent);
+
+ // parse own
+ switch(aSVGToken)
+ {
+ case SVGTokenStyle:
+ {
+ maSvgStyleAttributes.readStyle(aContent);
+ break;
+ }
+ case SVGTokenViewBox:
+ {
+ const basegfx::B2DRange aRange(readViewBox(aContent, *this));
+
+ if(!aRange.isEmpty())
+ {
+ setViewBox(&aRange);
+ }
+ break;
+ }
+ case SVGTokenPreserveAspectRatio:
+ {
+ setSvgAspectRatio(readSvgAspectRatio(aContent));
+ break;
+ }
+ }
+ }
+
+ } // end of namespace svgreader
+} // end of namespace svgio
+
+//////////////////////////////////////////////////////////////////////////////
+// eof