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 4 : StyleContainer::StyleContainer() :
37 4 : m_nNextId( 1 )
38 : {
39 4 : }
40 :
41 308 : sal_Int32 StyleContainer::impl_getStyleId( const Style& rStyle, bool bSubStyle )
42 : {
43 308 : sal_Int32 nRet = -1;
44 :
45 : // construct HashedStyle to find or insert
46 308 : HashedStyle aSearchStyle;
47 308 : aSearchStyle.Name = rStyle.Name;
48 308 : aSearchStyle.Properties = rStyle.Properties;
49 308 : aSearchStyle.Contents = rStyle.Contents;
50 308 : aSearchStyle.ContainedElement = rStyle.ContainedElement;
51 434 : for( unsigned int n = 0; n < rStyle.SubStyles.size(); ++n )
52 126 : aSearchStyle.SubStyles.push_back( impl_getStyleId( *rStyle.SubStyles[n], true ) );
53 :
54 : boost::unordered_map< HashedStyle, sal_Int32, StyleHash >::iterator it =
55 308 : m_aStyleToId.find( aSearchStyle );
56 :
57 308 : if( it != m_aStyleToId.end() )
58 : {
59 214 : nRet = it->second;
60 214 : HashedStyle& rFound = m_aIdToStyle[ nRet ];
61 : // increase refcount on this style
62 214 : rFound.RefCount++;
63 214 : if( ! bSubStyle )
64 130 : rFound.IsSubStyle = false;
65 : }
66 : else
67 : {
68 94 : nRet = m_nNextId++;
69 : // create new style
70 94 : HashedStyle& rNew = m_aIdToStyle[ nRet ];
71 94 : rNew = aSearchStyle;
72 94 : rNew.RefCount = 1;
73 94 : rNew.IsSubStyle = bSubStyle;
74 : // fill the style hash to find the id
75 94 : m_aStyleToId[ rNew ] = nRet;
76 : }
77 308 : return nRet;
78 : }
79 :
80 50 : sal_Int32 StyleContainer::getStandardStyleId( const rtl::OString& rName )
81 : {
82 50 : PropertyMap aProps;
83 50 : aProps[ USTR( "style:family" ) ] = rtl::OStringToOUString( rName, RTL_TEXTENCODING_UTF8 );
84 50 : aProps[ USTR( "style:name" ) ] = USTR( "standard" );
85 :
86 50 : Style aStyle( "style:style", aProps );
87 50 : 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 262 : OUString StyleContainer::getStyleName( sal_Int32 nStyle ) const
151 : {
152 262 : OUStringBuffer aRet( 64 );
153 :
154 : boost::unordered_map< sal_Int32, HashedStyle >::const_iterator style_it =
155 262 : m_aIdToStyle.find( nStyle );
156 262 : if( style_it != m_aIdToStyle.end() )
157 : {
158 262 : const HashedStyle& rStyle = style_it->second;
159 :
160 262 : PropertyMap::const_iterator name_it = rStyle.Properties.find( USTR("style:name") );
161 262 : if( name_it != rStyle.Properties.end() )
162 8 : aRet.append( name_it->second );
163 : else
164 : {
165 254 : PropertyMap::const_iterator fam_it = rStyle.Properties.find( USTR("style:family" ) );
166 254 : OUString aStyleName;
167 254 : if( fam_it != rStyle.Properties.end() )
168 : {
169 232 : aStyleName = fam_it->second;
170 : }
171 : else
172 22 : aStyleName = OStringToOUString( rStyle.Name, RTL_TEXTENCODING_ASCII_US );
173 254 : sal_Int32 nIndex = aStyleName.lastIndexOf( ':' );
174 254 : aRet.append( aStyleName.copy( nIndex+1 ) );
175 254 : aRet.append( nStyle );
176 : }
177 : }
178 : else
179 : {
180 0 : aRet.appendAscii( "invalid style id " );
181 0 : aRet.append( nStyle );
182 : }
183 :
184 262 : return aRet.makeStringAndClear();
185 : }
186 :
187 94 : void StyleContainer::impl_emitStyle( sal_Int32 nStyleId,
188 : EmitContext& rContext,
189 : ElementTreeVisitor& rContainedElemVisitor )
190 : {
191 94 : boost::unordered_map< sal_Int32, HashedStyle >::const_iterator it = m_aIdToStyle.find( nStyleId );
192 94 : if( it != m_aIdToStyle.end() )
193 : {
194 94 : const HashedStyle& rStyle = it->second;
195 94 : PropertyMap aProps( rStyle.Properties );
196 94 : if( !rStyle.IsSubStyle )
197 52 : aProps[ USTR( "style:name" ) ] = getStyleName( nStyleId );
198 94 : rContext.rEmitter.beginTag( rStyle.Name.getStr(), aProps );
199 :
200 136 : for( unsigned int n = 0; n < rStyle.SubStyles.size(); ++n )
201 42 : impl_emitStyle( rStyle.SubStyles[n], rContext, rContainedElemVisitor );
202 94 : if( !rStyle.Contents.isEmpty() )
203 0 : rContext.rEmitter.write( rStyle.Contents );
204 94 : if( rStyle.ContainedElement )
205 : rStyle.ContainedElement->visitedBy( rContainedElemVisitor,
206 0 : std::list<Element*>::iterator() );
207 94 : rContext.rEmitter.endTag( rStyle.Name.getStr() );
208 : }
209 94 : }
210 :
211 4 : void StyleContainer::emit( EmitContext& rContext,
212 : ElementTreeVisitor& rContainedElemVisitor )
213 : {
214 4 : std::vector< sal_Int32 > aMasterPageSection, aAutomaticStyleSection, aOfficeStyleSection;
215 294 : for( boost::unordered_map< sal_Int32, HashedStyle >::iterator it = m_aIdToStyle.begin();
216 196 : it != m_aIdToStyle.end(); ++it )
217 : {
218 94 : if( ! it->second.IsSubStyle )
219 : {
220 52 : if( it->second.Name.equals( "style:master-page" ) )
221 4 : aMasterPageSection.push_back( it->first );
222 48 : else if( getStyleName( it->first ) == "standard" )
223 4 : aOfficeStyleSection.push_back( it->first );
224 : else
225 44 : aAutomaticStyleSection.push_back( it->first );
226 : }
227 : }
228 :
229 4 : if( ! aMasterPageSection.empty() )
230 4 : std::stable_sort( aMasterPageSection.begin(), aMasterPageSection.end(), StyleIdNameSort(&m_aIdToStyle) );
231 4 : if( ! aAutomaticStyleSection.empty() )
232 4 : std::stable_sort( aAutomaticStyleSection.begin(), aAutomaticStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) );
233 4 : if( ! aOfficeStyleSection.empty() )
234 2 : std::stable_sort( aOfficeStyleSection.begin(), aOfficeStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) );
235 :
236 4 : int n = 0, nElements = 0;
237 4 : rContext.rEmitter.beginTag( "office:styles", PropertyMap() );
238 8 : for( n = 0, nElements = aOfficeStyleSection.size(); n < nElements; n++ )
239 4 : impl_emitStyle( aOfficeStyleSection[n], rContext, rContainedElemVisitor );
240 4 : rContext.rEmitter.endTag( "office:styles" );
241 4 : rContext.rEmitter.beginTag( "office:automatic-styles", PropertyMap() );
242 48 : for( n = 0, nElements = aAutomaticStyleSection.size(); n < nElements; n++ )
243 44 : impl_emitStyle( aAutomaticStyleSection[n], rContext, rContainedElemVisitor );
244 4 : rContext.rEmitter.endTag( "office:automatic-styles" );
245 4 : rContext.rEmitter.beginTag( "office:master-styles", PropertyMap() );
246 8 : for( n = 0, nElements = aMasterPageSection.size(); n < nElements; n++ )
247 4 : impl_emitStyle( aMasterPageSection[n], rContext, rContainedElemVisitor );
248 4 : rContext.rEmitter.endTag( "office:master-styles" );
249 4 : }
250 :
251 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|