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