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