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 
29 using namespace pdfi;
30 
31 
33  m_nNextId( 1 )
34 {
35 }
36 
37 sal_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 
76 sal_Int32 StyleContainer::getStandardStyleId( const OString& 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", aProps );
83  return getStyleId( aStyle );
84 }
85 
86 const 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 
93 sal_Int32 StyleContainer::setProperties( sal_Int32 nStyleId, const 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 = 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 = 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 
146 OUString 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( std::u16string_view(aStyleName).substr(nIndex+1) );
171  aRet.append( nStyle );
172  }
173  }
174  else
175  {
176  aRet.append( "invalid style id " );
177  aRet.append( nStyle );
178  }
179 
180  return aRet.makeStringAndClear();
181 }
182 
183 void StyleContainer::impl_emitStyle( sal_Int32 nStyleId,
184  EmitContext& rContext,
185  ElementTreeVisitor& rContainedElemVisitor )
186 {
187  std::unordered_map< sal_Int32, RefCountedHashedStyle >::const_iterator it = m_aIdToStyle.find( nStyleId );
188  if( it == m_aIdToStyle.end() )
189  return;
190 
191  const HashedStyle& rStyle = it->second.style;
192  PropertyMap aProps( rStyle.Properties );
193  if( !rStyle.IsSubStyle )
194  aProps[ "style:name" ] = getStyleName( nStyleId );
195  if (rStyle.Name == "draw:stroke-dash")
196  aProps[ "draw:name" ] = aProps[ "style:name" ];
197  rContext.rEmitter.beginTag( rStyle.Name.getStr(), aProps );
198 
199  for(sal_Int32 nSubStyle : rStyle.SubStyles)
200  impl_emitStyle( nSubStyle, rContext, rContainedElemVisitor );
201  if( !rStyle.Contents.isEmpty() )
202  rContext.rEmitter.write( rStyle.Contents );
203  if( rStyle.ContainedElement )
204  rStyle.ContainedElement->visitedBy( rContainedElemVisitor,
205  std::list<std::unique_ptr<Element>>::iterator() );
206  rContext.rEmitter.endTag( rStyle.Name.getStr() );
207 }
208 
210  ElementTreeVisitor& rContainedElemVisitor )
211 {
212  std::vector< sal_Int32 > aMasterPageSection, aAutomaticStyleSection, aOfficeStyleSection;
213  for( const auto& rEntry : m_aIdToStyle )
214  {
215  if( ! rEntry.second.style.IsSubStyle )
216  {
217  if( rEntry.second.style.Name == "style:master-page" )
218  aMasterPageSection.push_back( rEntry.first );
219  else if( getStyleName( rEntry.first ) == "standard" )
220  aOfficeStyleSection.push_back( rEntry.first );
221  else
222  aAutomaticStyleSection.push_back( rEntry.first );
223  }
224  }
225 
226  if( ! aMasterPageSection.empty() )
227  std::stable_sort( aMasterPageSection.begin(), aMasterPageSection.end(), StyleIdNameSort(&m_aIdToStyle) );
228  if( ! aAutomaticStyleSection.empty() )
229  std::stable_sort( aAutomaticStyleSection.begin(), aAutomaticStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) );
230  if( ! aOfficeStyleSection.empty() )
231  std::stable_sort( aOfficeStyleSection.begin(), aOfficeStyleSection.end(), StyleIdNameSort(&m_aIdToStyle) );
232 
233  int n = 0, nElements = 0;
234  rContext.rEmitter.beginTag( "office:styles", PropertyMap() );
235  for( n = 0, nElements = aOfficeStyleSection.size(); n < nElements; n++ )
236  impl_emitStyle( aOfficeStyleSection[n], rContext, rContainedElemVisitor );
237  rContext.rEmitter.endTag( "office:styles" );
238  rContext.rEmitter.beginTag( "office:automatic-styles", PropertyMap() );
239  for( n = 0, nElements = aAutomaticStyleSection.size(); n < nElements; n++ )
240  impl_emitStyle( aAutomaticStyleSection[n], rContext, rContainedElemVisitor );
241  rContext.rEmitter.endTag( "office:automatic-styles" );
242  rContext.rEmitter.beginTag( "office:master-styles", PropertyMap() );
243  for( n = 0, nElements = aMasterPageSection.size(); n < nElements; n++ )
244  impl_emitStyle( aMasterPageSection[n], rContext, rContainedElemVisitor );
245  rContext.rEmitter.endTag( "office:master-styles" );
246 }
247 
248 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::unordered_map< OUString, OUString > PropertyMap
Definition: pdfihelper.hxx:45
sal_Int32 nIndex
sal_Int32 m_nNextId
Definition: style.hxx:137
std::vector< Style * > SubStyles
Definition: style.hxx:45
PropertyMap Properties
Definition: style.hxx:42
std::unordered_map< HashedStyle, sal_Int32, StyleHash > m_aStyleToId
Definition: style.hxx:139
sal_Int64 n
virtual void beginTag(const char *pTag, const PropertyMap &rProperties)=0
Open up a tag with the given properties.
sal_Int32 impl_getStyleId(const Style &rStyle, bool bSubStyle)
Definition: style.cxx:37
Element * ContainedElement
Definition: style.hxx:44
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.
sal_Int32 nElements
std::vector< sal_Int32 > SubStyles
Definition: style.hxx:61
To be visited by all tree element types.
const PropertyMap * getProperties(sal_Int32 nStyleId) const
Definition: style.cxx:86
friend struct StyleIdNameSort
Definition: style.hxx:113
sal_Int32 setProperties(sal_Int32 nStyleId, const PropertyMap &rNewProps)
Definition: style.cxx:93
OUString getStyleName(sal_Int32 nStyle) const
Definition: style.cxx:146
void impl_emitStyle(sal_Int32 nStyleId, EmitContext &rContext, ElementTreeVisitor &rContainedElemVisitor)
Definition: style.cxx:183
sal_Int32 getStyleId(const Style &rStyle)
Definition: style.hxx:152
void emit(EmitContext &rContext, ElementTreeVisitor &rContainedElemVisitor)
Definition: style.cxx:209
std::unordered_map< sal_Int32, RefCountedHashedStyle > m_aIdToStyle
Definition: style.hxx:138
XmlEmitter & rEmitter
sal_Int32 getStandardStyleId(const OString &rFamily)
Definition: style.cxx:76
virtual void write(const OUString &rString)=0
Write PCTEXT as-is to output.
virtual void endTag(const char *pTag)=0
Close previously opened tag.