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