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