1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sdext.hxx" 26 27 #include "style.hxx" 28 #include "genericelements.hxx" 29 #include "xmlemitter.hxx" 30 #include "pdfiprocessor.hxx" 31 #include <rtl/ustrbuf.hxx> 32 33 #include <algorithm> 34 35 using namespace rtl; 36 using namespace pdfi; 37 38 #define USTR(x) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( x ) ) 39 40 StyleContainer::StyleContainer() : 41 m_nNextId( 1 ) 42 { 43 } 44 45 sal_Int32 StyleContainer::impl_getStyleId( const Style& rStyle, bool bSubStyle ) 46 { 47 sal_Int32 nRet = -1; 48 49 // construct HashedStyle to find or insert 50 HashedStyle aSearchStyle; 51 aSearchStyle.Name = rStyle.Name; 52 aSearchStyle.Properties = rStyle.Properties; 53 aSearchStyle.Contents = rStyle.Contents; 54 aSearchStyle.ContainedElement = rStyle.ContainedElement; 55 for( unsigned int n = 0; n < rStyle.SubStyles.size(); ++n ) 56 aSearchStyle.SubStyles.push_back( impl_getStyleId( *rStyle.SubStyles[n], true ) ); 57 58 std::hash_map< HashedStyle, sal_Int32, StyleHash >::iterator it = 59 m_aStyleToId.find( aSearchStyle ); 60 61 if( it != m_aStyleToId.end() ) 62 { 63 nRet = it->second; 64 HashedStyle& rFound = m_aIdToStyle[ nRet ]; 65 // increase refcount on this style 66 rFound.RefCount++; 67 if( ! bSubStyle ) 68 rFound.IsSubStyle = false; 69 } 70 else 71 { 72 nRet = m_nNextId++; 73 // create new style 74 HashedStyle& rNew = m_aIdToStyle[ nRet ]; 75 rNew = aSearchStyle; 76 rNew.RefCount = 1; 77 rNew.IsSubStyle = bSubStyle; 78 // fill the style hash to find the id 79 m_aStyleToId[ rNew ] = nRet; 80 } 81 return nRet; 82 } 83 84 sal_Int32 StyleContainer::getStandardStyleId( const rtl::OString& rName ) 85 { 86 PropertyMap aProps; 87 aProps[ USTR( "style:family" ) ] = rtl::OStringToOUString( rName, RTL_TEXTENCODING_UTF8 ); 88 aProps[ USTR( "style:name" ) ] = USTR( "standard" ); 89 90 Style aStyle( "style:style", aProps ); 91 return getStyleId( aStyle ); 92 } 93 94 const PropertyMap* StyleContainer::getProperties( sal_Int32 nStyleId ) const 95 { 96 std::hash_map< sal_Int32, HashedStyle >::const_iterator it = 97 m_aIdToStyle.find( nStyleId ); 98 return it != m_aIdToStyle.end() ? &(it->second.Properties) : NULL; 99 } 100 101 sal_Int32 StyleContainer::setProperties( sal_Int32 nStyleId, const PropertyMap& rNewProps ) 102 { 103 sal_Int32 nRet = -1; 104 std::hash_map< sal_Int32, HashedStyle >::iterator it = 105 m_aIdToStyle.find( nStyleId ); 106 if( it != m_aIdToStyle.end() ) 107 { 108 if( it->second.RefCount == 1 ) 109 { 110 nRet = it->first; 111 // erase old hash to id mapping 112 m_aStyleToId.erase( it->second ); 113 // change properties 114 it->second.Properties = rNewProps; 115 // fill in new hash to id mapping 116 m_aStyleToId[ it->second ] = nRet; 117 } 118 else 119 { 120 // decrease refcound on old instance 121 it->second.RefCount--; 122 // acquire new HashedStyle 123 HashedStyle aSearchStyle; 124 aSearchStyle.Name = it->second.Name; 125 aSearchStyle.Properties = rNewProps; 126 aSearchStyle.Contents = it->second.Contents; 127 aSearchStyle.ContainedElement = it->second.ContainedElement; 128 aSearchStyle.SubStyles = it->second.SubStyles; 129 aSearchStyle.IsSubStyle = it->second.IsSubStyle; 130 131 // find out whether this new style already exists 132 std::hash_map< HashedStyle, sal_Int32, StyleHash >::iterator new_it = 133 m_aStyleToId.find( aSearchStyle ); 134 if( new_it != m_aStyleToId.end() ) 135 { 136 nRet = new_it->second; 137 m_aIdToStyle[ nRet ].RefCount++; 138 } 139 else 140 { 141 nRet = m_nNextId++; 142 // create new style with new id 143 HashedStyle& rNew = m_aIdToStyle[ nRet ]; 144 rNew = aSearchStyle; 145 rNew.RefCount = 1; 146 // fill style to id hash 147 m_aStyleToId[ aSearchStyle ] = nRet; 148 } 149 } 150 } 151 return nRet; 152 } 153 154 OUString StyleContainer::getStyleName( sal_Int32 nStyle ) const 155 { 156 OUStringBuffer aRet( 64 ); 157 158 std::hash_map< sal_Int32, HashedStyle >::const_iterator style_it = 159 m_aIdToStyle.find( nStyle ); 160 if( style_it != m_aIdToStyle.end() ) 161 { 162 const HashedStyle& rStyle = style_it->second; 163 164 PropertyMap::const_iterator name_it = rStyle.Properties.find( USTR("style:name") ); 165 if( name_it != rStyle.Properties.end() ) 166 aRet.append( name_it->second ); 167 else 168 { 169 PropertyMap::const_iterator fam_it = rStyle.Properties.find( USTR("style:family" ) ); 170 OUString aStyleName; 171 if( fam_it != rStyle.Properties.end() ) 172 { 173 aStyleName = fam_it->second; 174 } 175 else 176 aStyleName = OStringToOUString( rStyle.Name, RTL_TEXTENCODING_ASCII_US ); 177 sal_Int32 nIndex = aStyleName.lastIndexOf( ':' ); 178 aRet.append( aStyleName.copy( nIndex+1 ) ); 179 aRet.append( nStyle ); 180 } 181 } 182 else 183 { 184 aRet.appendAscii( "invalid style id " ); 185 aRet.append( nStyle ); 186 } 187 188 return aRet.makeStringAndClear(); 189 } 190 191 void StyleContainer::impl_emitStyle( sal_Int32 nStyleId, 192 EmitContext& rContext, 193 ElementTreeVisitor& rContainedElemVisitor ) 194 { 195 std::hash_map< sal_Int32, HashedStyle >::const_iterator it = m_aIdToStyle.find( nStyleId ); 196 if( it != m_aIdToStyle.end() ) 197 { 198 const HashedStyle& rStyle = it->second; 199 PropertyMap aProps( rStyle.Properties ); 200 if( !rStyle.IsSubStyle ) 201 aProps[ USTR( "style:name" ) ] = getStyleName( nStyleId ); 202 rContext.rEmitter.beginTag( rStyle.Name.getStr(), aProps ); 203 204 for( unsigned int n = 0; n < rStyle.SubStyles.size(); ++n ) 205 impl_emitStyle( rStyle.SubStyles[n], rContext, rContainedElemVisitor ); 206 if( rStyle.Contents ) 207 rContext.rEmitter.write( rStyle.Contents ); 208 if( rStyle.ContainedElement ) 209 rStyle.ContainedElement->visitedBy( rContainedElemVisitor, 210 std::list<Element*>::iterator() ); 211 rContext.rEmitter.endTag( rStyle.Name.getStr() ); 212 } 213 } 214 215 void StyleContainer::emit( EmitContext& rContext, 216 ElementTreeVisitor& rContainedElemVisitor ) 217 { 218 std::vector< sal_Int32 > aMasterPageSection, aAutomaticStyleSection, aOfficeStyleSection; 219 for( std::hash_map< sal_Int32, HashedStyle >::iterator it = m_aIdToStyle.begin(); 220 it != m_aIdToStyle.end(); ++it ) 221 { 222 if( ! it->second.IsSubStyle ) 223 { 224 if( it->second.Name.equals( "style:master-page" ) ) 225 aMasterPageSection.push_back( it->first ); 226 else if( getStyleName( it->first ).equalsAscii( "standard" ) ) 227 aOfficeStyleSection.push_back( it->first ); 228 else 229 aAutomaticStyleSection.push_back( it->first ); 230 } 231 } 232 233 if( ! aMasterPageSection.empty() ) 234 std::stable_sort( aMasterPageSection.begin(), aMasterPageSection.end(), StyleIdNameSort(&m_aIdToStyle) ); 235 if( ! aAutomaticStyleSection.empty() ) 236 std::stable_sort( aAutomaticStyleSection.begin(), aAutomaticStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) ); 237 if( ! aOfficeStyleSection.empty() ) 238 std::stable_sort( aOfficeStyleSection.begin(), aOfficeStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) ); 239 240 int n = 0, nElements = 0; 241 rContext.rEmitter.beginTag( "office:styles", PropertyMap() ); 242 for( n = 0, nElements = aOfficeStyleSection.size(); n < nElements; n++ ) 243 impl_emitStyle( aOfficeStyleSection[n], rContext, rContainedElemVisitor ); 244 rContext.rEmitter.endTag( "office:styles" ); 245 rContext.rEmitter.beginTag( "office:automatic-styles", PropertyMap() ); 246 for( n = 0, nElements = aAutomaticStyleSection.size(); n < nElements; n++ ) 247 impl_emitStyle( aAutomaticStyleSection[n], rContext, rContainedElemVisitor ); 248 rContext.rEmitter.endTag( "office:automatic-styles" ); 249 rContext.rEmitter.beginTag( "office:master-styles", PropertyMap() ); 250 for( n = 0, nElements = aMasterPageSection.size(); n < nElements; n++ ) 251 impl_emitStyle( aMasterPageSection[n], rContext, rContainedElemVisitor ); 252 rContext.rEmitter.endTag( "office:master-styles" ); 253 } 254