bump product version to 6.4.0.3
[LibreOffice.git] / editeng / source / rtf / svxrtf.cxx
blob7f5fdd34ac6ad2f78f6d81ea6cc2076d2e793ccf
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 <com/sun/star/lang/Locale.hpp>
34 #include <editeng/scriptspaceitem.hxx>
35 #include <editeng/fontitem.hxx>
36 #include <editeng/colritem.hxx>
37 #include <editeng/svxrtf.hxx>
38 #include <editeng/editids.hrc>
39 #include <vcl/font.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/settings.hxx>
43 #include <com/sun/star/document/XDocumentProperties.hpp>
46 using namespace ::com::sun::star;
49 static rtl_TextEncoding lcl_GetDefaultTextEncodingForRTF()
52 OUString aLangString( Application::GetSettings().GetLanguageTag().getLanguage());
54 if ( aLangString == "ru" || aLangString == "uk" )
55 return RTL_TEXTENCODING_MS_1251;
56 if ( aLangString == "tr" )
57 return RTL_TEXTENCODING_MS_1254;
58 else
59 return RTL_TEXTENCODING_MS_1252;
62 // -------------- Methods --------------------
64 SvxRTFParser::SvxRTFParser( SfxItemPool& rPool, SvStream& rIn )
65 : SvRTFParser( rIn, 5 )
66 , aPlainMap(rPool)
67 , aPardMap(rPool)
68 , pAttrPool( &rPool )
69 , nDfltFont( 0)
70 , bNewDoc( true )
71 , bNewGroup( false)
72 , bIsSetDfltTab( false)
73 , bChkStyleAttr( false )
74 , bCalcValue( false )
75 , bIsLeftToRightDef( true)
76 , bIsInReadStyleTab( false)
78 pDfltFont.reset( new vcl::Font );
79 pDfltColor.reset( new Color );
82 SvxRTFParser::~SvxRTFParser()
84 if( !aColorTbl.empty() )
85 ClearColorTbl();
86 if( !aAttrStack.empty() )
87 ClearAttrStack();
90 void SvxRTFParser::SetInsPos( const EditPosition& rNew )
92 pInsPos = rNew.Clone();
95 SvParserState SvxRTFParser::CallParser()
97 DBG_ASSERT( pInsPos, "no insertion position");
99 if( !pInsPos )
100 return SvParserState::Error;
102 if( !aColorTbl.empty() )
103 ClearColorTbl();
104 m_FontTable.clear();
105 m_StyleTable.clear();
106 if( !aAttrStack.empty() )
107 ClearAttrStack();
109 bIsSetDfltTab = false;
110 bNewGroup = false;
111 nDfltFont = 0;
113 // generate the correct WhichId table from the set WhichIds.
114 BuildWhichTable();
116 return SvRTFParser::CallParser();
119 void SvxRTFParser::Continue( int nToken )
121 SvRTFParser::Continue( nToken );
123 SvParserState eStatus = GetStatus();
124 if (eStatus != SvParserState::Pending && eStatus != SvParserState::Error)
126 SetAllAttrOfStk();
127 //Regardless of what "color 0" is, word defaults to auto as the default colour.
128 //e.g. see #i7713#
133 // is called for each token that is recognized in CallParser
134 void SvxRTFParser::NextToken( int nToken )
136 sal_Unicode cCh;
137 switch( nToken )
139 case RTF_COLORTBL: ReadColorTable(); break;
140 case RTF_FONTTBL: ReadFontTable(); break;
141 case RTF_STYLESHEET: ReadStyleTable(); break;
143 case RTF_DEFF:
144 if( bNewDoc )
146 if (!m_FontTable.empty())
147 // Can immediately be set
148 SetDefault( nToken, nTokenValue );
149 else
150 // is set after reading the font table
151 nDfltFont = int(nTokenValue);
153 break;
155 case RTF_DEFTAB:
156 case RTF_DEFLANG:
157 if( bNewDoc )
158 SetDefault( nToken, nTokenValue );
159 break;
162 case RTF_PICT: ReadBitmapData(); break;
164 case RTF_LINE: cCh = '\n'; goto INSINGLECHAR;
165 case RTF_TAB: cCh = '\t'; goto INSINGLECHAR;
166 case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR;
168 case RTF_EMDASH: cCh = 0x2014; goto INSINGLECHAR;
169 case RTF_ENDASH: cCh = 0x2013; goto INSINGLECHAR;
170 case RTF_BULLET: cCh = 0x2022; goto INSINGLECHAR;
171 case RTF_LQUOTE: cCh = 0x2018; goto INSINGLECHAR;
172 case RTF_RQUOTE: cCh = 0x2019; goto INSINGLECHAR;
173 case RTF_LDBLQUOTE: cCh = 0x201C; goto INSINGLECHAR;
174 case RTF_RDBLQUOTE: cCh = 0x201D; goto INSINGLECHAR;
175 INSINGLECHAR:
176 aToken = OUString(cCh);
177 [[fallthrough]]; // aToken is set as Text
178 case RTF_TEXTTOKEN:
180 InsertText();
181 // all collected Attributes are set
182 for (size_t n = m_AttrSetList.size(); n; )
184 auto const& pStkSet = m_AttrSetList[--n];
185 SetAttrSet( *pStkSet );
186 m_AttrSetList.pop_back();
189 break;
192 case RTF_PAR:
193 InsertPara();
194 break;
195 case '{':
196 if (bNewGroup) // Nesting!
197 GetAttrSet_();
198 bNewGroup = true;
199 break;
200 case '}':
201 if( !bNewGroup ) // Empty Group ??
202 AttrGroupEnd();
203 bNewGroup = false;
204 break;
205 case RTF_INFO:
206 SkipGroup();
207 break;
209 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
210 // First overwrite all (all have to be in one group!!)
211 // Could also appear in the RTF-file without the IGNORE-Flag; all Groups
212 // with the IGNORE-Flag are overwritten in the default branch.
214 case RTF_SWG_PRTDATA:
215 case RTF_FIELD:
216 case RTF_ATNID:
217 case RTF_ANNOTATION:
219 case RTF_BKMKSTART:
220 case RTF_BKMKEND:
221 case RTF_BKMK_KEY:
222 case RTF_XE:
223 case RTF_TC:
224 case RTF_NEXTFILE:
225 case RTF_TEMPLATE:
226 // RTF_SHPRSLT disabled for #i19718#
227 SkipGroup();
228 break;
229 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
231 case RTF_PGDSCNO:
232 case RTF_PGBRK:
233 case RTF_SHADOW:
234 if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
235 break;
236 nToken = SkipToken();
237 if( '{' == GetStackPtr( -1 )->nTokenId )
238 nToken = SkipToken();
240 ReadAttr( nToken, &GetAttrSet() );
241 break;
243 default:
244 switch( nToken & ~(0xff | RTF_SWGDEFS) )
246 case RTF_PARFMT: // here are no SWGDEFS
247 ReadAttr( nToken, &GetAttrSet() );
248 break;
250 case RTF_CHRFMT:
251 case RTF_BRDRDEF:
252 case RTF_TABSTOPDEF:
254 if( RTF_SWGDEFS & nToken)
256 if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
257 break;
258 nToken = SkipToken();
259 if( '{' == GetStackPtr( -1 )->nTokenId )
261 nToken = SkipToken();
264 ReadAttr( nToken, &GetAttrSet() );
265 break;
266 default:
268 if( RTF_IGNOREFLAG == GetStackPtr( -1 )->nTokenId &&
269 '{' == GetStackPtr( -2 )->nTokenId )
270 SkipGroup();
272 break;
274 break;
278 void SvxRTFParser::ReadStyleTable()
280 int bSaveChkStyleAttr = bChkStyleAttr ? 1 : 0;
281 sal_uInt16 nStyleNo = 0;
282 bool bHasStyleNo = false;
283 int _nOpenBrakets = 1; // the first was already detected earlier!!
284 std::unique_ptr<SvxRTFStyleType> pStyle(
285 new SvxRTFStyleType( *pAttrPool, aWhichMap.data() ));
286 pStyle->aAttrSet.Put( GetRTFDefaults() );
288 bIsInReadStyleTab = true;
289 bChkStyleAttr = false; // Do not check Attribute against the Styles
291 while( _nOpenBrakets && IsParserWorking() )
293 int nToken = GetNextToken();
294 switch( nToken )
296 case '}': if( --_nOpenBrakets && IsParserWorking() )
297 // Style has been completely read,
298 // so this is still a stable status
299 SaveState( RTF_STYLESHEET );
300 break;
301 case '{':
303 if( RTF_IGNOREFLAG != GetNextToken() )
304 SkipToken();
305 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
306 RTF_PN != nToken )
307 SkipToken( -2 );
308 else
310 // filter out at once
311 ReadUnknownData();
312 nToken = GetNextToken();
313 if( '}' != nToken )
314 eState = SvParserState::Error;
315 break;
317 ++_nOpenBrakets;
319 break;
321 case RTF_SBASEDON: pStyle->nBasedOn = sal_uInt16(nTokenValue); break;
322 case RTF_SNEXT: break;
323 case RTF_OUTLINELEVEL:
324 case RTF_SOUTLVL: pStyle->nOutlineNo = sal_uInt8(nTokenValue); break;
325 case RTF_S: nStyleNo = static_cast<short>(nTokenValue);
326 bHasStyleNo = true;
327 break;
328 case RTF_CS: nStyleNo = static_cast<short>(nTokenValue);
329 bHasStyleNo = true;
330 break;
332 case RTF_TEXTTOKEN:
333 if (bHasStyleNo)
335 pStyle->sName = DelCharAtEnd( aToken, ';' );
337 if (!m_StyleTable.empty())
339 m_StyleTable.erase(nStyleNo);
341 // All data from the font is available, so off to the table
342 m_StyleTable.insert(std::make_pair(nStyleNo, std::move(pStyle)));
343 pStyle.reset(new SvxRTFStyleType( *pAttrPool, aWhichMap.data() ));
344 pStyle->aAttrSet.Put( GetRTFDefaults() );
345 nStyleNo = 0;
346 bHasStyleNo = false;
348 break;
349 default:
350 switch( nToken & ~(0xff | RTF_SWGDEFS) )
352 case RTF_PARFMT: // here are no SWGDEFS
353 ReadAttr( nToken, &pStyle->aAttrSet );
354 break;
356 case RTF_CHRFMT:
357 case RTF_BRDRDEF:
358 case RTF_TABSTOPDEF:
359 #ifndef NDEBUG
360 auto nEnteringToken = nToken;
361 #endif
362 auto nEnteringIndex = m_nTokenIndex;
363 int nSkippedTokens = 0;
364 if( RTF_SWGDEFS & nToken)
366 if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId )
367 break;
368 nToken = SkipToken();
369 ++nSkippedTokens;
370 if( '{' == GetStackPtr( -1 )->nTokenId )
372 nToken = SkipToken();
373 ++nSkippedTokens;
376 ReadAttr( nToken, &pStyle->aAttrSet );
377 if (nSkippedTokens && m_nTokenIndex == nEnteringIndex - nSkippedTokens)
379 // we called SkipToken to go back one or two, but ReadAttrs
380 // read nothing, so on next loop of the outer while we
381 // would end up in the same state again (assert that)
382 assert(nEnteringToken == GetNextToken());
383 // and loop endlessly, skip format a token
384 // instead to avoid that
385 SkipToken(nSkippedTokens);
387 break;
389 break;
392 pStyle.reset(); // Delete the Last Style
393 SkipToken(); // the closing brace is evaluated "above"
395 // Flag back to old state
396 bChkStyleAttr = bSaveChkStyleAttr;
397 bIsInReadStyleTab = false;
400 void SvxRTFParser::ReadColorTable()
402 int nToken;
403 sal_uInt8 nRed = 0xff, nGreen = 0xff, nBlue = 0xff;
405 while( '}' != ( nToken = GetNextToken() ) && IsParserWorking() )
407 switch( nToken )
409 case RTF_RED: nRed = sal_uInt8(nTokenValue); break;
410 case RTF_GREEN: nGreen = sal_uInt8(nTokenValue); break;
411 case RTF_BLUE: nBlue = sal_uInt8(nTokenValue); break;
413 case RTF_TEXTTOKEN:
414 if( 1 == aToken.getLength()
415 ? aToken[ 0 ] != ';'
416 : -1 == aToken.indexOf( ";" ) )
417 break; // At least the ';' must be found
419 [[fallthrough]];
421 case ';':
422 if( IsParserWorking() )
424 // one color is finished, fill in the table
425 // try to map the values to SV internal names
426 Color* pColor = new Color( nRed, nGreen, nBlue );
427 if( aColorTbl.empty() &&
428 sal_uInt8(-1) == nRed && sal_uInt8(-1) == nGreen && sal_uInt8(-1) == nBlue )
429 *pColor = COL_AUTO;
430 aColorTbl.push_back( pColor );
431 nRed = 0;
432 nGreen = 0;
433 nBlue = 0;
435 // Color has been completely read,
436 // so this is still a stable status
437 SaveState( RTF_COLORTBL );
439 break;
442 SkipToken(); // the closing brace is evaluated "above"
445 void SvxRTFParser::ReadFontTable()
447 int _nOpenBrakets = 1; // the first was already detected earlier!!
448 std::unique_ptr<vcl::Font> pFont(new vcl::Font);
449 short nFontNo(0), nInsFontNo (0);
450 OUString sAltNm, sFntNm;
451 bool bIsAltFntNm = false;
453 rtl_TextEncoding nSystemChar = lcl_GetDefaultTextEncodingForRTF();
454 pFont->SetCharSet( nSystemChar );
455 SetEncoding( nSystemChar );
457 while( _nOpenBrakets && IsParserWorking() )
459 bool bCheckNewFont = false;
460 int nToken = GetNextToken();
461 switch( nToken )
463 case '}':
464 bIsAltFntNm = false;
465 // Style has been completely read,
466 // so this is still a stable status
467 if( --_nOpenBrakets <= 1 && IsParserWorking() )
468 SaveState( RTF_FONTTBL );
469 bCheckNewFont = true;
470 nInsFontNo = nFontNo;
471 break;
472 case '{':
473 if( RTF_IGNOREFLAG != GetNextToken() )
474 SkipToken();
475 // immediately skip unknown and all known but non-evaluated
476 // groups
477 else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) &&
478 RTF_PANOSE != nToken && RTF_FNAME != nToken &&
479 RTF_FONTEMB != nToken && RTF_FONTFILE != nToken )
480 SkipToken( -2 );
481 else
483 // filter out at once
484 ReadUnknownData();
485 nToken = GetNextToken();
486 if( '}' != nToken )
487 eState = SvParserState::Error;
488 break;
490 ++_nOpenBrakets;
491 break;
492 case RTF_FROMAN:
493 pFont->SetFamily( FAMILY_ROMAN );
494 break;
495 case RTF_FSWISS:
496 pFont->SetFamily( FAMILY_SWISS );
497 break;
498 case RTF_FMODERN:
499 pFont->SetFamily( FAMILY_MODERN );
500 break;
501 case RTF_FSCRIPT:
502 pFont->SetFamily( FAMILY_SCRIPT );
503 break;
504 case RTF_FDECOR:
505 pFont->SetFamily( FAMILY_DECORATIVE );
506 break;
507 // for technical/symbolic font of the rtl_TextEncoding is changed!
508 case RTF_FTECH:
509 pFont->SetCharSet( RTL_TEXTENCODING_SYMBOL );
510 [[fallthrough]];
511 case RTF_FNIL:
512 pFont->SetFamily( FAMILY_DONTKNOW );
513 break;
514 case RTF_FCHARSET:
515 if (-1 != nTokenValue)
517 rtl_TextEncoding nrtl_TextEncoding = rtl_getTextEncodingFromWindowsCharset(
518 static_cast<sal_uInt8>(nTokenValue));
519 pFont->SetCharSet(nrtl_TextEncoding);
520 //When we're in a font, the fontname is in the font
521 //charset, except for symbol fonts I believe
522 if (nrtl_TextEncoding == RTL_TEXTENCODING_SYMBOL)
523 nrtl_TextEncoding = RTL_TEXTENCODING_DONTKNOW;
524 SetEncoding(nrtl_TextEncoding);
526 break;
527 case RTF_FPRQ:
528 switch( nTokenValue )
530 case 1:
531 pFont->SetPitch( PITCH_FIXED );
532 break;
533 case 2:
534 pFont->SetPitch( PITCH_VARIABLE );
535 break;
537 break;
538 case RTF_F:
539 bCheckNewFont = true;
540 nInsFontNo = nFontNo;
541 nFontNo = static_cast<short>(nTokenValue);
542 break;
543 case RTF_FALT:
544 bIsAltFntNm = true;
545 break;
546 case RTF_TEXTTOKEN:
547 DelCharAtEnd( aToken, ';' );
548 if ( !aToken.isEmpty() )
550 if( bIsAltFntNm )
551 sAltNm = aToken;
552 else
553 sFntNm = aToken;
555 break;
558 if( bCheckNewFont && 1 >= _nOpenBrakets && !sFntNm.isEmpty() ) // one font is ready
560 // All data from the font is available, so off to the table
561 if (!sAltNm.isEmpty())
562 sFntNm += ";" + sAltNm;
564 pFont->SetFamilyName( sFntNm );
565 m_FontTable.insert(std::make_pair(nInsFontNo, std::move(pFont)));
566 pFont.reset(new vcl::Font);
567 pFont->SetCharSet( nSystemChar );
568 sAltNm.clear();
569 sFntNm.clear();
572 // the last one we have to delete manually
573 pFont.reset();
574 SkipToken(); // the closing brace is evaluated "above"
576 // set the default font in the Document
577 if( bNewDoc && IsParserWorking() )
578 SetDefault( RTF_DEFF, nDfltFont );
581 void SvxRTFParser::ClearColorTbl()
583 while ( !aColorTbl.empty() )
585 delete aColorTbl.back();
586 aColorTbl.pop_back();
590 void SvxRTFParser::ClearAttrStack()
592 aAttrStack.clear();
595 OUString& SvxRTFParser::DelCharAtEnd( OUString& rStr, const sal_Unicode cDel )
597 if( !rStr.isEmpty() && ' ' == rStr[ 0 ])
598 rStr = comphelper::string::stripStart(rStr, ' ');
599 if( !rStr.isEmpty() && ' ' == rStr[ rStr.getLength()-1 ])
600 rStr = comphelper::string::stripEnd(rStr, ' ');
601 if( !rStr.isEmpty() && cDel == rStr[ rStr.getLength()-1 ])
602 rStr = rStr.copy( 0, rStr.getLength()-1 );
603 return rStr;
607 const vcl::Font& SvxRTFParser::GetFont( sal_uInt16 nId )
609 SvxRTFFontTbl::const_iterator it = m_FontTable.find( nId );
610 if (it != m_FontTable.end())
612 return *it->second;
614 const SvxFontItem& rDfltFont = static_cast<const SvxFontItem&>(
615 pAttrPool->GetDefaultItem( aPlainMap.nFont ));
616 pDfltFont->SetFamilyName( rDfltFont.GetStyleName() );
617 pDfltFont->SetFamily( rDfltFont.GetFamily() );
618 return *pDfltFont;
621 SvxRTFItemStackType* SvxRTFParser::GetAttrSet_()
623 SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
624 std::unique_ptr<SvxRTFItemStackType> pNew;
625 if( pCurrent )
626 pNew.reset(new SvxRTFItemStackType( *pCurrent, *pInsPos, false/*bCopyAttr*/ ));
627 else
628 pNew.reset(new SvxRTFItemStackType( *pAttrPool, aWhichMap.data(),
629 *pInsPos ));
630 pNew->SetRTFDefaults( GetRTFDefaults() );
632 aAttrStack.push_back( std::move(pNew) );
633 bNewGroup = false;
634 return aAttrStack.back().get();
638 void SvxRTFParser::ClearStyleAttr_( SvxRTFItemStackType& rStkType )
640 // check attributes to the attributes of the stylesheet or to
641 // the default attrs of the document
642 SfxItemSet &rSet = rStkType.GetAttrSet();
643 const SfxItemPool& rPool = *rSet.GetPool();
644 const SfxPoolItem* pItem;
645 SfxWhichIter aIter( rSet );
647 if( !IsChkStyleAttr() ||
648 !rStkType.GetAttrSet().Count() ||
649 m_StyleTable.count( rStkType.nStyleNo ) == 0 )
651 for( sal_uInt16 nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() )
653 if (SfxItemPool::IsWhich(nWhich) &&
654 SfxItemState::SET == rSet.GetItemState( nWhich, false, &pItem ) &&
655 rPool.GetDefaultItem( nWhich ) == *pItem )
656 rSet.ClearItem( nWhich ); // delete
659 else
661 // Delete all Attributes, which are already defined in the Style,
662 // from the current AttrSet.
663 auto const& pStyle = m_StyleTable.find(rStkType.nStyleNo)->second;
664 SfxItemSet &rStyleSet = pStyle->aAttrSet;
665 const SfxPoolItem* pSItem;
666 for( sal_uInt16 nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() )
668 if( SfxItemState::SET == rStyleSet.GetItemState( nWhich, true, &pSItem ))
670 if( SfxItemState::SET == rSet.GetItemState( nWhich, false, &pItem )
671 && *pItem == *pSItem )
672 rSet.ClearItem( nWhich ); // delete
674 else if (SfxItemPool::IsWhich(nWhich) &&
675 SfxItemState::SET == rSet.GetItemState( nWhich, false, &pItem ) &&
676 rPool.GetDefaultItem( nWhich ) == *pItem )
677 rSet.ClearItem( nWhich ); // delete
682 void SvxRTFParser::AttrGroupEnd() // process the current, delete from Stack
684 if( !aAttrStack.empty() )
686 std::unique_ptr<SvxRTFItemStackType> pOld = std::move(aAttrStack.back());
687 aAttrStack.pop_back();
688 SvxRTFItemStackType *pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
690 do { // middle check loop
691 sal_Int32 nOldSttNdIdx = pOld->pSttNd->GetIdx();
692 if (!pOld->m_pChildList &&
693 ((!pOld->aAttrSet.Count() && !pOld->nStyleNo ) ||
694 (nOldSttNdIdx == pInsPos->GetNodeIdx() &&
695 pOld->nSttCnt == pInsPos->GetCntIdx() )))
696 break; // no attributes or Area
698 // set only the attributes that are different from the parent
699 if( pCurrent && pOld->aAttrSet.Count() )
701 SfxItemIter aIter( pOld->aAttrSet );
702 const SfxPoolItem* pItem = aIter.GetCurItem(), *pGet;
705 if( SfxItemState::SET == pCurrent->aAttrSet.GetItemState(
706 pItem->Which(), false, &pGet ) &&
707 *pItem == *pGet )
708 pOld->aAttrSet.ClearItem( pItem->Which() );
710 pItem = aIter.NextItem();
711 } while (pItem);
713 if (!pOld->aAttrSet.Count() && !pOld->m_pChildList &&
714 !pOld->nStyleNo )
715 break;
718 // Set all attributes which have been defined from start until here
719 bool bCrsrBack = !pInsPos->GetCntIdx();
720 if( bCrsrBack )
722 // at the beginning of a paragraph? Move back one position
723 sal_Int32 nNd = pInsPos->GetNodeIdx();
724 MovePos(false);
725 // if can not move backward then later don't move forward !
726 bCrsrBack = nNd != pInsPos->GetNodeIdx();
729 if( pOld->pSttNd->GetIdx() < pInsPos->GetNodeIdx() ||
730 ( pOld->pSttNd->GetIdx() == pInsPos->GetNodeIdx() &&
731 pOld->nSttCnt <= pInsPos->GetCntIdx() ) )
733 if( !bCrsrBack )
735 // all pard attributes are only valid until the previous
736 // paragraph !!
737 if( nOldSttNdIdx == pInsPos->GetNodeIdx() )
740 else
742 // Now it gets complicated:
743 // - all character attributes sre keep the area
744 // - all paragraph attributes to get the area
745 // up to the previous paragraph
746 std::unique_ptr<SvxRTFItemStackType> pNew(
747 new SvxRTFItemStackType(*pOld, *pInsPos, true));
748 pNew->aAttrSet.SetParent( pOld->aAttrSet.GetParent() );
750 // Delete all paragraph attributes from pNew
751 for( sal_uInt16 n = 0; n < (sizeof(aPardMap) / sizeof(sal_uInt16)) &&
752 pNew->aAttrSet.Count(); ++n )
753 if( reinterpret_cast<sal_uInt16*>(&aPardMap)[n] )
754 pNew->aAttrSet.ClearItem( reinterpret_cast<sal_uInt16*>(&aPardMap)[n] );
755 pNew->SetRTFDefaults( GetRTFDefaults() );
757 // Were there any?
758 if( pNew->aAttrSet.Count() == pOld->aAttrSet.Count() )
760 pNew.reset();
762 else
764 pNew->nStyleNo = 0;
766 // Now span the real area of pNew from old
767 SetEndPrevPara( pOld->pEndNd, pOld->nEndCnt );
768 pNew->nSttCnt = 0;
770 if( IsChkStyleAttr() )
772 ClearStyleAttr_( *pOld );
773 ClearStyleAttr_( *pNew ); //#i10381#, methinks.
776 if( pCurrent )
778 pCurrent->Add(std::move(pOld));
779 pCurrent->Add(std::move(pNew));
781 else
783 // Last off the stack, thus cache it until the next text was
784 // read. (Span no attributes!)
786 m_AttrSetList.push_back(std::move(pOld));
787 m_AttrSetList.push_back(std::move(pNew));
789 break;
794 pOld->pEndNd = pInsPos->MakeNodeIdx().release();
795 pOld->nEndCnt = pInsPos->GetCntIdx();
798 #i21422#
799 If the parent (pCurrent) sets something e.g. , and the child (pOld)
800 unsets it and the style both are based on has it unset then
801 clearing the pOld by looking at the style is clearly a disaster
802 as the text ends up with pCurrents bold and not pOlds no bold, this
803 should be rethought out. For the moment its safest to just do
804 the clean if we have no parent, all we suffer is too many
805 redundant properties.
807 if (IsChkStyleAttr() && !pCurrent)
808 ClearStyleAttr_( *pOld );
810 if( pCurrent )
812 pCurrent->Add(std::move(pOld));
813 // split up and create new entry, because it makes no sense
814 // to create a "so long" depend list. Bug 95010
815 if (bCrsrBack && 50 < pCurrent->m_pChildList->size())
817 // at the beginning of a paragraph? Move back one position
818 MovePos();
819 bCrsrBack = false;
821 // Open a new Group.
822 std::unique_ptr<SvxRTFItemStackType> pNew(new SvxRTFItemStackType(
823 *pCurrent, *pInsPos, true ));
824 pNew->SetRTFDefaults( GetRTFDefaults() );
826 // Set all until here valid Attributes
827 AttrGroupEnd();
828 pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get(); // can be changed after AttrGroupEnd!
829 pNew->aAttrSet.SetParent( pCurrent ? &pCurrent->aAttrSet : nullptr );
830 aAttrStack.push_back( std::move(pNew) );
833 else
834 // Last off the stack, thus cache it until the next text was
835 // read. (Span no attributes!)
836 m_AttrSetList.push_back(std::move(pOld));
839 if( bCrsrBack )
840 // at the beginning of a paragraph? Move back one position
841 MovePos();
843 } while( false );
845 bNewGroup = false;
849 void SvxRTFParser::SetAllAttrOfStk() // end all Attr. and set it into doc
851 // repeat until all attributes will be taken from stack
852 while( !aAttrStack.empty() )
853 AttrGroupEnd();
855 for (size_t n = m_AttrSetList.size(); n; )
857 auto const& pStkSet = m_AttrSetList[--n];
858 SetAttrSet( *pStkSet );
859 pStkSet->DropChildList();
860 m_AttrSetList.pop_back();
864 // sets all the attributes that are different from the current
865 void SvxRTFParser::SetAttrSet( SvxRTFItemStackType &rSet )
867 // Was DefTab never read? then set to default
868 if( !bIsSetDfltTab )
869 SetDefault( RTF_DEFTAB, 720 );
871 if (rSet.m_pChildList)
872 rSet.Compress( *this );
873 if( rSet.aAttrSet.Count() || rSet.nStyleNo )
874 SetAttrInDoc( rSet );
876 // then process all the children
877 if (rSet.m_pChildList)
878 for (size_t n = 0; n < rSet.m_pChildList->size(); ++n)
879 SetAttrSet( *(*rSet.m_pChildList)[ n ] );
882 // Has no text been inserted yet? (SttPos from the top Stack entry!)
883 bool SvxRTFParser::IsAttrSttPos()
885 SvxRTFItemStackType* pCurrent = aAttrStack.empty() ? nullptr : aAttrStack.back().get();
886 return !pCurrent || (pCurrent->pSttNd->GetIdx() == pInsPos->GetNodeIdx() &&
887 pCurrent->nSttCnt == pInsPos->GetCntIdx());
891 void SvxRTFParser::SetAttrInDoc( SvxRTFItemStackType & )
895 void SvxRTFParser::BuildWhichTable()
897 aWhichMap.clear();
898 aWhichMap.push_back( 0 );
900 // Building a Which-Map 'rWhichMap' from an array of
901 // 'pWhichIds' from Which-Ids. It has the long 'nWhichIds'.
902 // The Which-Map is not going to be deleted.
903 ::BuildWhichTable( aWhichMap, reinterpret_cast<sal_uInt16*>(&aPardMap), sizeof(aPardMap) / sizeof(sal_uInt16) );
904 ::BuildWhichTable( aWhichMap, reinterpret_cast<sal_uInt16*>(&aPlainMap), sizeof(aPlainMap) / sizeof(sal_uInt16) );
907 const SfxItemSet& SvxRTFParser::GetRTFDefaults()
909 if( !pRTFDefaults )
911 pRTFDefaults.reset( new SfxItemSet( *pAttrPool, aWhichMap.data() ) );
912 sal_uInt16 nId;
913 if( 0 != ( nId = aPardMap.nScriptSpace ))
915 SvxScriptSpaceItem aItem( false, nId );
916 if( bNewDoc )
917 pAttrPool->SetPoolDefaultItem( aItem );
918 else
919 pRTFDefaults->Put( aItem );
922 return *pRTFDefaults;
926 SvxRTFStyleType::SvxRTFStyleType( SfxItemPool& rPool, const sal_uInt16* pWhichRange )
927 : aAttrSet( rPool, pWhichRange )
929 nOutlineNo = sal_uInt8(-1); // not set
930 nBasedOn = 0;
934 SvxRTFItemStackType::SvxRTFItemStackType(
935 SfxItemPool& rPool, const sal_uInt16* pWhichRange,
936 const EditPosition& rPos )
937 : aAttrSet( rPool, pWhichRange )
938 , nStyleNo( 0 )
940 pSttNd = rPos.MakeNodeIdx();
941 nSttCnt = rPos.GetCntIdx();
942 pEndNd = pSttNd.get();
943 nEndCnt = nSttCnt;
946 SvxRTFItemStackType::SvxRTFItemStackType(
947 const SvxRTFItemStackType& rCpy,
948 const EditPosition& rPos,
949 bool const bCopyAttr )
950 : aAttrSet( *rCpy.aAttrSet.GetPool(), rCpy.aAttrSet.GetRanges() )
951 , nStyleNo( rCpy.nStyleNo )
953 pSttNd = rPos.MakeNodeIdx();
954 nSttCnt = rPos.GetCntIdx();
955 pEndNd = pSttNd.get();
956 nEndCnt = nSttCnt;
958 aAttrSet.SetParent( &rCpy.aAttrSet );
959 if( bCopyAttr )
960 aAttrSet.Put( rCpy.aAttrSet );
963 /* ofz#13491 SvxRTFItemStackType dtor recursively
964 calls the dtor of its m_pChildList. The recurse
965 depth can grow sufficiently to trigger asan.
967 So breadth-first iterate through the nodes
968 and make a flat vector of them which can
969 be iterated through in order of most
970 distant from root first and release
971 their children linearly
973 void SvxRTFItemStackType::DropChildList()
975 if (!m_pChildList || m_pChildList->empty())
976 return;
978 std::vector<SvxRTFItemStackType*> bfs;
979 std::queue<SvxRTFItemStackType*> aQueue;
980 aQueue.push(this);
982 while (!aQueue.empty())
984 auto* front = aQueue.front();
985 aQueue.pop();
986 if (front->m_pChildList)
988 for (const auto& a : *front->m_pChildList)
989 aQueue.push(a.get());
990 bfs.push_back(front);
994 for (auto it = bfs.rbegin(); it != bfs.rend(); ++it)
996 SvxRTFItemStackType* pNode = *it;
997 pNode->m_pChildList.reset();
1001 SvxRTFItemStackType::~SvxRTFItemStackType()
1003 if( pSttNd.get() != pEndNd )
1004 delete pEndNd;
1007 void SvxRTFItemStackType::Add(std::unique_ptr<SvxRTFItemStackType> pIns)
1009 if (!m_pChildList)
1010 m_pChildList.reset( new SvxRTFItemStackList );
1011 m_pChildList->push_back(std::move(pIns));
1014 void SvxRTFItemStackType::SetStartPos( const EditPosition& rPos )
1016 if (pSttNd.get() != pEndNd)
1017 delete pEndNd;
1018 pSttNd = rPos.MakeNodeIdx();
1019 pEndNd = pSttNd.get();
1020 nSttCnt = rPos.GetCntIdx();
1023 void SvxRTFItemStackType::Compress( const SvxRTFParser& rParser )
1025 ENSURE_OR_RETURN_VOID(m_pChildList, "Compress: no ChildList" );
1026 ENSURE_OR_RETURN_VOID(!m_pChildList->empty(), "Compress: ChildList empty");
1028 SvxRTFItemStackType* pTmp = (*m_pChildList)[0].get();
1030 if( !pTmp->aAttrSet.Count() ||
1031 pSttNd->GetIdx() != pTmp->pSttNd->GetIdx() ||
1032 nSttCnt != pTmp->nSttCnt )
1033 return;
1035 EditNodeIdx* pLastNd = pTmp->pEndNd;
1036 sal_Int32 nLastCnt = pTmp->nEndCnt;
1038 SfxItemSet aMrgSet( pTmp->aAttrSet );
1039 for (size_t n = 1; n < m_pChildList->size(); ++n)
1041 pTmp = (*m_pChildList)[n].get();
1042 if (pTmp->m_pChildList)
1043 pTmp->Compress( rParser );
1045 if( !pTmp->nSttCnt
1046 ? (pLastNd->GetIdx()+1 != pTmp->pSttNd->GetIdx() ||
1047 !rParser.IsEndPara( pLastNd, nLastCnt ) )
1048 : ( pTmp->nSttCnt != nLastCnt ||
1049 pLastNd->GetIdx() != pTmp->pSttNd->GetIdx() ))
1051 while (++n < m_pChildList->size())
1053 pTmp = (*m_pChildList)[n].get();
1054 if (pTmp->m_pChildList)
1055 pTmp->Compress( rParser );
1057 return;
1060 if( n )
1062 // Search for all which are set over the whole area
1063 SfxItemIter aIter( aMrgSet );
1064 const SfxPoolItem* pItem;
1065 const SfxPoolItem* pIterItem = aIter.GetCurItem();
1066 do {
1067 sal_uInt16 nWhich = pIterItem->Which();
1068 if( SfxItemState::SET != pTmp->aAttrSet.GetItemState( nWhich,
1069 false, &pItem ) || *pItem != *pIterItem)
1070 aMrgSet.ClearItem( nWhich );
1072 pIterItem = aIter.NextItem();
1073 } while(pIterItem);
1075 if( !aMrgSet.Count() )
1076 return;
1079 pLastNd = pTmp->pEndNd;
1080 nLastCnt = pTmp->nEndCnt;
1083 if( pEndNd->GetIdx() != pLastNd->GetIdx() || nEndCnt != nLastCnt )
1084 return;
1086 // It can be merged
1087 aAttrSet.Put( aMrgSet );
1089 for (size_t n = 0; n < m_pChildList->size(); ++n)
1091 pTmp = (*m_pChildList)[n].get();
1092 pTmp->aAttrSet.Differentiate( aMrgSet );
1094 if (!pTmp->m_pChildList && !pTmp->aAttrSet.Count() && !pTmp->nStyleNo)
1096 m_pChildList->erase( m_pChildList->begin() + n );
1097 --n;
1100 if (m_pChildList->empty())
1102 m_pChildList.reset();
1105 void SvxRTFItemStackType::SetRTFDefaults( const SfxItemSet& rDefaults )
1107 if( rDefaults.Count() )
1109 SfxItemIter aIter( rDefaults );
1110 const SfxPoolItem* pItem = aIter.GetCurItem();
1111 do {
1112 sal_uInt16 nWhich = pItem->Which();
1113 if( SfxItemState::SET != aAttrSet.GetItemState( nWhich, false ))
1114 aAttrSet.Put(*pItem);
1116 pItem = aIter.NextItem();
1117 } while(pItem);
1122 RTFPlainAttrMapIds::RTFPlainAttrMapIds( const SfxItemPool& rPool )
1124 nCaseMap = rPool.GetTrueWhich( SID_ATTR_CHAR_CASEMAP, false );
1125 nBgColor = rPool.GetTrueWhich( SID_ATTR_BRUSH_CHAR, false );
1126 nColor = rPool.GetTrueWhich( SID_ATTR_CHAR_COLOR, false );
1127 nContour = rPool.GetTrueWhich( SID_ATTR_CHAR_CONTOUR, false );
1128 nCrossedOut = rPool.GetTrueWhich( SID_ATTR_CHAR_STRIKEOUT, false );
1129 nEscapement = rPool.GetTrueWhich( SID_ATTR_CHAR_ESCAPEMENT, false );
1130 nFont = rPool.GetTrueWhich( SID_ATTR_CHAR_FONT, false );
1131 nFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_FONTHEIGHT, false );
1132 nKering = rPool.GetTrueWhich( SID_ATTR_CHAR_KERNING, false );
1133 nLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_LANGUAGE, false );
1134 nPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_POSTURE, false );
1135 nShadowed = rPool.GetTrueWhich( SID_ATTR_CHAR_SHADOWED, false );
1136 nUnderline = rPool.GetTrueWhich( SID_ATTR_CHAR_UNDERLINE, false );
1137 nOverline = rPool.GetTrueWhich( SID_ATTR_CHAR_OVERLINE, false );
1138 nWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_WEIGHT, false );
1139 nWordlineMode = rPool.GetTrueWhich( SID_ATTR_CHAR_WORDLINEMODE, false );
1140 nAutoKerning = rPool.GetTrueWhich( SID_ATTR_CHAR_AUTOKERN, false );
1142 nCJKFont = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONT, false );
1143 nCJKFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT, false );
1144 nCJKLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_LANGUAGE, false );
1145 nCJKPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_POSTURE, false );
1146 nCJKWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_WEIGHT, false );
1147 nCTLFont = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONT, false );
1148 nCTLFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT, false );
1149 nCTLLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_LANGUAGE, false );
1150 nCTLPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_POSTURE, false );
1151 nCTLWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_WEIGHT, false );
1152 nEmphasis = rPool.GetTrueWhich( SID_ATTR_CHAR_EMPHASISMARK, false );
1153 nTwoLines = rPool.GetTrueWhich( SID_ATTR_CHAR_TWO_LINES, false );
1154 nCharScaleX = rPool.GetTrueWhich( SID_ATTR_CHAR_SCALEWIDTH, false );
1155 nHorzVert = rPool.GetTrueWhich( SID_ATTR_CHAR_ROTATED, false );
1156 nRelief = rPool.GetTrueWhich( SID_ATTR_CHAR_RELIEF, false );
1157 nHidden = rPool.GetTrueWhich( SID_ATTR_CHAR_HIDDEN, false );
1160 RTFPardAttrMapIds ::RTFPardAttrMapIds ( const SfxItemPool& rPool )
1162 nLinespacing = rPool.GetTrueWhich( SID_ATTR_PARA_LINESPACE, false );
1163 nAdjust = rPool.GetTrueWhich( SID_ATTR_PARA_ADJUST, false );
1164 nTabStop = rPool.GetTrueWhich( SID_ATTR_TABSTOP, false );
1165 nHyphenzone = rPool.GetTrueWhich( SID_ATTR_PARA_HYPHENZONE, false );
1166 nLRSpace = rPool.GetTrueWhich( SID_ATTR_LRSPACE, false );
1167 nULSpace = rPool.GetTrueWhich( SID_ATTR_ULSPACE, false );
1168 nBrush = rPool.GetTrueWhich( SID_ATTR_BRUSH, false );
1169 nBox = rPool.GetTrueWhich( SID_ATTR_BORDER_OUTER, false );
1170 nShadow = rPool.GetTrueWhich( SID_ATTR_BORDER_SHADOW, false );
1171 nOutlineLvl = rPool.GetTrueWhich( SID_ATTR_PARA_OUTLLEVEL, false );
1172 nSplit = rPool.GetTrueWhich( SID_ATTR_PARA_SPLIT, false );
1173 nKeep = rPool.GetTrueWhich( SID_ATTR_PARA_KEEP, false );
1174 nFontAlign = rPool.GetTrueWhich( SID_PARA_VERTALIGN, false );
1175 nScriptSpace = rPool.GetTrueWhich( SID_ATTR_PARA_SCRIPTSPACE, false );
1176 nHangPunct = rPool.GetTrueWhich( SID_ATTR_PARA_HANGPUNCTUATION, false );
1177 nForbRule = rPool.GetTrueWhich( SID_ATTR_PARA_FORBIDDEN_RULES, false );
1178 nDirection = rPool.GetTrueWhich( SID_ATTR_FRAMEDIRECTION, false );
1181 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */