nss: upgrade to release 3.73
[LibreOffice.git] / editeng / source / rtf / svxrtf.cxx
blob17ef94553ec538e464d5fb3f49a1c25a6dafae51
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <queue>
22 #include <tools/diagnose_ex.h>
23 #include <rtl/tencinfo.h>
24 #include <svl/itemiter.hxx>
25 #include <svl/whiter.hxx>
26 #include <svtools/rtftoken.h>
27 #include <svl/itempool.hxx>
28 #include <i18nlangtag/languagetag.hxx>
29 #include <tools/debug.hxx>
31 #include <comphelper/string.hxx>
33 #include <editeng/scriptspaceitem.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/svxrtf.hxx>
36 #include <editeng/editids.hrc>
37 #include <vcl/font.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/settings.hxx>
42 using namespace ::com::sun::star;
45 static rtl_TextEncoding lcl_GetDefaultTextEncodingForRTF()
48 OUString aLangString( Application::GetSettings().GetLanguageTag().getLanguage());
50 if ( aLangString == "ru" || aLangString == "uk" )
51 return RTL_TEXTENCODING_MS_1251;
52 if ( aLangString == "tr" )
53 return RTL_TEXTENCODING_MS_1254;
54 else
55 return RTL_TEXTENCODING_MS_1252;
58 // -------------- Methods --------------------
60 SvxRTFParser::SvxRTFParser( SfxItemPool& rPool, SvStream& rIn )
61 : SvRTFParser( rIn, 5 )
62 , aPlainMap(rPool)
63 , aPardMap(rPool)
64 , pAttrPool( &rPool )
65 , nDfltFont( 0)
66 , bNewDoc( true )
67 , bNewGroup( false)
68 , bIsSetDfltTab( false)
69 , bChkStyleAttr( false )
70 , bCalcValue( false )
71 , bIsLeftToRightDef( true)
72 , bIsInReadStyleTab( false)
74 pDfltFont.reset( new vcl::Font );
75 mxDefaultColor = Color();
78 SvxRTFParser::~SvxRTFParser()
80 if( !aAttrStack.empty() )
81 ClearAttrStack();
84 void SvxRTFParser::SetInsPos( const EditPosition& rNew )
86 pInsPos = rNew.Clone();
89 SvParserState SvxRTFParser::CallParser()
91 DBG_ASSERT( pInsPos, "no insertion position");
93 if( !pInsPos )
94 return SvParserState::Error;
96 if( !maColorTable.empty() )
97 ClearColorTbl();
98 m_FontTable.clear();
99 m_StyleTable.clear();
100 if( !aAttrStack.empty() )
101 ClearAttrStack();
103 bIsSetDfltTab = false;
104 bNewGroup = false;
105 nDfltFont = 0;
107 // generate the correct WhichId table from the set WhichIds.
108 BuildWhichTable();
110 return SvRTFParser::CallParser();
113 void SvxRTFParser::Continue( int nToken )
115 SvRTFParser::Continue( nToken );
117 SvParserState eStatus = GetStatus();
118 if (eStatus != SvParserState::Pending && eStatus != SvParserState::Error)
120 SetAllAttrOfStk();
121 //Regardless of what "color 0" is, word defaults to auto as the default colour.
122 //e.g. see #i7713#
127 // is called for each token that is recognized in CallParser
128 void SvxRTFParser::NextToken( int nToken )
130 sal_Unicode cCh;
131 switch( nToken )
133 case RTF_COLORTBL: ReadColorTable(); break;
134 case RTF_FONTTBL: ReadFontTable(); break;
135 case RTF_STYLESHEET: ReadStyleTable(); break;
137 case RTF_DEFF:
138 if( bNewDoc )
140 if (!m_FontTable.empty())
141 // Can immediately be set
142 SetDefault( nToken, nTokenValue );
143 else
144 // is set after reading the font table
145 nDfltFont = int(nTokenValue);
147 break;
149 case RTF_DEFTAB:
150 case RTF_DEFLANG:
151 if( bNewDoc )
152 SetDefault( nToken, nTokenValue );
153 break;
156 case RTF_PICT: ReadBitmapData(); break;
158 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
159 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
160 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
162 case RTF_EMDASH: cCh = 0x2014; goto INSINGLECHAR;
163 case RTF_ENDASH: cCh = 0x2013; goto INSINGLECHAR;
164 case RTF_BULLET: cCh = 0x2022; goto INSINGLECHAR;
165 case RTF_LQUOTE: cCh = 0x2018; goto INSINGLECHAR;
166 case RTF_RQUOTE: cCh = 0x2019; goto INSINGLECHAR;
167 case RTF_LDBLQUOTE: cCh = 0x201C; goto INSINGLECHAR;
168 case RTF_RDBLQUOTE: cCh = 0x201D; goto INSINGLECHAR;
169 INSINGLECHAR:
170 aToken = OUString(cCh);
171 [[fallthrough]]; // aToken is set as Text
172 case RTF_TEXTTOKEN:
174 InsertText();
175 // all collected Attributes are set
176 for (size_t n = m_AttrSetList.size(); n; )
178 auto const& pStkSet = m_AttrSetList[--n];
179 SetAttrSet( *pStkSet );
180 m_AttrSetList.pop_back();
183 break;
186 case RTF_PAR:
187 InsertPara();
188 break;
189 case '{':
190 if (bNewGroup) // Nesting!
191 GetAttrSet_();
192 bNewGroup = true;
193 break;
194 case '}':
195 if( !bNewGroup ) // Empty Group ??
196 AttrGroupEnd();
197 bNewGroup = false;
198 break;
199 case RTF_INFO:
200 SkipGroup();
201 break;
203 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
204 // First overwrite all (all have to be in one group!!)
205 // Could also appear in the RTF-file without the IGNORE-Flag; all Groups
206 // with the IGNORE-Flag are overwritten in the default branch.
208 case RTF_SWG_PRTDATA:
209 case RTF_FIELD:
210 case RTF_ATNID:
211 case RTF_ANNOTATION:
213 case RTF_BKMKSTART:
214 case RTF_BKMKEND:
215 case RTF_BKMK_KEY:
216 case RTF_XE:
217 case RTF_TC:
218 case RTF_NEXTFILE:
219 case RTF_TEMPLATE:
220 // RTF_SHPRSLT disabled for #i19718#
221 SkipGroup();
222 break;
223 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
225 case RTF_PGDSCNO:
226 case RTF_PGBRK:
227 case RTF_SHADOW:
228 if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
229 break;
230 nToken = SkipToken();
231 if( '{' == GetStackPtr( -1 )->nTokenId )
232 nToken = SkipToken();
234 ReadAttr( nToken, &GetAttrSet() );
235 break;
237 default:
238 switch( nToken & ~(0xff | RTF_SWGDEFS) )
240 case RTF_PARFMT: // here are no SWGDEFS
241 ReadAttr( nToken, &GetAttrSet() );
242 break;
244 case RTF_CHRFMT:
245 case RTF_BRDRDEF:
246 case RTF_TABSTOPDEF:
248 if( RTF_SWGDEFS & nToken)
250 if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
251 break;
252 nToken = SkipToken();
253 if( '{' == GetStackPtr( -1 )->nTokenId )
255 nToken = SkipToken();
258 ReadAttr( nToken, &GetAttrSet() );
259 break;
260 default:
262 if( RTF_IGNOREFLAG == GetStackPtr( -1 )->nTokenId &&
263 '{' == GetStackPtr( -2 )->nTokenId )
264 SkipGroup();
266 break;
268 break;
272 void SvxRTFParser::ReadStyleTable()
274 int bSaveChkStyleAttr = bChkStyleAttr ? 1 : 0;
275 sal_uInt16 nStyleNo = 0;
276 bool bHasStyleNo = false;
277 int _nOpenBrakets = 1; // the first was already detected earlier!!
278 std::unique_ptr<SvxRTFStyleType> pStyle(
279 new SvxRTFStyleType( *pAttrPool, aWhichMap.data() ));
280 pStyle->aAttrSet.Put( GetRTFDefaults() );
282 bIsInReadStyleTab = true;
283 bChkStyleAttr = false; // Do not check Attribute against the Styles
285 while( _nOpenBrakets && IsParserWorking() )
287 int nToken = GetNextToken();
288 switch( nToken )
290 case '}': if( --_nOpenBrakets && IsParserWorking() )
291 // Style has been completely read,
292 // so this is still a stable status
293 SaveState( RTF_STYLESHEET );
294 break;
295 case '{':
297 if( RTF_IGNOREFLAG != GetNextToken() )
298 SkipToken();
299 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
300 RTF_PN != nToken )
301 SkipToken( -2 );
302 else
304 // filter out at once
305 ReadUnknownData();
306 nToken = GetNextToken();
307 if( '}' != nToken )
308 eState = SvParserState::Error;
309 break;
311 ++_nOpenBrakets;
313 break;
315 case RTF_SBASEDON: pStyle->nBasedOn = sal_uInt16(nTokenValue); break;
316 case RTF_SNEXT: break;
317 case RTF_OUTLINELEVEL:
318 case RTF_SOUTLVL: pStyle->nOutlineNo = sal_uInt8(nTokenValue); break;
319 case RTF_S: nStyleNo = static_cast<short>(nTokenValue);
320 bHasStyleNo = true;
321 break;
322 case RTF_CS: nStyleNo = static_cast<short>(nTokenValue);
323 bHasStyleNo = true;
324 break;
326 case RTF_TEXTTOKEN:
327 if (bHasStyleNo)
329 pStyle->sName = DelCharAtEnd( aToken, ';' );
331 if (!m_StyleTable.empty())
333 m_StyleTable.erase(nStyleNo);
335 // All data from the font is available, so off to the table
336 m_StyleTable.insert(std::make_pair(nStyleNo, std::move(pStyle)));
337 pStyle.reset(new SvxRTFStyleType( *pAttrPool, aWhichMap.data() ));
338 pStyle->aAttrSet.Put( GetRTFDefaults() );
339 nStyleNo = 0;
340 bHasStyleNo = false;
342 break;
343 default:
344 switch( nToken & ~(0xff | RTF_SWGDEFS) )
346 case RTF_PARFMT: // here are no SWGDEFS
347 ReadAttr( nToken, &pStyle->aAttrSet );
348 break;
350 case RTF_CHRFMT:
351 case RTF_BRDRDEF:
352 case RTF_TABSTOPDEF:
353 #ifndef NDEBUG
354 auto nEnteringToken = nToken;
355 #endif
356 auto nEnteringIndex = m_nTokenIndex;
357 int nSkippedTokens = 0;
358 if( RTF_SWGDEFS & nToken)
360 if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
361 break;
362 nToken = SkipToken();
363 ++nSkippedTokens;
364 if( '{' == GetStackPtr( -1 )->nTokenId )
366 nToken = SkipToken();
367 ++nSkippedTokens;
370 ReadAttr( nToken, &pStyle->aAttrSet );
371 if (nSkippedTokens && m_nTokenIndex == nEnteringIndex - nSkippedTokens)
373 // we called SkipToken to go back one or two, but ReadAttrs
374 // read nothing, so on next loop of the outer while we
375 // would end up in the same state again (assert that)
376 assert(nEnteringToken == GetNextToken());
377 // and loop endlessly, skip format a token
378 // instead to avoid that
379 SkipToken(nSkippedTokens);
381 break;
383 break;
386 pStyle.reset(); // Delete the Last Style
387 SkipToken(); // the closing brace is evaluated "above"
389 // Flag back to old state
390 bChkStyleAttr = bSaveChkStyleAttr;
391 bIsInReadStyleTab = false;
394 void SvxRTFParser::ReadColorTable()
396 int nToken;
397 sal_uInt8 nRed = 0xff, nGreen = 0xff, nBlue = 0xff;
399 for (;;)
401 nToken = GetNextToken();
402 if ( '}' == nToken || !IsParserWorking() )
403 break;
404 switch( nToken )
406 case RTF_RED: nRed = sal_uInt8(nTokenValue); break;
407 case RTF_GREEN: nGreen = sal_uInt8(nTokenValue); break;
408 case RTF_BLUE: nBlue = sal_uInt8(nTokenValue); break;
410 case RTF_TEXTTOKEN:
411 if( 1 == aToken.getLength()
412 ? aToken[ 0 ] != ';'
413 : -1 == aToken.indexOf( ";" ) )
414 break; // At least the ';' must be found
416 [[fallthrough]];
418 case ';':
419 if( IsParserWorking() )
421 // one color is finished, fill in the table
422 // try to map the values to SV internal names
423 Color aColor( nRed, nGreen, nBlue );
424 if( maColorTable.empty() &&
425 sal_uInt8(-1) == nRed && sal_uInt8(-1) == nGreen && sal_uInt8(-1) == nBlue )
426 aColor = COL_AUTO;
427 maColorTable.push_back( aColor );
428 nRed = 0;
429 nGreen = 0;
430 nBlue = 0;
432 // Color has been completely read,
433 // so this is still a stable status
434 SaveState( RTF_COLORTBL );
436 break;
439 SkipToken(); // the closing brace is evaluated "above"
442 void SvxRTFParser::ReadFontTable()
444 int _nOpenBrakets = 1; // the first was already detected earlier!!
445 std::unique_ptr<vcl::Font> pFont(new vcl::Font);
446 short nFontNo(0), nInsFontNo (0);
447 OUString sAltNm, sFntNm;
448 bool bIsAltFntNm = false;
450 rtl_TextEncoding nSystemChar = lcl_GetDefaultTextEncodingForRTF();
451 pFont->SetCharSet( nSystemChar );
452 SetEncoding( nSystemChar );
454 while( _nOpenBrakets && IsParserWorking() )
456 bool bCheckNewFont = false;
457 int nToken = GetNextToken();
458 switch( nToken )
460 case '}':
461 bIsAltFntNm = false;
462 // Style has been completely read,
463 // so this is still a stable status
464 if( --_nOpenBrakets <= 1 && IsParserWorking() )
465 SaveState( RTF_FONTTBL );
466 bCheckNewFont = true;
467 nInsFontNo = nFontNo;
468 break;
469 case '{':
470 if( RTF_IGNOREFLAG != GetNextToken() )
471 SkipToken();
472 // immediately skip unknown and all known but non-evaluated
473 // groups
474 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
475 RTF_PANOSE != nToken && RTF_FNAME != nToken &&
476 RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
477 SkipToken( -2 );
478 else
480 // filter out at once
481 ReadUnknownData();
482 nToken = GetNextToken();
483 if( '}' != nToken )
484 eState = SvParserState::Error;
485 break;
487 ++_nOpenBrakets;
488 break;
489 case RTF_FROMAN:
490 pFont->SetFamily( FAMILY_ROMAN );
491 break;
492 case RTF_FSWISS:
493 pFont->SetFamily( FAMILY_SWISS );
494 break;
495 case RTF_FMODERN:
496 pFont->SetFamily( FAMILY_MODERN );
497 break;
498 case RTF_FSCRIPT:
499 pFont->SetFamily( FAMILY_SCRIPT );
500 break;
501 case RTF_FDECOR:
502 pFont->SetFamily( FAMILY_DECORATIVE );
503 break;
504 // for technical/symbolic font of the rtl_TextEncoding is changed!
505 case RTF_FTECH:
506 pFont->SetCharSet( RTL_TEXTENCODING_SYMBOL );
507 [[fallthrough]];
508 case RTF_FNIL:
509 pFont->SetFamily( FAMILY_DONTKNOW );
510 break;
511 case RTF_FCHARSET:
512 if (-1 != nTokenValue)
514 rtl_TextEncoding nrtl_TextEncoding = rtl_getTextEncodingFromWindowsCharset(
515 static_cast<sal_uInt8>(nTokenValue));
516 pFont->SetCharSet(nrtl_TextEncoding);
517 //When we're in a font, the fontname is in the font
518 //charset, except for symbol fonts I believe
519 if (nrtl_TextEncoding == RTL_TEXTENCODING_SYMBOL)
520 nrtl_TextEncoding = RTL_TEXTENCODING_DONTKNOW;
521 SetEncoding(nrtl_TextEncoding);
523 break;
524 case RTF_FPRQ:
525 switch( nTokenValue )
527 case 1:
528 pFont->SetPitch( PITCH_FIXED );
529 break;
530 case 2:
531 pFont->SetPitch( PITCH_VARIABLE );
532 break;
534 break;
535 case RTF_F:
536 bCheckNewFont = true;
537 nInsFontNo = nFontNo;
538 nFontNo = static_cast<short>(nTokenValue);
539 break;
540 case RTF_FALT:
541 bIsAltFntNm = true;
542 break;
543 case RTF_TEXTTOKEN:
544 DelCharAtEnd( aToken, ';' );
545 if ( !aToken.isEmpty() )
547 if( bIsAltFntNm )
548 sAltNm = aToken;
549 else
550 sFntNm = aToken;
552 break;
555 if( bCheckNewFont && 1 >= _nOpenBrakets && !sFntNm.isEmpty() ) // one font is ready
557 // All data from the font is available, so off to the table
558 if (!sAltNm.isEmpty())
559 sFntNm += ";" + sAltNm;
561 pFont->SetFamilyName( sFntNm );
562 m_FontTable.insert(std::make_pair(nInsFontNo, std::move(pFont)));
563 pFont.reset(new vcl::Font);
564 pFont->SetCharSet( nSystemChar );
565 sAltNm.clear();
566 sFntNm.clear();
569 // the last one we have to delete manually
570 pFont.reset();
571 SkipToken(); // the closing brace is evaluated "above"
573 // set the default font in the Document
574 if( bNewDoc && IsParserWorking() )
575 SetDefault( RTF_DEFF, nDfltFont );
578 void SvxRTFParser::ClearColorTbl()
580 maColorTable.clear();
583 void SvxRTFParser::ClearAttrStack()
585 aAttrStack.clear();
588 OUString& SvxRTFParser::DelCharAtEnd( OUString& rStr, const sal_Unicode cDel )
590 if( !rStr.isEmpty() && ' ' == rStr[ 0 ])
591 rStr = comphelper::string::stripStart(rStr, ' ');
592 if( !rStr.isEmpty() && ' ' == rStr[ rStr.getLength()-1 ])
593 rStr = comphelper::string::stripEnd(rStr, ' ');
594 if( !rStr.isEmpty() && cDel == rStr[ rStr.getLength()-1 ])
595 rStr = rStr.copy( 0, rStr.getLength()-1 );
596 return rStr;
600 const vcl::Font& SvxRTFParser::GetFont( sal_uInt16 nId )
602 SvxRTFFontTbl::const_iterator it = m_FontTable.find( nId );
603 if (it != m_FontTable.end())
605 return *it->second;
607 const SvxFontItem& rDfltFont = static_cast<const SvxFontItem&>(
608 pAttrPool->GetDefaultItem( aPlainMap.nFont ));
609 pDfltFont->SetFamilyName( rDfltFont.GetStyleName() );
610 pDfltFont->SetFamily( rDfltFont.GetFamily() );
611 return *pDfltFont;
614 SvxRTFItemStackType* SvxRTFParser::GetAttrSet_()
616 SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
617 std::unique_ptr<SvxRTFItemStackType> pNew;
618 if( pCurrent )
619 pNew.reset(new SvxRTFItemStackType( *pCurrent, *pInsPos, false/*bCopyAttr*/ ));
620 else
621 pNew.reset(new SvxRTFItemStackType( *pAttrPool, aWhichMap.data(),
622 *pInsPos ));
623 pNew->SetRTFDefaults( GetRTFDefaults() );
625 aAttrStack.push_back( std::move(pNew) );
626 bNewGroup = false;
627 return aAttrStack.back().get();
631 void SvxRTFParser::ClearStyleAttr_( SvxRTFItemStackType& rStkType )
633 // check attributes to the attributes of the stylesheet or to
634 // the default attrs of the document
635 SfxItemSet &rSet = rStkType.GetAttrSet();
636 const SfxItemPool& rPool = *rSet.GetPool();
637 const SfxPoolItem* pItem;
638 SfxWhichIter aIter( rSet );
640 if( !IsChkStyleAttr() ||
641 !rStkType.GetAttrSet().Count() ||
642 m_StyleTable.count( rStkType.nStyleNo ) == 0 )
644 for( sal_uInt16 nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() )
646 if (SfxItemPool::IsWhich(nWhich) &&
647 SfxItemState::SET == rSet.GetItemState( nWhich, false, &pItem ) &&
648 rPool.GetDefaultItem( nWhich ) == *pItem )
649 rSet.ClearItem( nWhich ); // delete
652 else
654 // Delete all Attributes, which are already defined in the Style,
655 // from the current AttrSet.
656 auto const& pStyle = m_StyleTable.find(rStkType.nStyleNo)->second;
657 SfxItemSet &rStyleSet = pStyle->aAttrSet;
658 const SfxPoolItem* pSItem;
659 for( sal_uInt16 nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() )
661 if( SfxItemState::SET == rStyleSet.GetItemState( nWhich, true, &pSItem ))
663 if( SfxItemState::SET == rSet.GetItemState( nWhich, false, &pItem )
664 && *pItem == *pSItem )
665 rSet.ClearItem( nWhich ); // delete
667 else if (SfxItemPool::IsWhich(nWhich) &&
668 SfxItemState::SET == rSet.GetItemState( nWhich, false, &pItem ) &&
669 rPool.GetDefaultItem( nWhich ) == *pItem )
670 rSet.ClearItem( nWhich ); // delete
675 void SvxRTFParser::AttrGroupEnd() // process the current, delete from Stack
677 if( aAttrStack.empty() )
678 return;
680 std::unique_ptr<SvxRTFItemStackType> pOld = std::move(aAttrStack.back());
681 aAttrStack.pop_back();
682 SvxRTFItemStackType *pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
684 do { // middle check loop
685 sal_Int32 nOldSttNdIdx = pOld->pSttNd->GetIdx();
686 if (!pOld->m_pChildList &&
687 ((!pOld->aAttrSet.Count() && !pOld->nStyleNo ) ||
688 (nOldSttNdIdx == pInsPos->GetNodeIdx() &&
689 pOld->nSttCnt == pInsPos->GetCntIdx() )))
690 break; // no attributes or Area
692 // set only the attributes that are different from the parent
693 if( pCurrent && pOld->aAttrSet.Count() )
695 SfxItemIter aIter( pOld->aAttrSet );
696 const SfxPoolItem* pItem = aIter.GetCurItem(), *pGet;
699 if( SfxItemState::SET == pCurrent->aAttrSet.GetItemState(
700 pItem->Which(), false, &pGet ) &&
701 *pItem == *pGet )
702 pOld->aAttrSet.ClearItem( pItem->Which() );
704 pItem = aIter.NextItem();
705 } while (pItem);
707 if (!pOld->aAttrSet.Count() && !pOld->m_pChildList &&
708 !pOld->nStyleNo )
709 break;
712 // Set all attributes which have been defined from start until here
713 bool bCrsrBack = !pInsPos->GetCntIdx();
714 if( bCrsrBack )
716 // at the beginning of a paragraph? Move back one position
717 sal_Int32 nNd = pInsPos->GetNodeIdx();
718 MovePos(false);
719 // if can not move backward then later don't move forward !
720 bCrsrBack = nNd != pInsPos->GetNodeIdx();
723 if( pOld->pSttNd->GetIdx() < pInsPos->GetNodeIdx() ||
724 ( pOld->pSttNd->GetIdx() == pInsPos->GetNodeIdx() &&
725 pOld->nSttCnt <= pInsPos->GetCntIdx() ) )
727 if( !bCrsrBack )
729 // all pard attributes are only valid until the previous
730 // paragraph !!
731 if( nOldSttNdIdx == pInsPos->GetNodeIdx() )
734 else
736 // Now it gets complicated:
737 // - all character attributes sre keep the area
738 // - all paragraph attributes to get the area
739 // up to the previous paragraph
740 std::unique_ptr<SvxRTFItemStackType> pNew(
741 new SvxRTFItemStackType(*pOld, *pInsPos, true));
742 pNew->aAttrSet.SetParent( pOld->aAttrSet.GetParent() );
744 // Delete all paragraph attributes from pNew
745 for( sal_uInt16 n = 0; n < (sizeof(aPardMap) / sizeof(sal_uInt16)) &&
746 pNew->aAttrSet.Count(); ++n )
747 if( reinterpret_cast<sal_uInt16*>(&aPardMap)[n] )
748 pNew->aAttrSet.ClearItem( reinterpret_cast<sal_uInt16*>(&aPardMap)[n] );
749 pNew->SetRTFDefaults( GetRTFDefaults() );
751 // Were there any?
752 if( pNew->aAttrSet.Count() == pOld->aAttrSet.Count() )
754 pNew.reset();
756 else
758 pNew->nStyleNo = 0;
760 // Now span the real area of pNew from old
761 SetEndPrevPara( pOld->pEndNd, pOld->nEndCnt );
762 pNew->nSttCnt = 0;
764 if( IsChkStyleAttr() )
766 ClearStyleAttr_( *pOld );
767 ClearStyleAttr_( *pNew ); //#i10381#, methinks.
770 if( pCurrent )
772 pCurrent->Add(std::move(pOld));
773 pCurrent->Add(std::move(pNew));
775 else
777 // Last off the stack, thus cache it until the next text was
778 // read. (Span no attributes!)
780 m_AttrSetList.push_back(std::move(pOld));
781 m_AttrSetList.push_back(std::move(pNew));
783 break;
788 pOld->pEndNd = pInsPos->MakeNodeIdx().release();
789 pOld->nEndCnt = pInsPos->GetCntIdx();
792 #i21422#
793 If the parent (pCurrent) sets something e.g. , and the child (pOld)
794 unsets it and the style both are based on has it unset then
795 clearing the pOld by looking at the style is clearly a disaster
796 as the text ends up with pCurrents bold and not pOlds no bold, this
797 should be rethought out. For the moment its safest to just do
798 the clean if we have no parent, all we suffer is too many
799 redundant properties.
801 if (IsChkStyleAttr() && !pCurrent)
802 ClearStyleAttr_( *pOld );
804 if( pCurrent )
806 pCurrent->Add(std::move(pOld));
807 // split up and create new entry, because it makes no sense
808 // to create a "so long" depend list. Bug 95010
809 if (bCrsrBack && 50 < pCurrent->m_pChildList->size())
811 // at the beginning of a paragraph? Move back one position
812 MovePos();
813 bCrsrBack = false;
815 // Open a new Group.
816 std::unique_ptr<SvxRTFItemStackType> pNew(new SvxRTFItemStackType(
817 *pCurrent, *pInsPos, true ));
818 pNew->SetRTFDefaults( GetRTFDefaults() );
820 // Set all until here valid Attributes
821 AttrGroupEnd();
822 pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get(); // can be changed after AttrGroupEnd!
823 pNew->aAttrSet.SetParent( pCurrent ? &pCurrent->aAttrSet : nullptr );
824 aAttrStack.push_back( std::move(pNew) );
827 else
828 // Last off the stack, thus cache it until the next text was
829 // read. (Span no attributes!)
830 m_AttrSetList.push_back(std::move(pOld));
833 if( bCrsrBack )
834 // at the beginning of a paragraph? Move back one position
835 MovePos();
837 } while( false );
839 bNewGroup = false;
842 void SvxRTFParser::SetAllAttrOfStk() // end all Attr. and set it into doc
844 // repeat until all attributes will be taken from stack
845 while( !aAttrStack.empty() )
846 AttrGroupEnd();
848 for (size_t n = m_AttrSetList.size(); n; )
850 auto const& pStkSet = m_AttrSetList[--n];
851 SetAttrSet( *pStkSet );
852 pStkSet->DropChildList();
853 m_AttrSetList.pop_back();
857 // sets all the attributes that are different from the current
858 void SvxRTFParser::SetAttrSet( SvxRTFItemStackType &rSet )
860 // Was DefTab never read? then set to default
861 if( !bIsSetDfltTab )
862 SetDefault( RTF_DEFTAB, 720 );
864 if (rSet.m_pChildList)
865 rSet.Compress( *this );
866 if( rSet.aAttrSet.Count() || rSet.nStyleNo )
867 SetAttrInDoc( rSet );
869 // then process all the children
870 if (rSet.m_pChildList)
871 for (size_t n = 0; n < rSet.m_pChildList->size(); ++n)
872 SetAttrSet( *(*rSet.m_pChildList)[ n ] );
875 // Has no text been inserted yet? (SttPos from the top Stack entry!)
876 bool SvxRTFParser::IsAttrSttPos()
878 SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
879 return !pCurrent || (pCurrent->pSttNd->GetIdx() == pInsPos->GetNodeIdx() &&
880 pCurrent->nSttCnt == pInsPos->GetCntIdx());
884 void SvxRTFParser::SetAttrInDoc( SvxRTFItemStackType & )
888 void SvxRTFParser::BuildWhichTable()
890 aWhichMap.clear();
891 aWhichMap.push_back( 0 );
893 // Building a Which-Map 'rWhichMap' from an array of
894 // 'pWhichIds' from Which-Ids. It has the long 'nWhichIds'.
895 // The Which-Map is not going to be deleted.
896 ::BuildWhichTable( aWhichMap, reinterpret_cast<sal_uInt16*>(&aPardMap), sizeof(aPardMap) / sizeof(sal_uInt16) );
897 ::BuildWhichTable( aWhichMap, reinterpret_cast<sal_uInt16*>(&aPlainMap), sizeof(aPlainMap) / sizeof(sal_uInt16) );
900 const SfxItemSet& SvxRTFParser::GetRTFDefaults()
902 if( !pRTFDefaults )
904 pRTFDefaults.reset( new SfxItemSet( *pAttrPool, aWhichMap.data() ) );
905 sal_uInt16 nId;
906 if( 0 != ( nId = aPardMap.nScriptSpace ))
908 SvxScriptSpaceItem aItem( false, nId );
909 if( bNewDoc )
910 pAttrPool->SetPoolDefaultItem( aItem );
911 else
912 pRTFDefaults->Put( aItem );
915 return *pRTFDefaults;
919 SvxRTFStyleType::SvxRTFStyleType( SfxItemPool& rPool, const sal_uInt16* pWhichRange )
920 : aAttrSet( rPool, pWhichRange )
922 nOutlineNo = sal_uInt8(-1); // not set
923 nBasedOn = 0;
927 SvxRTFItemStackType::SvxRTFItemStackType(
928 SfxItemPool& rPool, const sal_uInt16* pWhichRange,
929 const EditPosition& rPos )
930 : aAttrSet( rPool, pWhichRange )
931 , nStyleNo( 0 )
933 pSttNd = rPos.MakeNodeIdx();
934 nSttCnt = rPos.GetCntIdx();
935 pEndNd = pSttNd.get();
936 nEndCnt = nSttCnt;
939 SvxRTFItemStackType::SvxRTFItemStackType(
940 const SvxRTFItemStackType& rCpy,
941 const EditPosition& rPos,
942 bool const bCopyAttr )
943 : aAttrSet( *rCpy.aAttrSet.GetPool(), rCpy.aAttrSet.GetRanges() )
944 , nStyleNo( rCpy.nStyleNo )
946 pSttNd = rPos.MakeNodeIdx();
947 nSttCnt = rPos.GetCntIdx();
948 pEndNd = pSttNd.get();
949 nEndCnt = nSttCnt;
951 aAttrSet.SetParent( &rCpy.aAttrSet );
952 if( bCopyAttr )
953 aAttrSet.Put( rCpy.aAttrSet );
956 /* ofz#13491 SvxRTFItemStackType dtor recursively
957 calls the dtor of its m_pChildList. The recurse
958 depth can grow sufficiently to trigger asan.
960 So breadth-first iterate through the nodes
961 and make a flat vector of them which can
962 be iterated through in order of most
963 distant from root first and release
964 their children linearly
966 void SvxRTFItemStackType::DropChildList()
968 if (!m_pChildList || m_pChildList->empty())
969 return;
971 std::vector<SvxRTFItemStackType*> bfs;
972 std::queue<SvxRTFItemStackType*> aQueue;
973 aQueue.push(this);
975 while (!aQueue.empty())
977 auto* front = aQueue.front();
978 aQueue.pop();
979 if (front->m_pChildList)
981 for (const auto& a : *front->m_pChildList)
982 aQueue.push(a.get());
983 bfs.push_back(front);
987 for (auto it = bfs.rbegin(); it != bfs.rend(); ++it)
989 SvxRTFItemStackType* pNode = *it;
990 pNode->m_pChildList.reset();
994 SvxRTFItemStackType::~SvxRTFItemStackType()
996 if( pSttNd.get() != pEndNd )
997 delete pEndNd;
1000 void SvxRTFItemStackType::Add(std::unique_ptr<SvxRTFItemStackType> pIns)
1002 if (!m_pChildList)
1003 m_pChildList.reset( new SvxRTFItemStackList );
1004 m_pChildList->push_back(std::move(pIns));
1007 void SvxRTFItemStackType::SetStartPos( const EditPosition& rPos )
1009 if (pSttNd.get() != pEndNd)
1010 delete pEndNd;
1011 pSttNd = rPos.MakeNodeIdx();
1012 pEndNd = pSttNd.get();
1013 nSttCnt = rPos.GetCntIdx();
1016 void SvxRTFItemStackType::Compress( const SvxRTFParser& rParser )
1018 ENSURE_OR_RETURN_VOID(m_pChildList, "Compress: no ChildList" );
1019 ENSURE_OR_RETURN_VOID(!m_pChildList->empty(), "Compress: ChildList empty");
1021 SvxRTFItemStackType* pTmp = (*m_pChildList)[0].get();
1023 if( !pTmp->aAttrSet.Count() ||
1024 pSttNd->GetIdx() != pTmp->pSttNd->GetIdx() ||
1025 nSttCnt != pTmp->nSttCnt )
1026 return;
1028 EditNodeIdx* pLastNd = pTmp->pEndNd;
1029 sal_Int32 nLastCnt = pTmp->nEndCnt;
1031 SfxItemSet aMrgSet( pTmp->aAttrSet );
1032 for (size_t n = 1; n < m_pChildList->size(); ++n)
1034 pTmp = (*m_pChildList)[n].get();
1035 if (pTmp->m_pChildList)
1036 pTmp->Compress( rParser );
1038 if( !pTmp->nSttCnt
1039 ? (pLastNd->GetIdx()+1 != pTmp->pSttNd->GetIdx() ||
1040 !rParser.IsEndPara( pLastNd, nLastCnt ) )
1041 : ( pTmp->nSttCnt != nLastCnt ||
1042 pLastNd->GetIdx() != pTmp->pSttNd->GetIdx() ))
1044 while (++n < m_pChildList->size())
1046 pTmp = (*m_pChildList)[n].get();
1047 if (pTmp->m_pChildList)
1048 pTmp->Compress( rParser );
1050 return;
1053 if( n )
1055 // Search for all which are set over the whole area
1056 SfxItemIter aIter( aMrgSet );
1057 const SfxPoolItem* pItem;
1058 const SfxPoolItem* pIterItem = aIter.GetCurItem();
1059 do {
1060 sal_uInt16 nWhich = pIterItem->Which();
1061 if( SfxItemState::SET != pTmp->aAttrSet.GetItemState( nWhich,
1062 false, &pItem ) || *pItem != *pIterItem)
1063 aMrgSet.ClearItem( nWhich );
1065 pIterItem = aIter.NextItem();
1066 } while(pIterItem);
1068 if( !aMrgSet.Count() )
1069 return;
1072 pLastNd = pTmp->pEndNd;
1073 nLastCnt = pTmp->nEndCnt;
1076 if( pEndNd->GetIdx() != pLastNd->GetIdx() || nEndCnt != nLastCnt )
1077 return;
1079 // It can be merged
1080 aAttrSet.Put( aMrgSet );
1082 size_t n = 0, nChildLen = m_pChildList->size();
1083 while (n < nChildLen)
1085 pTmp = (*m_pChildList)[n].get();
1086 pTmp->aAttrSet.Differentiate( aMrgSet );
1088 if (!pTmp->m_pChildList && !pTmp->aAttrSet.Count() && !pTmp->nStyleNo)
1090 m_pChildList->erase( m_pChildList->begin() + n );
1091 --nChildLen;
1092 continue;
1094 ++n;
1096 if (m_pChildList->empty())
1098 m_pChildList.reset();
1101 void SvxRTFItemStackType::SetRTFDefaults( const SfxItemSet& rDefaults )
1103 if( rDefaults.Count() )
1105 SfxItemIter aIter( rDefaults );
1106 const SfxPoolItem* pItem = aIter.GetCurItem();
1107 do {
1108 sal_uInt16 nWhich = pItem->Which();
1109 if( SfxItemState::SET != aAttrSet.GetItemState( nWhich, false ))
1110 aAttrSet.Put(*pItem);
1112 pItem = aIter.NextItem();
1113 } while(pItem);
1118 RTFPlainAttrMapIds::RTFPlainAttrMapIds( const SfxItemPool& rPool )
1120 nCaseMap = rPool.GetTrueWhich( SID_ATTR_CHAR_CASEMAP, false );
1121 nBgColor = rPool.GetTrueWhich( SID_ATTR_BRUSH_CHAR, false );
1122 nColor = rPool.GetTrueWhich( SID_ATTR_CHAR_COLOR, false );
1123 nContour = rPool.GetTrueWhich( SID_ATTR_CHAR_CONTOUR, false );
1124 nCrossedOut = rPool.GetTrueWhich( SID_ATTR_CHAR_STRIKEOUT, false );
1125 nEscapement = rPool.GetTrueWhich( SID_ATTR_CHAR_ESCAPEMENT, false );
1126 nFont = rPool.GetTrueWhich( SID_ATTR_CHAR_FONT, false );
1127 nFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_FONTHEIGHT, false );
1128 nKering = rPool.GetTrueWhich( SID_ATTR_CHAR_KERNING, false );
1129 nLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_LANGUAGE, false );
1130 nPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_POSTURE, false );
1131 nShadowed = rPool.GetTrueWhich( SID_ATTR_CHAR_SHADOWED, false );
1132 nUnderline = rPool.GetTrueWhich( SID_ATTR_CHAR_UNDERLINE, false );
1133 nOverline = rPool.GetTrueWhich( SID_ATTR_CHAR_OVERLINE, false );
1134 nWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_WEIGHT, false );
1135 nWordlineMode = rPool.GetTrueWhich( SID_ATTR_CHAR_WORDLINEMODE, false );
1136 nAutoKerning = rPool.GetTrueWhich( SID_ATTR_CHAR_AUTOKERN, false );
1138 nCJKFont = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONT, false );
1139 nCJKFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT, false );
1140 nCJKLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_LANGUAGE, false );
1141 nCJKPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_POSTURE, false );
1142 nCJKWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_WEIGHT, false );
1143 nCTLFont = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONT, false );
1144 nCTLFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT, false );
1145 nCTLLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_LANGUAGE, false );
1146 nCTLPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_POSTURE, false );
1147 nCTLWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_WEIGHT, false );
1148 nEmphasis = rPool.GetTrueWhich( SID_ATTR_CHAR_EMPHASISMARK, false );
1149 nTwoLines = rPool.GetTrueWhich( SID_ATTR_CHAR_TWO_LINES, false );
1150 nCharScaleX = rPool.GetTrueWhich( SID_ATTR_CHAR_SCALEWIDTH, false );
1151 nHorzVert = rPool.GetTrueWhich( SID_ATTR_CHAR_ROTATED, false );
1152 nRelief = rPool.GetTrueWhich( SID_ATTR_CHAR_RELIEF, false );
1153 nHidden = rPool.GetTrueWhich( SID_ATTR_CHAR_HIDDEN, false );
1156 RTFPardAttrMapIds ::RTFPardAttrMapIds ( const SfxItemPool& rPool )
1158 nLinespacing = rPool.GetTrueWhich( SID_ATTR_PARA_LINESPACE, false );
1159 nAdjust = rPool.GetTrueWhich( SID_ATTR_PARA_ADJUST, false );
1160 nTabStop = rPool.GetTrueWhich( SID_ATTR_TABSTOP, false );
1161 nHyphenzone = rPool.GetTrueWhich( SID_ATTR_PARA_HYPHENZONE, false );
1162 nLRSpace = rPool.GetTrueWhich( SID_ATTR_LRSPACE, false );
1163 nULSpace = rPool.GetTrueWhich( SID_ATTR_ULSPACE, false );
1164 nBrush = rPool.GetTrueWhich( SID_ATTR_BRUSH, false );
1165 nBox = rPool.GetTrueWhich( SID_ATTR_BORDER_OUTER, false );
1166 nShadow = rPool.GetTrueWhich( SID_ATTR_BORDER_SHADOW, false );
1167 nOutlineLvl = rPool.GetTrueWhich( SID_ATTR_PARA_OUTLLEVEL, false );
1168 nSplit = rPool.GetTrueWhich( SID_ATTR_PARA_SPLIT, false );
1169 nKeep = rPool.GetTrueWhich( SID_ATTR_PARA_KEEP, false );
1170 nFontAlign = rPool.GetTrueWhich( SID_PARA_VERTALIGN, false );
1171 nScriptSpace = rPool.GetTrueWhich( SID_ATTR_PARA_SCRIPTSPACE, false );
1172 nHangPunct = rPool.GetTrueWhich( SID_ATTR_PARA_HANGPUNCTUATION, false );
1173 nForbRule = rPool.GetTrueWhich( SID_ATTR_PARA_FORBIDDEN_RULES, false );
1174 nDirection = rPool.GetTrueWhich( SID_ATTR_FRAMEDIRECTION, false );
1177 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */