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