LCOV - code coverage report
Current view: top level - sw/source/filter/ww8 - writerwordglue.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 379 480 79.0 %
Date: 2014-11-03 Functions: 48 48 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10