1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27 /// @HTML
28 #include <msfilter.hxx>
29 #   include "writerwordglue.hxx"
30 #include <doc.hxx>
31 #   include "writerhelper.hxx"
32 
33 #include <algorithm>                //std::find_if
34 #include <functional>               //std::unary_function
35 
36 #include <unicode/ubidi.h>          //ubidi_getLogicalRun
37 #   include <tools/tenccvt.hxx>     //GetExtendedTextEncoding
38 #   include <i18nutil/unicode.hxx>  //unicode::getUnicodeScriptType
39 #ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HDL_
40 #   include <com/sun/star/i18n/ScriptType.hdl> //ScriptType
41 #endif
42 
43 #ifndef SV_FONTCVT_HXX
44 #   include <unotools/fontcvt.hxx>   //GetSubsFontName
45 #endif
46 #   include <editeng/paperinf.hxx>      //lA0Width...
47 #   include <editeng/lrspitem.hxx>      //SvxLRSpaceItem
48 #   include <editeng/ulspitem.hxx>      //SvxULSpaceItem
49 #   include <editeng/boxitem.hxx>       //SvxBoxItem
50 #   include <editeng/fontitem.hxx>      //SvxFontItem
51 #   include <frmfmt.hxx>            //SwFrmFmt
52 #   include <fmtclds.hxx>           //SwFmtCol
53 #   include <hfspacingitem.hxx>     //SwHeaderAndFooterEatSpacingItem
54 #   include <fmtfsize.hxx>          //SwFmtFrmSize
55 #   include <swrect.hxx>            //SwRect
56 #   include <fmthdft.hxx>           //SwFmtHeader/SwFmtFooter
57 #	include <frmatr.hxx>	        //GetLRSpace...
58 #   include <ndtxt.hxx>             //SwTxtNode
59 #   include <breakit.hxx>           //pBreakIt
60 
61 #define ASSIGN_CONST_ASC(s) AssignAscii(RTL_CONSTASCII_STRINGPARAM(s))
62 
63 namespace myImplHelpers
64 {
CalcHdFtDist(const SwFrmFmt & rFmt,sal_uInt16 nSpacing)65     SwTwips CalcHdFtDist(const SwFrmFmt& rFmt, sal_uInt16 nSpacing)
66     {
67         /*
68         #98506#
69         The normal case for reexporting word docs is to have dynamic spacing,
70         as this is word's only setting, and the reason for the existence of the
71         dynamic spacing features. If we have dynamic spacing active then we can
72         add its spacing to the value height of the h/f and get the wanted total
73         size for word.
74 
75         Otherwise we have to get the real layout rendered
76         height, which is totally nonoptimum, but the best we can do.
77         */
78         long nDist=0;
79         const SwFmtFrmSize& rSz = rFmt.GetFrmSize();
80 
81         const SwHeaderAndFooterEatSpacingItem &rSpacingCtrl =
82             sw::util::ItemGet<SwHeaderAndFooterEatSpacingItem>
83             (rFmt, RES_HEADER_FOOTER_EAT_SPACING);
84         if (rSpacingCtrl.GetValue())
85             nDist += rSz.GetHeight();
86         else
87         {
88             SwRect aRect(rFmt.FindLayoutRect(false));
89             if (aRect.Height())
90                 nDist += aRect.Height();
91             else
92             {
93                 const SwFmtFrmSize& rSize = rFmt.GetFrmSize();
94                 if (ATT_VAR_SIZE != rSize.GetHeightSizeType())
95                     nDist += rSize.GetHeight();
96                 else
97                 {
98                     nDist += 274;       // default for 12pt text
99                     nDist += nSpacing;
100                 }
101             }
102         }
103         return nDist;
104     }
105 
CalcHdDist(const SwFrmFmt & rFmt)106     SwTwips CalcHdDist(const SwFrmFmt& rFmt)
107     {
108         return CalcHdFtDist(rFmt, rFmt.GetULSpace().GetUpper());
109     }
110 
CalcFtDist(const SwFrmFmt & rFmt)111     SwTwips CalcFtDist(const SwFrmFmt& rFmt)
112     {
113         return CalcHdFtDist(rFmt, rFmt.GetULSpace().GetLower());
114     }
115 
116     /*
117      SwTxtFmtColl and SwCharFmt are quite distinct types and how they are
118      gotten is also distinct, but the algorithm to match word's eqivalents into
119      them is the same, so we put the different stuff into two separate helper
120      implementations and a core template that uses the helpers that uses the
121      same algorithm to do the work. We'll make the helpers specializations of a
122      non existing template so I can let the compiler figure out the right one
123      to use from a simple argument to the algorithm class
124     */
125     template <class C> class MapperImpl;
126     template<> class MapperImpl<SwTxtFmtColl>
127     {
128     private:
129         SwDoc &mrDoc;
130     public:
MapperImpl(SwDoc & rDoc)131         MapperImpl(SwDoc &rDoc) : mrDoc(rDoc) {}
132         SwTxtFmtColl* GetBuiltInStyle(ww::sti eSti);
133         SwTxtFmtColl* GetStyle(const String &rName);
134         SwTxtFmtColl* MakeStyle(const String &rName);
135     };
136 
GetBuiltInStyle(ww::sti eSti)137     SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::GetBuiltInStyle(ww::sti eSti)
138     {
139         const RES_POOL_COLLFMT_TYPE RES_NONE  = RES_POOLCOLL_DOC_END;
140         static const RES_POOL_COLLFMT_TYPE aArr[]=
141         {
142             RES_POOLCOLL_STANDARD, RES_POOLCOLL_HEADLINE1,
143             RES_POOLCOLL_HEADLINE2, RES_POOLCOLL_HEADLINE3,
144             RES_POOLCOLL_HEADLINE4, RES_POOLCOLL_HEADLINE5,
145             RES_POOLCOLL_HEADLINE6, RES_POOLCOLL_HEADLINE7,
146             RES_POOLCOLL_HEADLINE8, RES_POOLCOLL_HEADLINE9,
147             RES_POOLCOLL_TOX_IDX1, RES_POOLCOLL_TOX_IDX2,
148             RES_POOLCOLL_TOX_IDX3, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
149             RES_NONE, RES_NONE, RES_POOLCOLL_TOX_CNTNT1,
150             RES_POOLCOLL_TOX_CNTNT2, RES_POOLCOLL_TOX_CNTNT3,
151             RES_POOLCOLL_TOX_CNTNT4, RES_POOLCOLL_TOX_CNTNT5,
152             RES_POOLCOLL_TOX_CNTNT6, RES_POOLCOLL_TOX_CNTNT7,
153             RES_POOLCOLL_TOX_CNTNT8, RES_POOLCOLL_TOX_CNTNT9, RES_NONE,
154             RES_POOLCOLL_FOOTNOTE, RES_NONE, RES_POOLCOLL_HEADER,
155             RES_POOLCOLL_FOOTER, RES_POOLCOLL_TOX_IDXH, RES_NONE, RES_NONE,
156             RES_POOLCOLL_JAKETADRESS, RES_POOLCOLL_SENDADRESS, RES_NONE,
157             RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_POOLCOLL_ENDNOTE,
158             RES_NONE, RES_NONE, RES_NONE, RES_POOLCOLL_LISTS_BEGIN,
159             RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
160             RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
161             RES_NONE, RES_NONE, RES_POOLCOLL_DOC_TITEL, RES_NONE,
162             RES_POOLCOLL_SIGNATURE, RES_NONE, RES_POOLCOLL_TEXT,
163             RES_POOLCOLL_TEXT_MOVE, RES_NONE, RES_NONE, RES_NONE, RES_NONE,
164             RES_NONE, RES_NONE, RES_POOLCOLL_DOC_SUBTITEL
165         };
166 
167         const size_t nArrSize = (sizeof(aArr) / sizeof(aArr[0]));
168         ASSERT(nArrSize == 75, "Style Array has false size");
169 
170         SwTxtFmtColl* pRet = 0;
171         //If this is a built-in word style that has a built-in writer
172         //equivalent, then map it to one of our built in styles regardless
173         //of its name
174         if (sal::static_int_cast< size_t >(eSti) < nArrSize && aArr[eSti] != RES_NONE)
175             pRet = mrDoc.GetTxtCollFromPool( static_cast< sal_uInt16 >(aArr[eSti]), false);
176         return pRet;
177     }
178 
GetStyle(const String & rName)179     SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::GetStyle(const String &rName)
180     {
181         return sw::util::GetParaStyle(mrDoc, rName);
182     }
183 
MakeStyle(const String & rName)184     SwTxtFmtColl* MapperImpl<SwTxtFmtColl>::MakeStyle(const String &rName)
185     {
186         return mrDoc.MakeTxtFmtColl(rName,
187             const_cast<SwTxtFmtColl *>(mrDoc.GetDfltTxtFmtColl()));
188     }
189 
190     template<> class MapperImpl<SwCharFmt>
191     {
192     private:
193         SwDoc &mrDoc;
194     public:
MapperImpl(SwDoc & rDoc)195         MapperImpl(SwDoc &rDoc) : mrDoc(rDoc) {}
196         SwCharFmt* GetBuiltInStyle(ww::sti eSti);
197         SwCharFmt* GetStyle(const String &rName);
198         SwCharFmt* MakeStyle(const String &rName);
199     };
200 
GetBuiltInStyle(ww::sti eSti)201     SwCharFmt* MapperImpl<SwCharFmt>::GetBuiltInStyle(ww::sti eSti)
202     {
203         RES_POOL_CHRFMT_TYPE eLookup = RES_POOLCHR_NORMAL_END;
204         switch (eSti)
205         {
206             case ww::stiFtnRef:
207                 eLookup = RES_POOLCHR_FOOTNOTE;
208                 break;
209             case ww::stiLnn:
210                 eLookup = RES_POOLCHR_LINENUM;
211                 break;
212             case ww::stiPgn:
213                 eLookup = RES_POOLCHR_PAGENO;
214                 break;
215             case ww::stiEdnRef:
216                 eLookup = RES_POOLCHR_ENDNOTE;
217                 break;
218             case ww::stiHyperlink:
219                 eLookup = RES_POOLCHR_INET_NORMAL;
220                 break;
221             case ww::stiHyperlinkFollowed:
222                 eLookup = RES_POOLCHR_INET_VISIT;
223                 break;
224             case ww::stiStrong:
225                 eLookup = RES_POOLCHR_HTML_STRONG;
226                 break;
227             case ww::stiEmphasis:
228                 eLookup = RES_POOLCHR_HTML_EMPHASIS;
229                 break;
230             default:
231                 eLookup = RES_POOLCHR_NORMAL_END;
232                 break;
233         }
234         SwCharFmt *pRet = 0;
235         if (eLookup != RES_POOLCHR_NORMAL_END)
236             pRet = mrDoc.GetCharFmtFromPool( static_cast< sal_uInt16 >(eLookup) );
237         return pRet;
238     }
239 
GetStyle(const String & rName)240     SwCharFmt* MapperImpl<SwCharFmt>::GetStyle(const String &rName)
241     {
242         return sw::util::GetCharStyle(mrDoc, rName);
243     }
244 
MakeStyle(const String & rName)245     SwCharFmt* MapperImpl<SwCharFmt>::MakeStyle(const String &rName)
246     {
247         return mrDoc.MakeCharFmt(rName, mrDoc.GetDfltCharFmt());
248     }
249 
250     template<class C> class StyleMapperImpl
251     {
252     private:
253         MapperImpl<C> maHelper;
254         std::set<const C*> maUsedStyles;
255         C* MakeNonCollidingStyle(const String& rName);
256     public:
257         typedef std::pair<C*, bool> StyleResult;
StyleMapperImpl(SwDoc & rDoc)258         StyleMapperImpl(SwDoc &rDoc) : maHelper(rDoc) {}
259         StyleResult GetStyle(const String& rName, ww::sti eSti);
260     };
261 
262     template<class C>
263     typename StyleMapperImpl<C>::StyleResult
GetStyle(const String & rName,ww::sti eSti)264     StyleMapperImpl<C>::GetStyle(const String& rName, ww::sti eSti)
265     {
266         C *pRet = maHelper.GetBuiltInStyle(eSti);
267 
268         //If we've used it once, don't reuse it
269         if (pRet && (maUsedStyles.end() != maUsedStyles.find(pRet)))
270             pRet = 0;
271 
272         if (!pRet)
273         {
274             pRet = maHelper.GetStyle(rName);
275             //If we've used it once, don't reuse it
276             if (pRet && (maUsedStyles.end() != maUsedStyles.find(pRet)))
277                 pRet = 0;
278         }
279 
280         bool bStyExist = pRet ? true : false;
281 
282         if (!pRet)
283         {
284             String aName(rName);
285             xub_StrLen nPos = aName.Search(',');
286             // No commas allow in SW style names
287             if (STRING_NOTFOUND != nPos)
288                 aName.Erase(nPos);
289             pRet = MakeNonCollidingStyle(aName);
290         }
291 
292         if (pRet)
293             maUsedStyles.insert(pRet);
294 
295         return StyleResult(pRet, bStyExist);
296     }
297 
298     template<class C>
MakeNonCollidingStyle(const String & rName)299     C* StyleMapperImpl<C>::MakeNonCollidingStyle(const String& rName)
300     {
301         String aName(rName);
302         C* pColl = 0;
303 
304         if (0 != (pColl = maHelper.GetStyle(aName)))
305         {
306             //If the style collides first stick WW- in front of it, unless
307             //it already has it and then successively add a larger and
308             //larger number after it, its got to work at some stage!
309             if (!aName.EqualsIgnoreCaseAscii("WW-", 0, 3))
310                 aName.InsertAscii("WW-" , 0);
311 
312             sal_Int32 nI = 1;
313             while (
314                     0 != (pColl = maHelper.GetStyle(aName)) &&
315                     (nI < SAL_MAX_INT32)
316                   )
317             {
318                 aName += String::CreateFromInt32(nI++);
319             }
320         }
321 
322         return pColl ? 0 : maHelper.MakeStyle(aName);
323     }
324 
FindBestMSSubstituteFont(const String & rFont)325     String FindBestMSSubstituteFont(const String &rFont)
326     {
327         String sRet;
328         if (sw::util::IsStarSymbol(rFont))
329             sRet.ASSIGN_CONST_ASC("Arial Unicode MS");
330         else
331             sRet = GetSubsFontName(rFont, SUBSFONT_ONLYONE | SUBSFONT_MS);
332         return sRet;
333     }
334 
335     /*
336      Utility to categorize unicode characters into the best fit windows charset
337      range for exporting to ww6, or as a hint to non \u unicode token aware rtf
338      readers
339     */
getScriptClass(sal_Unicode cChar)340     rtl_TextEncoding getScriptClass(sal_Unicode cChar)
341     {
342         using namespace ::com::sun::star::i18n;
343 
344         static ScriptTypeList aScripts[] =
345         {
346             { UnicodeScript_kBasicLatin, UnicodeScript_kBasicLatin, RTL_TEXTENCODING_MS_1252},
347             { UnicodeScript_kLatin1Supplement, UnicodeScript_kLatin1Supplement, RTL_TEXTENCODING_MS_1252},
348             { UnicodeScript_kLatinExtendedA, UnicodeScript_kLatinExtendedA, RTL_TEXTENCODING_MS_1250},
349             { UnicodeScript_kLatinExtendedB, UnicodeScript_kLatinExtendedB, RTL_TEXTENCODING_MS_1257},
350             { UnicodeScript_kGreek, UnicodeScript_kGreek, RTL_TEXTENCODING_MS_1253},
351             { UnicodeScript_kCyrillic, UnicodeScript_kCyrillic, RTL_TEXTENCODING_MS_1251},
352             { UnicodeScript_kHebrew, UnicodeScript_kHebrew, RTL_TEXTENCODING_MS_1255},
353             { UnicodeScript_kArabic, UnicodeScript_kArabic, RTL_TEXTENCODING_MS_1256},
354             { UnicodeScript_kThai, UnicodeScript_kThai, RTL_TEXTENCODING_MS_1258},
355             { UnicodeScript_kHangulJamo, UnicodeScript_kHangulJamo, RTL_TEXTENCODING_MS_949},
356             { UnicodeScript_kHangulCompatibilityJamo, UnicodeScript_kHangulCompatibilityJamo, RTL_TEXTENCODING_MS_949},
357             { UnicodeScript_kHangulSyllable, UnicodeScript_kHangulSyllable, RTL_TEXTENCODING_MS_949},
358             { UnicodeScript_kScriptCount, UnicodeScript_kScriptCount, RTL_TEXTENCODING_MS_1252}
359         };
360 
361         return unicode::getUnicodeScriptType(cChar, aScripts,
362             RTL_TEXTENCODING_MS_1252);
363     }
364 
365     //Utility to remove entries before a given starting position
366     class IfBeforeStart
367         : public std::unary_function<const sw::util::CharRunEntry&, bool>
368     {
369     private:
370         xub_StrLen mnStart;
371     public:
IfBeforeStart(xub_StrLen nStart)372         IfBeforeStart(xub_StrLen nStart) : mnStart(nStart) {}
operator ()(const sw::util::CharRunEntry & rEntry) const373         bool operator()(const sw::util::CharRunEntry &rEntry) const
374         {
375             return rEntry.mnEndPos < mnStart;
376         }
377     };
378 }
379 
380 namespace sw
381 {
382     namespace util
383     {
384 
IsPlausableSingleWordSection(const SwFrmFmt & rTitleFmt,const SwFrmFmt & rFollowFmt,sal_Int8 nDocType)385         bool IsPlausableSingleWordSection(const SwFrmFmt &rTitleFmt,
386             const SwFrmFmt &rFollowFmt, sal_Int8 nDocType )
387         {
388             bool bPlausableTitlePage = true;
389 
390             const SwFmtCol& rFirstCols = rTitleFmt.GetCol();
391             const SwFmtCol& rFollowCols = rFollowFmt.GetCol();
392             const SwColumns& rFirstColumns = rFirstCols.GetColumns();
393             const SwColumns& rFollowColumns = rFollowCols.GetColumns();
394             const SvxLRSpaceItem &rOneLR = rTitleFmt.GetLRSpace();
395             const SvxLRSpaceItem &rTwoLR= rFollowFmt.GetLRSpace();
396 
397             if (rFirstColumns.Count() != rFollowColumns.Count())
398             {
399                 //e.g. #i4320#
400                 bPlausableTitlePage = false;
401             }
402             else if (rOneLR != rTwoLR)
403                 bPlausableTitlePage = false;
404             else
405             {
406                 HdFtDistanceGlue aOne(rTitleFmt.GetAttrSet());
407                 HdFtDistanceGlue aTwo(rFollowFmt.GetAttrSet());
408                 //if one doesn't own a footer, then assume it equals with the other one.
409                 const sal_Bool bCheckFooter = ( aOne.HasFooter() && aTwo.HasFooter() ) ? sal_True : sal_False;
410                 //e.g. #i14509#
411                 if (!aOne.EqualTopBottom(aTwo) && nDocType != 1 && bCheckFooter )
412                     bPlausableTitlePage = false;
413             }
414             return bPlausableTitlePage;
415         }
416 
HdFtDistanceGlue(const SfxItemSet & rPage)417         HdFtDistanceGlue::HdFtDistanceGlue(const SfxItemSet &rPage)
418         {
419             if (const SvxBoxItem *pBox = HasItem<SvxBoxItem>(rPage, RES_BOX))
420             {
421                 dyaHdrTop = pBox->CalcLineSpace(BOX_LINE_TOP);
422                 dyaHdrBottom = pBox->CalcLineSpace(BOX_LINE_BOTTOM);
423             }
424             else
425             {
426                 dyaHdrTop = dyaHdrBottom = 0;
427                 dyaHdrBottom = 0;
428             }
429             const SvxULSpaceItem &rUL =
430                 ItemGet<SvxULSpaceItem>(rPage, RES_UL_SPACE);
431             dyaHdrTop = dyaHdrTop + rUL.GetUpper();
432             dyaHdrBottom = dyaHdrBottom + rUL.GetLower();
433 
434             dyaTop = dyaHdrTop;
435             dyaBottom = dyaHdrBottom;
436 
437             using sw::types::msword_cast;
438 
439             const SwFmtHeader *pHd = HasItem<SwFmtHeader>(rPage, RES_HEADER);
440             if (pHd && pHd->IsActive() && pHd->GetHeaderFmt())
441             {
442                 mbHasHeader = true;
443                 dyaTop = dyaTop + static_cast< sal_uInt16 >( (myImplHelpers::CalcHdDist(*(pHd->GetHeaderFmt()))) );
444             }
445             else
446                 mbHasHeader = false;
447 
448             const SwFmtFooter *pFt = HasItem<SwFmtFooter>(rPage, RES_FOOTER);
449             if (pFt && pFt->IsActive() && pFt->GetFooterFmt())
450             {
451                 mbHasFooter = true;
452                 dyaBottom = dyaBottom + static_cast< sal_uInt16 >( (myImplHelpers::CalcFtDist(*(pFt->GetFooterFmt()))) );
453             }
454             else
455                 mbHasFooter = false;
456         }
457 
EqualTopBottom(const HdFtDistanceGlue & rOther) const458         bool HdFtDistanceGlue::EqualTopBottom(const HdFtDistanceGlue &rOther)
459             const
460         {
461             return (dyaTop == rOther.dyaTop && dyaBottom == rOther.dyaBottom);
462         }
463 
ParaStyleMapper(SwDoc & rDoc)464         ParaStyleMapper::ParaStyleMapper(SwDoc &rDoc)
465 			: mpImpl(new myImplHelpers::StyleMapperImpl<SwTxtFmtColl>(rDoc))
466         {
467         }
468 
~ParaStyleMapper()469         ParaStyleMapper::~ParaStyleMapper()
470         {
471             delete mpImpl;
472         }
473 
GetStyle(const String & rName,ww::sti eSti)474         ParaStyleMapper::StyleResult ParaStyleMapper::GetStyle(
475             const String& rName, ww::sti eSti)
476         {
477             return mpImpl->GetStyle(rName, eSti);
478         }
479 
CharStyleMapper(SwDoc & rDoc)480         CharStyleMapper::CharStyleMapper(SwDoc &rDoc)
481 			: mpImpl(new myImplHelpers::StyleMapperImpl<SwCharFmt>(rDoc))
482         {
483         }
484 
~CharStyleMapper()485         CharStyleMapper::~CharStyleMapper()
486         {
487             delete mpImpl;
488         }
489 
GetStyle(const String & rName,ww::sti eSti)490         CharStyleMapper::StyleResult CharStyleMapper::GetStyle(
491             const String& rName, ww::sti eSti)
492         {
493             return mpImpl->GetStyle(rName, eSti);
494         }
495 
FontMapExport(const String & rFamilyName)496         FontMapExport::FontMapExport(const String &rFamilyName)
497         {
498             msPrimary = GetFontToken(rFamilyName, 0);
499 			msSecondary = myImplHelpers::FindBestMSSubstituteFont(msPrimary);
500             if (!msSecondary.Len())
501                 msSecondary = GetFontToken(rFamilyName, 1);
502         }
503 
HasDistinctSecondary() const504         bool FontMapExport::HasDistinctSecondary() const
505         {
506             if (msSecondary.Len() && msSecondary != msPrimary)
507                 return true;
508             return false;
509         }
510 
operator ()(sal_uInt16 nA,sal_uInt16 nB) const511         bool ItemSort::operator()(sal_uInt16 nA, sal_uInt16 nB) const
512         {
513             /*
514              #i24291#
515              All we want to do is ensure for now is that if a charfmt exist
516              in the character properties that it rises to the top and is
517              exported first.  In the future we might find more ordering
518              depandancies for export, in which case this is the place to do
519              it
520             */
521             if (nA == nB)
522                 return false;
523             if (nA == RES_TXTATR_CHARFMT)
524                 return true;
525             if (nB == RES_TXTATR_CHARFMT)
526                 return false;
527             if (nA == RES_TXTATR_INETFMT)
528                 return true;
529             if (nB == RES_TXTATR_INETFMT)
530                return false;
531             return nA < nB;
532         }
533 
GetPseudoCharRuns(const SwTxtNode & rTxtNd,xub_StrLen nTxtStart,bool bSplitOnCharSet)534         CharRuns GetPseudoCharRuns(const SwTxtNode& rTxtNd,
535             xub_StrLen nTxtStart, bool bSplitOnCharSet)
536         {
537             const String &rTxt = rTxtNd.GetTxt();
538 
539             bool bParaIsRTL = false;
540             ASSERT(rTxtNd.GetDoc(), "No document for node?, suspicious");
541             if (rTxtNd.GetDoc())
542             {
543                 if (FRMDIR_HORI_RIGHT_TOP ==
544                     rTxtNd.GetDoc()->GetTextDirection(SwPosition(rTxtNd)))
545                 {
546                     bParaIsRTL = true;
547                 }
548             }
549 
550             using namespace ::com::sun::star::i18n;
551 
552 			sal_uInt16 nScript = i18n::ScriptType::LATIN;
553             if (rTxt.Len() && pBreakIt && pBreakIt->GetBreakIter().is())
554                 nScript = pBreakIt->GetBreakIter()->getScriptType(rTxt, 0);
555 
556             rtl_TextEncoding eChrSet = ItemGet<SvxFontItem>(rTxtNd,
557                 GetWhichOfScript(RES_CHRATR_FONT, nScript)).GetCharSet();
558             eChrSet = GetExtendedTextEncoding(eChrSet);
559 
560             CharRuns aRunChanges;
561 
562             if (!rTxt.Len())
563             {
564                 aRunChanges.push_back(CharRunEntry(0, nScript, eChrSet,
565                     bParaIsRTL));
566                 return aRunChanges;
567             }
568 
569             typedef std::pair<int32_t, bool> DirEntry;
570             typedef std::vector<DirEntry> DirChanges;
571             typedef DirChanges::const_iterator cDirIter;
572 
573             typedef std::pair<xub_StrLen, sal_Int16> CharSetEntry;
574             typedef std::vector<CharSetEntry> CharSetChanges;
575             typedef CharSetChanges::const_iterator cCharSetIter;
576 
577             typedef std::pair<xub_StrLen, sal_uInt16> ScriptEntry;
578             typedef std::vector<ScriptEntry> ScriptChanges;
579             typedef ScriptChanges::const_iterator cScriptIter;
580 
581             DirChanges aDirChanges;
582             CharSetChanges aCharSets;
583             ScriptChanges aScripts;
584 
585             UBiDiDirection eDefaultDir = bParaIsRTL ? UBIDI_RTL : UBIDI_LTR;
586             UErrorCode nError = U_ZERO_ERROR;
587             UBiDi* pBidi = ubidi_openSized(rTxt.Len(), 0, &nError);
588             ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(rTxt.GetBuffer()), rTxt.Len(),
589                     static_cast< UBiDiLevel >(eDefaultDir), 0, &nError);
590 
591             sal_Int32 nCount = ubidi_countRuns(pBidi, &nError);
592             aDirChanges.reserve(nCount);
593 
594             int32_t nStart = 0;
595             int32_t nEnd;
596             UBiDiLevel nCurrDir;
597 
598             for (sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx)
599             {
600                 ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir);
601                 /*
602                 UBiDiLevel is the type of the level values in this BiDi
603                 implementation.
604 
605                 It holds an embedding level and indicates the visual direction
606                 by its bit 0 (even/odd value).
607 
608                 The value for UBIDI_DEFAULT_LTR is even and the one for
609                 UBIDI_DEFAULT_RTL is odd
610                 */
611                 aDirChanges.push_back(DirEntry(nEnd, nCurrDir & 0x1));
612                 nStart = nEnd;
613             }
614             ubidi_close(pBidi);
615 
616             if (bSplitOnCharSet)
617             {
618                 //Split unicode text into plausible 8bit ranges for export to
619                 //older non unicode aware format
620                 xub_StrLen nLen = rTxt.Len();
621                 xub_StrLen nPos = 0;
622                 while (nPos != nLen)
623                 {
624                     rtl_TextEncoding ScriptType =
625 						myImplHelpers::getScriptClass(rTxt.GetChar(nPos++));
626                     while (
627                             (nPos != nLen) &&
628 							(ScriptType == myImplHelpers::getScriptClass(rTxt.GetChar(nPos)))
629                           )
630                     {
631                         ++nPos;
632                     }
633 
634                     aCharSets.push_back(CharSetEntry(nPos, ScriptType));
635                 }
636             }
637 
638             using sw::types::writer_cast;
639 
640             if (pBreakIt && pBreakIt->GetBreakIter().is())
641             {
642                 xub_StrLen nLen = rTxt.Len();
643                 xub_StrLen nPos = 0;
644                 while (nPos < nLen)
645                 {
646                     sal_Int32 nEnd2 = pBreakIt->GetBreakIter()->endOfScript(rTxt, nPos,
647                         nScript);
648                     if (nEnd2 < 0)
649                         break;
650 //                    nPos = writer_cast<xub_StrLen>(nEnd2);
651                     nPos = static_cast< xub_StrLen >(nEnd2);
652                     aScripts.push_back(ScriptEntry(nPos, nScript));
653                     nScript = pBreakIt->GetBreakIter()->getScriptType(rTxt, nPos);
654                 }
655             }
656 
657             cDirIter aBiDiEnd = aDirChanges.end();
658             cCharSetIter aCharSetEnd = aCharSets.end();
659             cScriptIter aScriptEnd = aScripts.end();
660 
661             cDirIter aBiDiIter = aDirChanges.begin();
662             cCharSetIter aCharSetIter = aCharSets.begin();
663             cScriptIter aScriptIter = aScripts.begin();
664 
665             bool bCharIsRTL = bParaIsRTL;
666 
667             while (
668                     aBiDiIter != aBiDiEnd ||
669                     aCharSetIter != aCharSetEnd ||
670                     aScriptIter != aScriptEnd
671                   )
672             {
673                 xub_StrLen nMinPos = rTxt.Len();
674 
675                 if (aBiDiIter != aBiDiEnd)
676                 {
677                     if (aBiDiIter->first < nMinPos)
678 //                        nMinPos = writer_cast<xub_StrLen>(aBiDiIter->first);
679                         nMinPos = static_cast< xub_StrLen >(aBiDiIter->first);
680                     bCharIsRTL = aBiDiIter->second;
681                 }
682 
683                 if (aCharSetIter != aCharSetEnd)
684                 {
685                     if (aCharSetIter->first < nMinPos)
686                         nMinPos = aCharSetIter->first;
687                     eChrSet = aCharSetIter->second;
688                 }
689 
690                 if (aScriptIter != aScriptEnd)
691                 {
692                     if (aScriptIter->first < nMinPos)
693                         nMinPos = aScriptIter->first;
694                     nScript = aScriptIter->second;
695                 }
696 
697                 aRunChanges.push_back(
698                     CharRunEntry(nMinPos, nScript, eChrSet, bCharIsRTL));
699 
700                 if (aBiDiIter != aBiDiEnd)
701                 {
702                     if (aBiDiIter->first == nMinPos)
703                         ++aBiDiIter;
704                 }
705 
706                 if (aCharSetIter != aCharSetEnd)
707                 {
708                     if (aCharSetIter->first == nMinPos)
709                         ++aCharSetIter;
710                 }
711 
712                 if (aScriptIter != aScriptEnd)
713                 {
714                     if (aScriptIter->first == nMinPos)
715                         ++aScriptIter;
716                 }
717             }
718 
719             aRunChanges.erase(std::remove_if(aRunChanges.begin(),
720 				aRunChanges.end(), myImplHelpers::IfBeforeStart(nTxtStart)), aRunChanges.end());
721 
722             return aRunChanges;
723         }
724     }
725 
726     namespace ms
727     {
rtl_TextEncodingToWinCharset(rtl_TextEncoding eTextEncoding)728         sal_uInt8 rtl_TextEncodingToWinCharset(rtl_TextEncoding eTextEncoding)
729         {
730             sal_uInt8 nRet =
731                 rtl_getBestWindowsCharsetFromTextEncoding(eTextEncoding);
732             switch (eTextEncoding)
733             {
734             	case RTL_TEXTENCODING_DONTKNOW:
735             	case RTL_TEXTENCODING_UCS2:
736             	case RTL_TEXTENCODING_UTF7:
737             	case RTL_TEXTENCODING_UTF8:
738             	case RTL_TEXTENCODING_JAVA_UTF8:
739                     ASSERT(nRet != 0x80, "This method may be redundant");
740                     nRet = 0x80;
741             	    break;
742             	default:
743             	    break;
744             }
745             return nRet;
746         }
747 
DateTime2DTTM(const DateTime & rDT)748         long DateTime2DTTM( const DateTime& rDT )
749         {
750         /*
751         mint    short   :6  0000003F    minutes (0-59)
752         hr      short   :5  000007C0    hours (0-23)
753         dom     short   :5  0000F800    days of month (1-31)
754         mon     short   :4  000F0000    months (1-12)
755         yr      short   :9  1FF00000    years (1900-2411)-1900
756         wdy     short   :3  E0000000    weekday(Sunday=0
757                                                 Monday=1
758         ( wdy can be ignored )                  Tuesday=2
759                                                 Wednesday=3
760                                                 Thursday=4
761                                                 Friday=5
762                                                 Saturday=6)
763         */
764 
765             if ( rDT.GetDate() == 0L )
766 				return 0L;
767 			long nDT = ( rDT.GetDayOfWeek() + 1 ) % 7;
768             nDT <<= 9;
769             nDT += ( rDT.GetYear() - 1900 ) & 0x1ff;
770             nDT <<= 4;
771             nDT += rDT.GetMonth() & 0xf;
772             nDT <<= 5;
773             nDT += rDT.GetDay() & 0x1f;
774             nDT <<= 5;
775             nDT += rDT.GetHour() & 0x1f;
776             nDT <<= 6;
777             nDT += rDT.GetMin() & 0x3f;
778             return nDT;
779         }
780 
DTTM2DateTime(long lDTTM)781         DateTime DTTM2DateTime( long lDTTM )
782         {
783             /*
784             mint    short   :6  0000003F    minutes (0-59)
785             hr      short   :5  000007C0    hours (0-23)
786             dom     short   :5  0000F800    days of month (1-31)
787             mon     short   :4  000F0000    months (1-12)
788             yr      short   :9  1FF00000    years (1900-2411)-1900
789             wdy     short   :3  E0000000    weekday(Sunday=0
790                                                     Monday=1
791             ( wdy can be ignored )                  Tuesday=2
792                                                     Wednesday=3
793                                                     Thursday=4
794                                                     Friday=5
795                                                     Saturday=6)
796             */
797             DateTime aDateTime(Date( 0 ), Time( 0 ));
798             if( lDTTM )
799             {
800                 sal_uInt16 lMin = (sal_uInt16)(lDTTM & 0x0000003F);
801                 lDTTM >>= 6;
802                 sal_uInt16 lHour= (sal_uInt16)(lDTTM & 0x0000001F);
803                 lDTTM >>= 5;
804                 sal_uInt16 lDay = (sal_uInt16)(lDTTM & 0x0000001F);
805                 lDTTM >>= 5;
806                 sal_uInt16 lMon = (sal_uInt16)(lDTTM & 0x0000000F);
807                 lDTTM >>= 4;
808                 sal_uInt16 lYear= (sal_uInt16)(lDTTM & 0x000001FF) + 1900;
809                 aDateTime = DateTime(Date(lDay, lMon, lYear), Time(lHour, lMin));
810             }
811             return aDateTime;
812         }
813 
MSDateTimeFormatToSwFormat(String & rParams,SvNumberFormatter * pFormatter,sal_uInt16 & rLang,bool bHijri)814         sal_uLong MSDateTimeFormatToSwFormat(String& rParams,
815             SvNumberFormatter *pFormatter, sal_uInt16 &rLang, bool bHijri)
816         {
817             // tell the Formatter about the new entry
818             sal_uInt16 nCheckPos = 0;
819             short  nType = NUMBERFORMAT_DEFINED;
820             sal_uInt32  nKey = 0;
821 
822             SwapQuotesInField(rParams);
823 
824             //#102782#, #102815#, #108341# & #111944# have to work at the same time :-)
825             bool bForceJapanese(false);
826             bool bForceNatNum(false);
827             xub_StrLen nLen = rParams.Len();
828             xub_StrLen nI = 0;
829             while (nI < nLen)
830             {
831                 if (rParams.GetChar(nI) == '\\')
832                     nI++;
833                 else if (rParams.GetChar(nI) == '\"')
834                 {
835                     ++nI;
836                     //While not at the end and not at an unescaped end quote
837                     while ((nI < nLen) && (!(rParams.GetChar(nI) == '\"') && (rParams.GetChar(nI-1) != '\\')))
838                         ++nI;
839                 }
840                 else //normal unquoted section
841                 {
842                     sal_Unicode nChar = rParams.GetChar(nI);
843                     if (nChar == 'O')
844                     {
845                         rParams.SetChar(nI, 'M');
846                         bForceNatNum = true;
847                     }
848                     else if (nChar == 'o')
849                     {
850                         rParams.SetChar(nI, 'm');
851                         bForceNatNum = true;
852                     }
853                     else if ((nChar == 'A') && IsNotAM(rParams, nI))
854                     {
855                         rParams.SetChar(nI, 'D');
856                         bForceNatNum = true;
857                     }
858                     else if ((nChar == 'g') || (nChar == 'G'))
859                         bForceJapanese = true;
860                     else if ((nChar == 'a') && IsNotAM(rParams, nI))
861                         bForceJapanese = true;
862                     else if (nChar == 'E')
863                     {
864                         if ((nI != nLen-1) && (rParams.GetChar(nI+1) == 'E'))
865                         {
866                             rParams.Replace(nI, 2, CREATE_CONST_ASC("YYYY"));
867                             nLen+=2;
868                             nI+=3;
869                         }
870                         bForceJapanese = true;
871                     }
872                     else if (nChar == 'e')
873                     {
874                         if ((nI != nLen-1) && (rParams.GetChar(nI+1) == 'e'))
875                         {
876                             rParams.Replace(nI, 2, CREATE_CONST_ASC("yyyy"));
877                             nLen+=2;
878                             nI+=3;
879                         }
880                         bForceJapanese = true;
881                     }
882                     else if (nChar == '/')
883                     {
884 						if(!(IsPreviousAM(rParams, nI) && IsNextPM(rParams, nI)))
885                             // MM We have to escape '/' in case it's used as a char
886                             rParams.Replace(nI, 1, CREATE_CONST_ASC("\\/"));
887                         // rParams.Insert( nI, '\\' );
888                         nI++;
889                         nLen++;
890                     }
891 
892                     // Deal with language differences in date format expression.
893                     // Should be made with i18n framework.
894                     // The list of the mappings and of those "special" locales is to be found at:
895                     // http://l10n.openoffice.org/i18n_framework/LocaleData.html
896                     switch ( rLang )
897                     {
898                     case LANGUAGE_FINNISH:
899                         {
900                             if (nChar == 'y' || nChar == 'Y')
901                                 rParams.SetChar (nI, 'V');
902                             else if (nChar == 'm' || nChar == 'M')
903                                 rParams.SetChar (nI, 'K');
904                             else if (nChar == 'd' || nChar == 'D')
905                                 rParams.SetChar (nI, 'P');
906                             else if (nChar == 'h' || nChar == 'H')
907                                 rParams.SetChar (nI, 'T');
908                         }
909                         break;
910                     case LANGUAGE_DANISH:
911                     case LANGUAGE_NORWEGIAN:
912                     case LANGUAGE_NORWEGIAN_BOKMAL:
913                     case LANGUAGE_NORWEGIAN_NYNORSK:
914                     case LANGUAGE_SWEDISH:
915                     case LANGUAGE_SWEDISH_FINLAND:
916                         {
917                             if (nChar == 'h' || nChar == 'H')
918                                 rParams.SetChar (nI, 'T');
919                         }
920                         break;
921                     case LANGUAGE_PORTUGUESE:
922                     case LANGUAGE_PORTUGUESE_BRAZILIAN:
923                     case LANGUAGE_SPANISH_MODERN:
924                     case LANGUAGE_SPANISH_DATED:
925                     case LANGUAGE_SPANISH_MEXICAN:
926                     case LANGUAGE_SPANISH_GUATEMALA:
927                     case LANGUAGE_SPANISH_COSTARICA:
928                     case LANGUAGE_SPANISH_PANAMA:
929                     case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC:
930                     case LANGUAGE_SPANISH_VENEZUELA:
931                     case LANGUAGE_SPANISH_COLOMBIA:
932                     case LANGUAGE_SPANISH_PERU:
933                     case LANGUAGE_SPANISH_ARGENTINA:
934                     case LANGUAGE_SPANISH_ECUADOR:
935                     case LANGUAGE_SPANISH_CHILE:
936                     case LANGUAGE_SPANISH_URUGUAY:
937                     case LANGUAGE_SPANISH_PARAGUAY:
938                     case LANGUAGE_SPANISH_BOLIVIA:
939                     case LANGUAGE_SPANISH_EL_SALVADOR:
940                     case LANGUAGE_SPANISH_HONDURAS:
941                     case LANGUAGE_SPANISH_NICARAGUA:
942                     case LANGUAGE_SPANISH_PUERTO_RICO:
943                         {
944                             if (nChar == 'a' || nChar == 'A')
945                                 rParams.SetChar (nI, 'O');
946                             else if (nChar == 'y' || nChar == 'Y')
947                                 rParams.SetChar (nI, 'A');
948                         }
949                         break;
950                     case LANGUAGE_DUTCH:
951                     case LANGUAGE_DUTCH_BELGIAN:
952                         {
953                             if (nChar == 'y' || nChar == 'Y')
954                                 rParams.SetChar (nI, 'J');
955                             else if (nChar == 'u' || nChar == 'U')
956                                 rParams.SetChar (nI, 'H');
957                         }
958                         break;
959                     case LANGUAGE_ITALIAN:
960                     case LANGUAGE_ITALIAN_SWISS:
961                         {
962                             if (nChar == 'a' || nChar == 'A')
963                                 rParams.SetChar (nI, 'O');
964                             else if (nChar == 'g' || nChar == 'G')
965                                 rParams.SetChar (nI, 'X');
966                             else if (nChar == 'y' || nChar == 'Y')
967                                 rParams.SetChar(nI, 'A');
968                             else if (nChar == 'd' || nChar == 'D')
969                                 rParams.SetChar (nI, 'G');
970                         }
971                         break;
972                     case LANGUAGE_GERMAN:
973                     case LANGUAGE_GERMAN_SWISS:
974                     case LANGUAGE_GERMAN_AUSTRIAN:
975                     case LANGUAGE_GERMAN_LUXEMBOURG:
976                     case LANGUAGE_GERMAN_LIECHTENSTEIN:
977                         {
978                             if (nChar == 'y' || nChar == 'Y')
979                                 rParams.SetChar (nI, 'J');
980                             else if (nChar == 'd' || nChar == 'D')
981                                 rParams.SetChar (nI, 'T');
982                         }
983                         break;
984                     case LANGUAGE_FRENCH:
985                     case LANGUAGE_FRENCH_BELGIAN:
986                     case LANGUAGE_FRENCH_CANADIAN:
987                     case LANGUAGE_FRENCH_SWISS:
988                     case LANGUAGE_FRENCH_LUXEMBOURG:
989                     case LANGUAGE_FRENCH_MONACO:
990                         {
991                             if (nChar == 'a' || nChar == 'A')
992                                 rParams.SetChar (nI, 'O');
993                             else if (nChar == 'y' || nChar == 'Y')
994                                 rParams.SetChar (nI, 'A');
995                             else if (nChar == 'd' || nChar == 'D')
996                                 rParams.SetChar (nI, 'J');
997                         }
998                         break;
999                     default:
1000                         {
1001                             ; // Nothing
1002                         }
1003                     }
1004                 }
1005                 ++nI;
1006             }
1007 
1008             if (bForceNatNum)
1009                 bForceJapanese = true;
1010 
1011             if (bForceJapanese)
1012                 rLang = LANGUAGE_JAPANESE;
1013 
1014             if (bForceNatNum)
1015                 rParams.Insert(CREATE_CONST_ASC("[NatNum1][$-411]"),0);
1016 
1017             if (bHijri)
1018                 rParams.Insert(CREATE_CONST_ASC("[~hijri]"), 0);
1019 
1020             pFormatter->PutEntry(rParams, nCheckPos, nType, nKey, rLang);
1021 
1022             return nKey;
1023         }
1024 
IsPreviousAM(String & rParams,xub_StrLen nPos)1025 		sal_Bool IsPreviousAM(String& rParams, xub_StrLen nPos){
1026 			xub_StrLen nPos1 = nPos - 1;
1027 			xub_StrLen nPos2 = nPos - 2;
1028 
1029 			if(nPos1 > nPos || nPos2 > nPos){
1030 				return sal_False;
1031 			}else{
1032 				return (
1033 					(rParams.GetChar(nPos1) == 'M'||rParams.GetChar(nPos1) == 'm')&&
1034 					(rParams.GetChar(nPos2) == 'A'||rParams.GetChar(nPos2) == 'a')
1035 					);
1036 			}
1037 		}
IsNextPM(String & rParams,xub_StrLen nPos)1038 		sal_Bool IsNextPM(String& rParams, xub_StrLen nPos){
1039 			xub_StrLen nPos1 = nPos + 1;
1040 			xub_StrLen nPos2 = nPos + 2;
1041 
1042 
1043 			if(nPos1 >= rParams.Len() - 1 || nPos2 > rParams.Len() - 1){
1044 				return sal_False;
1045 			}else{
1046 				return (
1047 					(rParams.GetChar(nPos1) == 'P'||rParams.GetChar(nPos1) == 'p')&&
1048 					(rParams.GetChar(nPos2) == 'M'||rParams.GetChar(nPos2) == 'm')
1049 					);
1050 			}
1051 
1052 		}
IsNotAM(String & rParams,xub_StrLen nPos)1053         bool IsNotAM(String& rParams, xub_StrLen nPos)
1054         {
1055             return (
1056                     (nPos == rParams.Len() - 1) ||
1057                     (
1058                     (rParams.GetChar(nPos+1) != 'M') &&
1059                     (rParams.GetChar(nPos+1) != 'm')
1060                     )
1061                 );
1062         }
1063 
SwapQuotesInField(String & rFmt)1064         void SwapQuotesInField(String &rFmt)
1065         {
1066             //Swap unescaped " and ' with ' and "
1067             xub_StrLen nLen = rFmt.Len();
1068             for (xub_StrLen nI = 0; nI < nLen; ++nI)
1069             {
1070                 if ((rFmt.GetChar(nI) == '\"') && (!nI || rFmt.GetChar(nI-1) != '\\'))
1071                     rFmt.SetChar(nI, '\'');
1072                 else if ((rFmt.GetChar(nI) == '\'') && (!nI || rFmt.GetChar(nI-1) != '\\'))
1073                     rFmt.SetChar(nI, '\"');
1074             }
1075         }
1076 
1077 
1078     }
1079 }
1080 
1081 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
1082