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 #include <PageMasterImportContext.hxx>
21 #include <xmloff/xmlimppr.hxx>
22 #include <xmloff/xmlnamespace.hxx>
23 #include <xmloff/xmlprmap.hxx>
24 #include <xmloff/xmltoken.hxx>
25 #include "PageMasterPropHdl.hxx"
26 #include "PagePropertySetContext.hxx"
27 #include "PageHeaderFooterContext.hxx"
28 #include <PageMasterStyleMap.hxx>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <osl/diagnose.h>
32 
33 //
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertySetInfo.hpp>
36 #include <com/sun/star/drawing/FillStyle.hpp>
37 #include <com/sun/star/drawing/BitmapMode.hpp>
38 #include <xmloff/xmlerror.hxx>
39 #include <xmloff/XMLTextMasterPageContext.hxx>
40 
41 using namespace ::com::sun::star;
42 using namespace ::xmloff::token;
43 using namespace ::com::sun::star::uno;
44 using namespace ::com::sun::star::lang;
45 
46 //
47 using namespace ::com::sun::star::beans;
48 
SetAttribute(sal_Int32 nElement,const OUString & rValue)49 void PageStyleContext::SetAttribute( sal_Int32 nElement,
50                                         const OUString& rValue )
51 {
52     if( nElement == XML_ELEMENT(STYLE, XML_PAGE_USAGE) )
53     {
54         sPageUsage = rValue;
55     }
56     else
57     {
58         XMLPropStyleContext::SetAttribute( nElement, rValue );
59     }
60 }
61 
62 
PageStyleContext(SvXMLImport & rImport,SvXMLStylesContext & rStyles,bool bDefaultStyle)63 PageStyleContext::PageStyleContext( SvXMLImport& rImport,
64         SvXMLStylesContext& rStyles,
65         bool bDefaultStyle) :
66     XMLPropStyleContext( rImport, rStyles, XmlStyleFamily::PAGE_MASTER, bDefaultStyle),
67     sPageUsage(),
68     m_bIsFillStyleAlreadyConverted(false) //
69 {
70 }
71 
~PageStyleContext()72 PageStyleContext::~PageStyleContext()
73 {
74 }
75 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)76 css::uno::Reference< css::xml::sax::XFastContextHandler > PageStyleContext::createFastChildContext(
77     sal_Int32 nElement,
78     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
79 {
80     if( nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE) ||
81         nElement == XML_ELEMENT(STYLE, XML_FOOTER_STYLE) )
82     {
83         bool bHeader = nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE);
84         rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
85             GetStyles()->GetImportPropertyMapper( GetFamily() );
86         if( xImpPrMap.is() )
87         {
88             const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
89             sal_Int32 nFlag;
90             if (bHeader)
91                 nFlag = CTF_PM_HEADERFLAG;
92             else
93                 nFlag = CTF_PM_FOOTERFLAG;
94             sal_Int32 nStartIndex (-1);
95             sal_Int32 nEndIndex (-1);
96             bool bFirst(false);
97             bool bEnd(false);
98             sal_Int32 nIndex = 0;
99             while ( nIndex < rMapper->GetEntryCount() && !bEnd)
100             {
101                 if ((rMapper->GetEntryContextId( nIndex ) & CTF_PM_FLAGMASK) == nFlag)
102                 {
103                     if (!bFirst)
104                     {
105                         bFirst = true;
106                         nStartIndex = nIndex;
107                     }
108                 }
109                 else if (bFirst)
110                 {
111                     bEnd = true;
112                     nEndIndex = nIndex;
113                 }
114                 nIndex++;
115             }
116             if (!bEnd)
117                 nEndIndex = nIndex;
118             return new PageHeaderFooterContext(GetImport(),
119                             GetProperties(), xImpPrMap, nStartIndex, nEndIndex, bHeader);
120         }
121     }
122 
123     if( nElement == XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_PROPERTIES) )
124     {
125         rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
126             GetStyles()->GetImportPropertyMapper( GetFamily() );
127         if( xImpPrMap.is() )
128         {
129             const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
130             sal_Int32 nEndIndex (-1);
131             bool bEnd(false);
132             sal_Int32 nIndex = 0;
133             sal_Int16 nContextID;
134             while ( nIndex < rMapper->GetEntryCount() && !bEnd)
135             {
136                 nContextID = rMapper->GetEntryContextId( nIndex );
137                 if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START))
138                 {
139                     nEndIndex = nIndex;
140                     bEnd = true;
141                 }
142                 nIndex++;
143             }
144             if (!bEnd)
145                 nEndIndex = nIndex;
146             return new PagePropertySetContext( GetImport(), nElement,
147                                                     xAttrList,
148                                                     XML_TYPE_PROP_PAGE_LAYOUT,
149                                                     GetProperties(),
150                                                     xImpPrMap, 0, nEndIndex, Page);
151         }
152     }
153 
154     return XMLPropStyleContext::createFastChildContext(nElement, xAttrList);
155 }
156 
FillPropertySet(const uno::Reference<beans::XPropertySet> &)157 void PageStyleContext::FillPropertySet(const uno::Reference<beans::XPropertySet > &)
158 {
159     assert(false); // don't call this virtual, call function below
160 }
161 
FillPropertySet_PageStyle(const uno::Reference<beans::XPropertySet> & xPropSet,XMLPropStyleContext * const pDrawingPageStyle)162 void PageStyleContext::FillPropertySet_PageStyle(
163         const uno::Reference<beans::XPropertySet> & xPropSet,
164         XMLPropStyleContext *const pDrawingPageStyle)
165 {
166     // need to filter out old fill definitions when the new ones are used. The new
167     // ones are used when a FillStyle is defined
168     if(!m_bIsFillStyleAlreadyConverted && !GetProperties().empty())
169     {
170         static OUString s_FillStyle("FillStyle");
171         static OUString s_HeaderFillStyle("HeaderFillStyle");
172         static OUString s_FooterFillStyle("FooterFillStyle");
173 
174         // note: the function must only check by property name, not any id/flag!
175         if (doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle)
176             || (pDrawingPageStyle && pDrawingPageStyle->doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle)))
177         {
178             deactivateOldFillStyleDefinitions(getStandardSet());
179         }
180 
181         if(doNewDrawingLayerFillStyleDefinitionsExist(s_HeaderFillStyle))
182         {
183             deactivateOldFillStyleDefinitions(getHeaderSet());
184         }
185 
186         if(doNewDrawingLayerFillStyleDefinitionsExist(s_FooterFillStyle))
187         {
188             deactivateOldFillStyleDefinitions(getFooterSet());
189         }
190 
191         m_bIsFillStyleAlreadyConverted = true;
192     }
193 
194     // do not use XMLPropStyleContext::FillPropertySet, we need to handle this ourselves since
195     // we have properties which use the MID_FLAG_NO_PROPERTY_IMPORT flag since they need some special
196     // handling
197     rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetStyles()->GetImportPropertyMapper(GetFamily());
198 
199     if(xImpPrMap.is())
200     {
201         // properties that need special handling because they need the used name to be translated first
202         struct ContextID_Index_Pair aContextIDs[] =
203         {
204             { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
205             { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
206             { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
207             { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
208 
209             // also need to special handling for header entries
210             { CTF_PM_HEADERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
211             { CTF_PM_HEADERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
212             { CTF_PM_HEADERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
213             { CTF_PM_HEADERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
214 
215             // also need to special handling for footer entries
216             { CTF_PM_FOOTERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
217             { CTF_PM_FOOTERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
218             { CTF_PM_FOOTERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
219             { CTF_PM_FOOTERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
220 
221             {-1, -1, drawing::FillStyle::FillStyle_GRADIENT}
222         };
223 
224         // the style families associated with the same index modulo 4
225         static const XmlStyleFamily aFamilies[] =
226         {
227             XmlStyleFamily::SD_GRADIENT_ID,
228             XmlStyleFamily::SD_GRADIENT_ID,
229             XmlStyleFamily::SD_HATCH_ID,
230             XmlStyleFamily::SD_FILL_IMAGE_ID
231         };
232 
233         // Fill PropertySet, but let it handle special properties not itself
234         xImpPrMap->FillPropertySet(GetProperties(), xPropSet, aContextIDs);
235 
236         // get property set mapper
237         const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
238         Reference<XPropertySetInfo> const xInfo(xPropSet->getPropertySetInfo());
239 
240         // don't look at the attributes, look at the property, could
241         // theoretically be inherited and we don't want to delete erroneously
242         drawing::FillStyle fillStyle{drawing::FillStyle_NONE};
243         drawing::FillStyle fillStyleHeader{drawing::FillStyle_NONE};
244         drawing::FillStyle fillStyleFooter{drawing::FillStyle_NONE};
245         if (xInfo->hasPropertyByName("FillStyle")) // SwXTextDefaults lacks it?
246         {
247             xPropSet->getPropertyValue("FillStyle") >>= fillStyle;
248             xPropSet->getPropertyValue("HeaderFillStyle") >>= fillStyleHeader;
249             xPropSet->getPropertyValue("FooterFillStyle") >>= fillStyleFooter;
250         }
251 
252         // handle special attributes which have MID_FLAG_NO_PROPERTY_IMPORT set
253         for(sal_uInt16 i = 0; aContextIDs[i].nContextID != -1; i++)
254         {
255             sal_Int32 nIndex = aContextIDs[i].nIndex;
256 
257             if(nIndex != -1)
258             {
259                 drawing::FillStyle const* pFillStyle(nullptr);
260                 switch(aContextIDs[i].nContextID)
261                 {
262                     case CTF_PM_FILLGRADIENTNAME:
263                     case CTF_PM_FILLTRANSNAME:
264                     case CTF_PM_FILLHATCHNAME:
265                     case CTF_PM_FILLBITMAPNAME:
266                         pFillStyle = &fillStyle;
267                         [[fallthrough]];
268                     case CTF_PM_HEADERFILLGRADIENTNAME:
269                     case CTF_PM_HEADERFILLTRANSNAME:
270                     case CTF_PM_HEADERFILLHATCHNAME:
271                     case CTF_PM_HEADERFILLBITMAPNAME:
272                         if (!pFillStyle) { pFillStyle = &fillStyleHeader; }
273                         [[fallthrough]];
274                     case CTF_PM_FOOTERFILLGRADIENTNAME:
275                     case CTF_PM_FOOTERFILLTRANSNAME:
276                     case CTF_PM_FOOTERFILLHATCHNAME:
277                     case CTF_PM_FOOTERFILLBITMAPNAME:
278                     {
279                         if (!pFillStyle) { pFillStyle = &fillStyleFooter; }
280                         struct XMLPropertyState& rState = GetProperties()[nIndex];
281                         OUString sStyleName;
282                         rState.maValue >>= sStyleName;
283 
284                         if (aContextIDs[i].nExpectedFillStyle != drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE
285                             && aContextIDs[i].nExpectedFillStyle != *pFillStyle)
286                         {
287                             SAL_INFO("xmloff.style", "PageStyleContext: dropping fill named item: " << sStyleName);
288                             break; // ignore it, it's not used
289                         }
290                         // translate the used name from ODF intern to the name used in the Model
291                         sStyleName = GetImport().GetStyleDisplayName(aFamilies[i%4], sStyleName);
292 
293                         try
294                         {
295                             // set property
296                             const OUString& rPropertyName = rMapper->GetEntryAPIName(rState.mnIndex);
297 
298                             if(xInfo->hasPropertyByName(rPropertyName))
299                             {
300                                 xPropSet->setPropertyValue(rPropertyName,Any(sStyleName));
301                             }
302                         }
303                         catch(css::lang::IllegalArgumentException& e)
304                         {
305                             Sequence<OUString> aSeq { sStyleName };
306                             GetImport().SetError(
307                                 XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING,
308                                 aSeq,e.Message,nullptr);
309                         }
310                         break;
311                     }
312                 }
313             }
314         }
315     }
316     else
317     {
318         OSL_ENSURE(xImpPrMap.is(), "Got no SvXMLImportPropertyMapper (!)");
319     }
320 
321     // pDrawingPageStyle overrides this
322     if (pDrawingPageStyle)
323     {
324         pDrawingPageStyle->FillPropertySet(xPropSet);
325     }
326     // horrible heuristic to guess BackgroundFullSize for Writer < 7.0
327     else if (!IsDefaultStyle() // ignore pool default, only fix existing styles
328             && (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x)
329             // also for AOO 4.x, assume there won't ever be a 4.2
330             || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x))
331     {
332         bool isFullSize(true); // default is current LO default
333         drawing::FillStyle fillStyle{drawing::FillStyle_NONE};
334         xPropSet->getPropertyValue("FillStyle") >>= fillStyle;
335         if (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_63x)
336             // also for AOO 4.x, assume there won't ever be a 4.2
337             || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x)
338         {
339             // before LO 6.3, always inside the margins (but ignore it if NONE)
340             if (fillStyle != drawing::FillStyle_NONE)
341             {
342                 isFullSize = false;
343             }
344         }
345         else
346         {
347             // LO 6.3/6.4: guess depending on fill style/bitmap mode
348             // this should work even if the document doesn't contain fill style
349             // but only old background attributes
350             // (can't use the aContextIDs stuff above because that requires
351             //  re-routing through handleSpecialItem())
352             switch (fillStyle)
353             {
354                 case drawing::FillStyle_NONE:
355                     break;
356                 case drawing::FillStyle_SOLID:
357                 case drawing::FillStyle_GRADIENT:
358                 case drawing::FillStyle_HATCH:
359                     isFullSize = true;
360                     break;
361                 case drawing::FillStyle_BITMAP:
362                     {
363                         drawing::BitmapMode bitmapMode{};
364                         xPropSet->getPropertyValue("FillBitmapMode") >>= bitmapMode;
365                         switch (bitmapMode)
366                         {
367                             case drawing::BitmapMode_REPEAT:
368                                 isFullSize = true;
369                                 break;
370                             case drawing::BitmapMode_STRETCH:
371                             case drawing::BitmapMode_NO_REPEAT:
372                                 isFullSize = false;
373                                 break;
374                             default:
375                                 assert(false);
376                         }
377                     }
378                     break;
379                 default:
380                     assert(false);
381             }
382         }
383         // set it explicitly if it's not the default
384         if (!isFullSize)
385         {
386             SAL_INFO("xmloff.style", "FillPropertySet_PageStyle: Heuristically resetting BackgroundFullSize");
387             xPropSet->setPropertyValue("BackgroundFullSize", uno::makeAny(isFullSize));
388         }
389     }
390 
391     // old code, replaced by above stuff
392     // XMLPropStyleContext::FillPropertySet(rPropSet);
393 
394     if (!sPageUsage.isEmpty())
395     {
396         uno::Any aPageUsage;
397         XMLPMPropHdl_PageStyleLayout aPageUsageHdl;
398         if (aPageUsageHdl.importXML(sPageUsage, aPageUsage, GetImport().GetMM100UnitConverter()))
399             xPropSet->setPropertyValue("PageStyleLayout", aPageUsage);
400     }
401 }
402 
403 extern ContextID_Index_Pair const g_MasterPageContextIDs[] =
404 {
405     { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
406     { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
407     { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
408     { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
409 
410     {-1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE}
411 };
412 
413 extern XmlStyleFamily const g_MasterPageFamilies[] =
414 {
415     XmlStyleFamily::SD_GRADIENT_ID,
416     XmlStyleFamily::SD_GRADIENT_ID,
417     XmlStyleFamily::SD_HATCH_ID,
418     XmlStyleFamily::SD_FILL_IMAGE_ID
419 };
420 
421 // text grid enhancement for better CJK support
422 //set default page layout style
SetDefaults()423 void PageStyleContext::SetDefaults( )
424 {
425     Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY);
426     if (xFactory.is())
427     {
428         Reference < XInterface > xInt = xFactory->createInstance( "com.sun.star.text.Defaults" );
429         Reference < beans::XPropertySet > xProperties ( xInt, UNO_QUERY );
430         if ( xProperties.is() )
431             FillPropertySet_PageStyle(xProperties, nullptr);
432     }
433 }
434 
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
436