LibreOffice Module sdext (master) 1
style.cxx
Go to the documentation of this file.
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 <rtl/ustrbuf.hxx>
25
26#include <algorithm>
27#include <string_view>
28
29using namespace pdfi;
30
31
32StyleContainer::StyleContainer() :
33 m_nNextId( 1 )
34{
35}
36
37sal_Int32 StyleContainer::impl_getStyleId( const Style& rStyle, bool bSubStyle )
38{
39 sal_Int32 nRet = -1;
40
41 // construct HashedStyle to find or insert
42 HashedStyle aSearchStyle;
43 aSearchStyle.Name = rStyle.Name;
44 aSearchStyle.Properties = rStyle.Properties;
45 aSearchStyle.Contents = rStyle.Contents;
46 aSearchStyle.ContainedElement = rStyle.ContainedElement;
47 for(Style* pSubStyle : rStyle.SubStyles)
48 aSearchStyle.SubStyles.push_back( impl_getStyleId( *pSubStyle, true ) );
49
50 std::unordered_map< HashedStyle, sal_Int32, StyleHash >::iterator it =
51 m_aStyleToId.find( aSearchStyle );
52
53 if( it != m_aStyleToId.end() )
54 {
55 nRet = it->second;
56 RefCountedHashedStyle& rFound = m_aIdToStyle[ nRet ];
57 // increase refcount on this style
58 rFound.RefCount++;
59 if( ! bSubStyle )
60 rFound.style.IsSubStyle = false;
61 }
62 else
63 {
64 nRet = m_nNextId++;
65 // create new style
66 RefCountedHashedStyle& rNew = m_aIdToStyle[ nRet ];
67 rNew.style = aSearchStyle;
68 rNew.RefCount = 1;
69 rNew.style.IsSubStyle = bSubStyle;
70 // fill the style hash to find the id
71 m_aStyleToId[ rNew.style ] = nRet;
72 }
73 return nRet;
74}
75
76sal_Int32 StyleContainer::getStandardStyleId( std::string_view rName )
77{
78 PropertyMap aProps;
79 aProps[ "style:family" ] = OStringToOUString( rName, RTL_TEXTENCODING_UTF8 );
80 aProps[ "style:name" ] = "standard";
81
82 Style aStyle( "style:style", std::move(aProps) );
83 return getStyleId( aStyle );
84}
85
86const PropertyMap* StyleContainer::getProperties( sal_Int32 nStyleId ) const
87{
88 std::unordered_map< sal_Int32, RefCountedHashedStyle >::const_iterator it =
89 m_aIdToStyle.find( nStyleId );
90 return it != m_aIdToStyle.end() ? &(it->second.style.Properties) : nullptr;
91}
92
93sal_Int32 StyleContainer::setProperties( sal_Int32 nStyleId, PropertyMap&& rNewProps )
94{
95 sal_Int32 nRet = -1;
96 std::unordered_map< sal_Int32, RefCountedHashedStyle >::iterator it =
97 m_aIdToStyle.find( nStyleId );
98 if( it != m_aIdToStyle.end() )
99 {
100 if( it->second.RefCount == 1 )
101 {
102 nRet = it->first;
103 // erase old hash to id mapping
104 m_aStyleToId.erase( it->second.style );
105 // change properties
106 it->second.style.Properties = std::move(rNewProps);
107 // fill in new hash to id mapping
108 m_aStyleToId[ it->second.style ] = nRet;
109 }
110 else
111 {
112 // decrease refcount on old instance
113 it->second.RefCount--;
114 // acquire new HashedStyle
115 HashedStyle aSearchStyle;
116 aSearchStyle.Name = it->second.style.Name;
117 aSearchStyle.Properties = std::move(rNewProps);
118 aSearchStyle.Contents = it->second.style.Contents;
119 aSearchStyle.ContainedElement = it->second.style.ContainedElement;
120 aSearchStyle.SubStyles = it->second.style.SubStyles;
121 aSearchStyle.IsSubStyle = it->second.style.IsSubStyle;
122
123 // find out whether this new style already exists
124 std::unordered_map< HashedStyle, sal_Int32, StyleHash >::iterator new_it =
125 m_aStyleToId.find( aSearchStyle );
126 if( new_it != m_aStyleToId.end() )
127 {
128 nRet = new_it->second;
129 m_aIdToStyle[ nRet ].RefCount++;
130 }
131 else
132 {
133 nRet = m_nNextId++;
134 // create new style with new id
135 RefCountedHashedStyle& rNew = m_aIdToStyle[ nRet ];
136 rNew.style = aSearchStyle;
137 rNew.RefCount = 1;
138 // fill style to id hash
139 m_aStyleToId[ aSearchStyle ] = nRet;
140 }
141 }
142 }
143 return nRet;
144}
145
146OUString StyleContainer::getStyleName( sal_Int32 nStyle ) const
147{
148 OUStringBuffer aRet( 64 );
149
150 std::unordered_map< sal_Int32, RefCountedHashedStyle >::const_iterator style_it =
151 m_aIdToStyle.find( nStyle );
152 if( style_it != m_aIdToStyle.end() )
153 {
154 const HashedStyle& rStyle = style_it->second.style;
155
156 PropertyMap::const_iterator name_it = rStyle.Properties.find( "style:name" );
157 if( name_it != rStyle.Properties.end() )
158 aRet.append( name_it->second );
159 else
160 {
161 PropertyMap::const_iterator fam_it = rStyle.Properties.find( "style:family" );
162 OUString aStyleName;
163 if( fam_it != rStyle.Properties.end() )
164 {
165 aStyleName = fam_it->second;
166 }
167 else
168 aStyleName = OStringToOUString( rStyle.Name, RTL_TEXTENCODING_ASCII_US );
169 sal_Int32 nIndex = aStyleName.lastIndexOf( ':' );
170 aRet.append( aStyleName.subView(nIndex+1) + OUString::number( nStyle ) );
171 }
172 }
173 else
174 {
175 aRet.append( "invalid style id " + OUString::number(nStyle) );
176 }
177
178 return aRet.makeStringAndClear();
179}
180
181void StyleContainer::impl_emitStyle( sal_Int32 nStyleId,
182 EmitContext& rContext,
183 ElementTreeVisitor& rContainedElemVisitor )
184{
185 std::unordered_map< sal_Int32, RefCountedHashedStyle >::const_iterator it = m_aIdToStyle.find( nStyleId );
186 if( it == m_aIdToStyle.end() )
187 return;
188
189 const HashedStyle& rStyle = it->second.style;
190 PropertyMap aProps( rStyle.Properties );
191 if( !rStyle.IsSubStyle )
192 aProps[ "style:name" ] = getStyleName( nStyleId );
193 if (rStyle.Name == "draw:stroke-dash")
194 aProps[ "draw:name" ] = aProps[ "style:name" ];
195 rContext.rEmitter.beginTag( rStyle.Name.getStr(), aProps );
196
197 for(sal_Int32 nSubStyle : rStyle.SubStyles)
198 impl_emitStyle( nSubStyle, rContext, rContainedElemVisitor );
199 if( !rStyle.Contents.isEmpty() )
200 rContext.rEmitter.write( rStyle.Contents );
201 if( rStyle.ContainedElement )
202 rStyle.ContainedElement->visitedBy( rContainedElemVisitor,
203 std::list<std::unique_ptr<Element>>::iterator() );
204 rContext.rEmitter.endTag( rStyle.Name.getStr() );
205}
206
208 ElementTreeVisitor& rContainedElemVisitor )
209{
210 std::vector< sal_Int32 > aMasterPageSection, aAutomaticStyleSection, aOfficeStyleSection;
211 for( const auto& rEntry : m_aIdToStyle )
212 {
213 if( ! rEntry.second.style.IsSubStyle )
214 {
215 if( rEntry.second.style.Name == "style:master-page" )
216 aMasterPageSection.push_back( rEntry.first );
217 else if( getStyleName( rEntry.first ) == "standard" )
218 aOfficeStyleSection.push_back( rEntry.first );
219 else
220 aAutomaticStyleSection.push_back( rEntry.first );
221 }
222 }
223
224 if( ! aMasterPageSection.empty() )
225 std::stable_sort( aMasterPageSection.begin(), aMasterPageSection.end(), StyleIdNameSort(&m_aIdToStyle) );
226 if( ! aAutomaticStyleSection.empty() )
227 std::stable_sort( aAutomaticStyleSection.begin(), aAutomaticStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) );
228 if( ! aOfficeStyleSection.empty() )
229 std::stable_sort( aOfficeStyleSection.begin(), aOfficeStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) );
230
231 int n = 0, nElements = 0;
232 rContext.rEmitter.beginTag( "office:styles", PropertyMap() );
233 for( n = 0, nElements = aOfficeStyleSection.size(); n < nElements; n++ )
234 impl_emitStyle( aOfficeStyleSection[n], rContext, rContainedElemVisitor );
235 rContext.rEmitter.endTag( "office:styles" );
236 rContext.rEmitter.beginTag( "office:automatic-styles", PropertyMap() );
237 for( n = 0, nElements = aAutomaticStyleSection.size(); n < nElements; n++ )
238 impl_emitStyle( aAutomaticStyleSection[n], rContext, rContainedElemVisitor );
239 rContext.rEmitter.endTag( "office:automatic-styles" );
240 rContext.rEmitter.beginTag( "office:master-styles", PropertyMap() );
241 for( n = 0, nElements = aMasterPageSection.size(); n < nElements; n++ )
242 impl_emitStyle( aMasterPageSection[n], rContext, rContainedElemVisitor );
243 rContext.rEmitter.endTag( "office:master-styles" );
244}
245
246/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void emit(EmitContext &rContext, ElementTreeVisitor &rContainedElemVisitor)
Definition: style.cxx:207
sal_Int32 setProperties(sal_Int32 nStyleId, PropertyMap &&rNewProps)
Definition: style.cxx:93
OUString getStyleName(sal_Int32 nStyle) const
Definition: style.cxx:146
sal_Int32 impl_getStyleId(const Style &rStyle, bool bSubStyle)
Definition: style.cxx:37
const PropertyMap * getProperties(sal_Int32 nStyleId) const
Definition: style.cxx:86
sal_Int32 m_nNextId
Definition: style.hxx:138
sal_Int32 getStandardStyleId(std::string_view rFamily)
Definition: style.cxx:76
std::unordered_map< HashedStyle, sal_Int32, StyleHash > m_aStyleToId
Definition: style.hxx:140
std::unordered_map< sal_Int32, RefCountedHashedStyle > m_aIdToStyle
Definition: style.hxx:139
void impl_emitStyle(sal_Int32 nStyleId, EmitContext &rContext, ElementTreeVisitor &rContainedElemVisitor)
Definition: style.cxx:181
sal_Int32 getStyleId(const Style &rStyle)
Definition: style.hxx:153
virtual void write(const OUString &rString)=0
Write PCTEXT as-is to output.
virtual void endTag(const char *pTag)=0
Close previously opened tag.
virtual void beginTag(const char *pTag, const PropertyMap &rProperties)=0
Open up a tag with the given properties.
sal_Int32 nElements
sal_Int32 nIndex
sal_Int64 n
std::unordered_map< OUString, OUString > PropertyMap
Definition: pdfihelper.hxx:44
To be visited by all tree element types.
virtual void visitedBy(ElementTreeVisitor &, const std::list< std::unique_ptr< Element > >::const_iterator &rParentIt)=0
To be implemented by every tree node that needs to be visitable.
XmlEmitter & rEmitter
std::vector< sal_Int32 > SubStyles
Definition: style.hxx:62
std::vector< Style * > SubStyles
Definition: style.hxx:46
Element * ContainedElement
Definition: style.hxx:45
PropertyMap Properties
Definition: style.hxx:43