| /************************************************************** |
| * |
| * 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_sdext.hxx" |
| |
| #include "style.hxx" |
| #include "genericelements.hxx" |
| #include "xmlemitter.hxx" |
| #include "pdfiprocessor.hxx" |
| #include <rtl/ustrbuf.hxx> |
| |
| #include <algorithm> |
| |
| using namespace rtl; |
| using namespace pdfi; |
| |
| #define USTR(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) ) |
| |
| StyleContainer::StyleContainer() : |
| m_nNextId( 1 ) |
| { |
| } |
| |
| sal_Int32 StyleContainer::impl_getStyleId( const Style& rStyle, bool bSubStyle ) |
| { |
| sal_Int32 nRet = -1; |
| |
| // construct HashedStyle to find or insert |
| HashedStyle aSearchStyle; |
| aSearchStyle.Name = rStyle.Name; |
| aSearchStyle.Properties = rStyle.Properties; |
| aSearchStyle.Contents = rStyle.Contents; |
| aSearchStyle.ContainedElement = rStyle.ContainedElement; |
| for( unsigned int n = 0; n < rStyle.SubStyles.size(); ++n ) |
| aSearchStyle.SubStyles.push_back( impl_getStyleId( *rStyle.SubStyles[n], true ) ); |
| |
| std::hash_map< HashedStyle, sal_Int32, StyleHash >::iterator it = |
| m_aStyleToId.find( aSearchStyle ); |
| |
| if( it != m_aStyleToId.end() ) |
| { |
| nRet = it->second; |
| HashedStyle& rFound = m_aIdToStyle[ nRet ]; |
| // increase refcount on this style |
| rFound.RefCount++; |
| if( ! bSubStyle ) |
| rFound.IsSubStyle = false; |
| } |
| else |
| { |
| nRet = m_nNextId++; |
| // create new style |
| HashedStyle& rNew = m_aIdToStyle[ nRet ]; |
| rNew = aSearchStyle; |
| rNew.RefCount = 1; |
| rNew.IsSubStyle = bSubStyle; |
| // fill the style hash to find the id |
| m_aStyleToId[ rNew ] = nRet; |
| } |
| return nRet; |
| } |
| |
| sal_Int32 StyleContainer::getStandardStyleId( const rtl::OString& rName ) |
| { |
| PropertyMap aProps; |
| aProps[ USTR( "style:family" ) ] = rtl::OStringToOUString( rName, RTL_TEXTENCODING_UTF8 ); |
| aProps[ USTR( "style:name" ) ] = USTR( "standard" ); |
| |
| Style aStyle( "style:style", aProps ); |
| return getStyleId( aStyle ); |
| } |
| |
| const PropertyMap* StyleContainer::getProperties( sal_Int32 nStyleId ) const |
| { |
| std::hash_map< sal_Int32, HashedStyle >::const_iterator it = |
| m_aIdToStyle.find( nStyleId ); |
| return it != m_aIdToStyle.end() ? &(it->second.Properties) : NULL; |
| } |
| |
| sal_Int32 StyleContainer::setProperties( sal_Int32 nStyleId, const PropertyMap& rNewProps ) |
| { |
| sal_Int32 nRet = -1; |
| std::hash_map< sal_Int32, HashedStyle >::iterator it = |
| m_aIdToStyle.find( nStyleId ); |
| if( it != m_aIdToStyle.end() ) |
| { |
| if( it->second.RefCount == 1 ) |
| { |
| nRet = it->first; |
| // erase old hash to id mapping |
| m_aStyleToId.erase( it->second ); |
| // change properties |
| it->second.Properties = rNewProps; |
| // fill in new hash to id mapping |
| m_aStyleToId[ it->second ] = nRet; |
| } |
| else |
| { |
| // decrease refcound on old instance |
| it->second.RefCount--; |
| // acquire new HashedStyle |
| HashedStyle aSearchStyle; |
| aSearchStyle.Name = it->second.Name; |
| aSearchStyle.Properties = rNewProps; |
| aSearchStyle.Contents = it->second.Contents; |
| aSearchStyle.ContainedElement = it->second.ContainedElement; |
| aSearchStyle.SubStyles = it->second.SubStyles; |
| aSearchStyle.IsSubStyle = it->second.IsSubStyle; |
| |
| // find out whether this new style already exists |
| std::hash_map< HashedStyle, sal_Int32, StyleHash >::iterator new_it = |
| m_aStyleToId.find( aSearchStyle ); |
| if( new_it != m_aStyleToId.end() ) |
| { |
| nRet = new_it->second; |
| m_aIdToStyle[ nRet ].RefCount++; |
| } |
| else |
| { |
| nRet = m_nNextId++; |
| // create new style with new id |
| HashedStyle& rNew = m_aIdToStyle[ nRet ]; |
| rNew = aSearchStyle; |
| rNew.RefCount = 1; |
| // fill style to id hash |
| m_aStyleToId[ aSearchStyle ] = nRet; |
| } |
| } |
| } |
| return nRet; |
| } |
| |
| OUString StyleContainer::getStyleName( sal_Int32 nStyle ) const |
| { |
| OUStringBuffer aRet( 64 ); |
| |
| std::hash_map< sal_Int32, HashedStyle >::const_iterator style_it = |
| m_aIdToStyle.find( nStyle ); |
| if( style_it != m_aIdToStyle.end() ) |
| { |
| const HashedStyle& rStyle = style_it->second; |
| |
| PropertyMap::const_iterator name_it = rStyle.Properties.find( USTR("style:name") ); |
| if( name_it != rStyle.Properties.end() ) |
| aRet.append( name_it->second ); |
| else |
| { |
| PropertyMap::const_iterator fam_it = rStyle.Properties.find( USTR("style:family" ) ); |
| OUString aStyleName; |
| if( fam_it != rStyle.Properties.end() ) |
| { |
| aStyleName = fam_it->second; |
| } |
| else |
| aStyleName = OStringToOUString( rStyle.Name, RTL_TEXTENCODING_ASCII_US ); |
| sal_Int32 nIndex = aStyleName.lastIndexOf( ':' ); |
| aRet.append( aStyleName.copy( nIndex+1 ) ); |
| aRet.append( nStyle ); |
| } |
| } |
| else |
| { |
| aRet.appendAscii( "invalid style id " ); |
| aRet.append( nStyle ); |
| } |
| |
| return aRet.makeStringAndClear(); |
| } |
| |
| void StyleContainer::impl_emitStyle( sal_Int32 nStyleId, |
| EmitContext& rContext, |
| ElementTreeVisitor& rContainedElemVisitor ) |
| { |
| std::hash_map< sal_Int32, HashedStyle >::const_iterator it = m_aIdToStyle.find( nStyleId ); |
| if( it != m_aIdToStyle.end() ) |
| { |
| const HashedStyle& rStyle = it->second; |
| PropertyMap aProps( rStyle.Properties ); |
| if( !rStyle.IsSubStyle ) |
| aProps[ USTR( "style:name" ) ] = getStyleName( nStyleId ); |
| rContext.rEmitter.beginTag( rStyle.Name.getStr(), aProps ); |
| |
| for( unsigned int n = 0; n < rStyle.SubStyles.size(); ++n ) |
| impl_emitStyle( rStyle.SubStyles[n], rContext, rContainedElemVisitor ); |
| if( rStyle.Contents ) |
| rContext.rEmitter.write( rStyle.Contents ); |
| if( rStyle.ContainedElement ) |
| rStyle.ContainedElement->visitedBy( rContainedElemVisitor, |
| std::list<Element*>::iterator() ); |
| rContext.rEmitter.endTag( rStyle.Name.getStr() ); |
| } |
| } |
| |
| void StyleContainer::emit( EmitContext& rContext, |
| ElementTreeVisitor& rContainedElemVisitor ) |
| { |
| std::vector< sal_Int32 > aMasterPageSection, aAutomaticStyleSection, aOfficeStyleSection; |
| for( std::hash_map< sal_Int32, HashedStyle >::iterator it = m_aIdToStyle.begin(); |
| it != m_aIdToStyle.end(); ++it ) |
| { |
| if( ! it->second.IsSubStyle ) |
| { |
| if( it->second.Name.equals( "style:master-page" ) ) |
| aMasterPageSection.push_back( it->first ); |
| else if( getStyleName( it->first ).equalsAscii( "standard" ) ) |
| aOfficeStyleSection.push_back( it->first ); |
| else |
| aAutomaticStyleSection.push_back( it->first ); |
| } |
| } |
| |
| if( ! aMasterPageSection.empty() ) |
| std::stable_sort( aMasterPageSection.begin(), aMasterPageSection.end(), StyleIdNameSort(&m_aIdToStyle) ); |
| if( ! aAutomaticStyleSection.empty() ) |
| std::stable_sort( aAutomaticStyleSection.begin(), aAutomaticStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) ); |
| if( ! aOfficeStyleSection.empty() ) |
| std::stable_sort( aOfficeStyleSection.begin(), aOfficeStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) ); |
| |
| int n = 0, nElements = 0; |
| rContext.rEmitter.beginTag( "office:styles", PropertyMap() ); |
| for( n = 0, nElements = aOfficeStyleSection.size(); n < nElements; n++ ) |
| impl_emitStyle( aOfficeStyleSection[n], rContext, rContainedElemVisitor ); |
| rContext.rEmitter.endTag( "office:styles" ); |
| rContext.rEmitter.beginTag( "office:automatic-styles", PropertyMap() ); |
| for( n = 0, nElements = aAutomaticStyleSection.size(); n < nElements; n++ ) |
| impl_emitStyle( aAutomaticStyleSection[n], rContext, rContainedElemVisitor ); |
| rContext.rEmitter.endTag( "office:automatic-styles" ); |
| rContext.rEmitter.beginTag( "office:master-styles", PropertyMap() ); |
| for( n = 0, nElements = aMasterPageSection.size(); n < nElements; n++ ) |
| impl_emitStyle( aMasterPageSection[n], rContext, rContainedElemVisitor ); |
| rContext.rEmitter.endTag( "office:master-styles" ); |
| } |