/************************************************************** * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// using namespace com::sun::star; ////////////////////////////////////////////////////////////////////////////// namespace { svgio::svgreader::SvgCharacterNode* whiteSpaceHandling(svgio::svgreader::SvgNode* pNode, svgio::svgreader::SvgCharacterNode* pLast) { if(pNode) { const svgio::svgreader::SvgNodeVector& rChilds = pNode->getChildren(); const sal_uInt32 nCount(rChilds.size()); for(sal_uInt32 a(0); a < nCount; a++) { svgio::svgreader::SvgNode* pCandidate = rChilds[a]; if(pCandidate) { switch(pCandidate->getType()) { case svgio::svgreader::SVGTokenCharacter: { // clean whitespace in text span svgio::svgreader::SvgCharacterNode* pCharNode = static_cast< svgio::svgreader::SvgCharacterNode* >(pCandidate); pCharNode->whiteSpaceHandling(); // pCharNode may have lost all text. If that's the case, ignore // as invalid character node if(pCharNode->getText().getLength()) { if(pLast) { // add in-between whitespace (single space) to last // known character node pLast->addGap(); } // remember new last corected character node pLast = pCharNode; } break; } case svgio::svgreader::SVGTokenTspan: case svgio::svgreader::SVGTokenTextPath: case svgio::svgreader::SVGTokenTref: { // recursively clean whitespaces in subhierarchy pLast = whiteSpaceHandling(pCandidate, pLast); break; } default: { OSL_ENSURE(false, "Unexpected token inside SVGTokenText (!)"); break; } } } } } return pLast; } } ////////////////////////////////////////////////////////////////////////////// namespace svgio { namespace svgreader { SvgDocHdl::SvgDocHdl(const rtl::OUString& aAbsolutePath) : maDocument(aAbsolutePath), mpTarget(0) { } SvgDocHdl::~SvgDocHdl() { #ifdef DBG_UTIL if(mpTarget) { OSL_ENSURE(false, "SvgDocHdl destructed with active target (!)"); delete mpTarget; } #endif } void SvgDocHdl::startDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) { OSL_ENSURE(!mpTarget, "Already a target at document start (!)"); } void SvgDocHdl::endDocument( ) throw (xml::sax::SAXException, uno::RuntimeException) { OSL_ENSURE(!mpTarget, "Still a target at document end (!)"); } void SvgDocHdl::startElement( const ::rtl::OUString& aName, const uno::Reference< xml::sax::XAttributeList >& xAttribs ) throw (xml::sax::SAXException, uno::RuntimeException) { if(aName.getLength()) { const SVGToken aSVGToken(StrToSVGToken(aName)); switch(aSVGToken) { /// structural elements case SVGTokenSymbol: { /// new basic node for Symbol. Content gets scanned, but /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) mpTarget = new SvgSymbolNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenDefs: case SVGTokenG: { /// new node for Defs/G mpTarget = new SvgGNode(aSVGToken, maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenSvg: { /// new node for Svg mpTarget = new SvgSvgNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenUse: { /// new node for Use mpTarget = new SvgUseNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// shape elements case SVGTokenCircle: { /// new node for Circle mpTarget = new SvgCircleNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenEllipse: { /// new node for Ellipse mpTarget = new SvgEllipseNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenLine: { /// new node for Line mpTarget = new SvgLineNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenPath: { /// new node for Path mpTarget = new SvgPathNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenPolygon: { /// new node for Polygon mpTarget = new SvgPolyNode(maDocument, mpTarget, false); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenPolyline: { /// new node for Polyline mpTarget = new SvgPolyNode(maDocument, mpTarget, true); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenRect: { /// new node for Rect mpTarget = new SvgRectNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenImage: { /// new node for Image mpTarget = new SvgImageNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// gradients case SVGTokenLinearGradient: case SVGTokenRadialGradient: { mpTarget = new SvgGradientNode(aSVGToken, maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// gradient stops case SVGTokenStop: { mpTarget = new SvgGradientStopNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// text case SVGTokenText: { mpTarget = new SvgTextNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenTspan: { mpTarget = new SvgTspanNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenTref: { mpTarget = new SvgTrefNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenTextPath: { mpTarget = new SvgTextPathNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// styles (as stylesheets) case SVGTokenStyle: { mpTarget = new SvgStyleNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// structural elements clip-path and mask. Content gets scanned, but /// will not be decomposed (see SvgNode::decomposeSvgNode and bReferenced) case SVGTokenClipPathNode: { /// new node for ClipPath mpTarget = new SvgClipPathNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } case SVGTokenMask: { /// new node for Mask mpTarget = new SvgMaskNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// structural element marker case SVGTokenMarker: { /// new node for marker mpTarget = new SvgMarkerNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } /// structural element pattern case SVGTokenPattern: { /// new node for pattern mpTarget = new SvgPatternNode(maDocument, mpTarget); mpTarget->parseAttributes(xAttribs); break; } default: { /// invalid token, ignore #ifdef DBG_UTIL myAssert( rtl::OUString::createFromAscii("Unknown Base SvgToken <") + aName + rtl::OUString::createFromAscii("> (!)")); #endif break; } } } } void SvgDocHdl::endElement( const ::rtl::OUString& aName ) throw (xml::sax::SAXException, uno::RuntimeException) { if(aName.getLength()) { const SVGToken aSVGToken(StrToSVGToken(aName)); SvgNode* pWhitespaceCheck(SVGTokenText == aSVGToken ? mpTarget : 0); switch(aSVGToken) { /// valid tokens for which a new one was created /// structural elements case SVGTokenDefs: case SVGTokenG: case SVGTokenSvg: case SVGTokenSymbol: case SVGTokenUse: /// shape elements case SVGTokenCircle: case SVGTokenEllipse: case SVGTokenLine: case SVGTokenPath: case SVGTokenPolygon: case SVGTokenPolyline: case SVGTokenRect: case SVGTokenImage: /// gradients case SVGTokenLinearGradient: case SVGTokenRadialGradient: /// gradient stops case SVGTokenStop: /// text case SVGTokenText: case SVGTokenTspan: case SVGTokenTextPath: case SVGTokenTref: /// styles (as stylesheets) case SVGTokenStyle: /// structural elements clip-path and mask case SVGTokenClipPathNode: case SVGTokenMask: /// structural element marker case SVGTokenMarker: /// structural element pattern case SVGTokenPattern: /// content handling after parsing { if(mpTarget) { if(!mpTarget->getParent()) { // last element closing, save this tree maDocument.appendNode(mpTarget); } mpTarget = const_cast< SvgNode* >(mpTarget->getParent()); } else { OSL_ENSURE(false, "Closing token, but no context (!)"); } break; } default: { /// invalid token, ignore } } if(pWhitespaceCheck) { // cleanup read strings whiteSpaceHandling(pWhitespaceCheck, 0); } } } void SvgDocHdl::characters( const ::rtl::OUString& aChars ) throw (xml::sax::SAXException, uno::RuntimeException) { if(mpTarget) { const sal_uInt32 nLength(aChars.getLength()); if(nLength && (SVGTokenText == mpTarget->getType() || SVGTokenTspan == mpTarget->getType() || SVGTokenTextPath == mpTarget->getType() || SVGTokenStyle == mpTarget->getType())) { switch(mpTarget->getType()) { case SVGTokenText: case SVGTokenTspan: case SVGTokenTextPath: { const SvgNodeVector& rChilds = mpTarget->getChildren(); SvgCharacterNode* pTarget = 0; if(rChilds.size()) { pTarget = dynamic_cast< SvgCharacterNode* >(rChilds[rChilds.size() - 1]); } if(pTarget) { // concatenate to current character span pTarget->concatenate(aChars); } else { // add character span as simplified tspan (no arguments) // as direct child of SvgTextNode/SvgTspanNode/SvgTextPathNode new SvgCharacterNode(maDocument, mpTarget, aChars); } break; } case SVGTokenStyle: { SvgStyleNode& rSvgStyleNode = static_cast< SvgStyleNode& >(*mpTarget); if(rSvgStyleNode.isTextCss()) { // need to interpret css styles and remember them as StyleSheets const ::rtl::OUString aTrimmedChars(aChars.trim()); if(aTrimmedChars.getLength()) { rSvgStyleNode.addCssStyleSheet(aTrimmedChars); } } break; } default: { // characters not used by a known node break; } } } } } void SvgDocHdl::ignorableWhitespace(const ::rtl::OUString& /*aWhitespaces*/) throw (xml::sax::SAXException, uno::RuntimeException) { } void SvgDocHdl::processingInstruction(const ::rtl::OUString& /*aTarget*/, const ::rtl::OUString& /*aData*/) throw (xml::sax::SAXException, uno::RuntimeException) { } void SvgDocHdl::setDocumentLocator(const uno::Reference< xml::sax::XLocator >& /*xLocator*/) throw (xml::sax::SAXException, uno::RuntimeException) { } } // end of namespace svgreader } // end of namespace svgio ////////////////////////////////////////////////////////////////////////////// // eof