1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <com/sun/star/text/VertOrientation.hpp>
21 #include <com/sun/star/style/NumberingType.hpp>
22 #include <hintids.hxx>
23 #include <svtools/htmltokn.h>
24 #include <svtools/htmlkywd.hxx>
25 #include <svtools/htmlout.hxx>
26 #include <svl/urihelper.hxx>
27 #include <editeng/brushitem.hxx>
28 #include <editeng/lrspitem.hxx>
29 #include <vcl/svapp.hxx>
30 #include <sal/log.hxx>
31 #include <osl/diagnose.h>
32 #include <numrule.hxx>
33 #include <doc.hxx>
34 #include <docary.hxx>
35 #include <poolfmt.hxx>
36 #include <ndtxt.hxx>
37 #include <paratr.hxx>
38 
39 #include "htmlnum.hxx"
40 #include "swcss1.hxx"
41 #include "swhtml.hxx"
42 
43 #include <SwNodeNum.hxx>
44 
45 using namespace css;
46 
47 // <UL TYPE=...>
48 static HTMLOptionEnum<sal_Unicode> const aHTMLULTypeTable[] =
49 {
50     { OOO_STRING_SVTOOLS_HTML_ULTYPE_disc,    HTML_BULLETCHAR_DISC   },
51     { OOO_STRING_SVTOOLS_HTML_ULTYPE_circle,  HTML_BULLETCHAR_CIRCLE },
52     { OOO_STRING_SVTOOLS_HTML_ULTYPE_square,  HTML_BULLETCHAR_SQUARE },
53     { nullptr,                                0                      }
54 };
55 
56 
NewNumBulList(HtmlTokenId nToken)57 void SwHTMLParser::NewNumBulList( HtmlTokenId nToken )
58 {
59     SwHTMLNumRuleInfo& rInfo = GetNumInfo();
60 
61     // Create a new paragraph
62     bool bSpace = (rInfo.GetDepth() + m_nDefListDeep) == 0;
63     if( m_pPam->GetPoint()->nContent.GetIndex() )
64         AppendTextNode( bSpace ? AM_SPACE : AM_NOSPACE, false );
65     else if( bSpace )
66         AddParSpace();
67 
68     // Increment the numbering depth
69     rInfo.IncDepth();
70     sal_uInt8 nLevel = static_cast<sal_uInt8>( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth()
71                                                         : MAXLEVEL) - 1 );
72 
73     // Create rules if needed
74     if( !rInfo.GetNumRule() )
75     {
76         sal_uInt16 nPos = m_xDoc->MakeNumRule( m_xDoc->GetUniqueNumRuleName() );
77         rInfo.SetNumRule( m_xDoc->GetNumRuleTable()[nPos] );
78     }
79 
80     // Change the format for this level if that hasn't happened yet for this level
81     bool bNewNumFormat = rInfo.GetNumRule()->GetNumFormat( nLevel ) == nullptr;
82     bool bChangeNumFormat = false;
83 
84     // Create the default numbering format
85     SwNumFormat aNumFormat( rInfo.GetNumRule()->Get(nLevel) );
86     rInfo.SetNodeStartValue( nLevel );
87     if( bNewNumFormat )
88     {
89         sal_uInt16 nChrFormatPoolId = 0;
90         if( HtmlTokenId::ORDERLIST_ON == nToken )
91         {
92             aNumFormat.SetNumberingType(SVX_NUM_ARABIC);
93             nChrFormatPoolId = RES_POOLCHR_NUM_LEVEL;
94         }
95         else
96         {
97             // We'll set a default style because the UI does the same. This meant a 9pt font, which
98             // was not the case in Netscape. That didn't bother anyone so far
99             // #i63395# - Only apply user defined default bullet font
100             if ( numfunc::IsDefBulletFontUserDefined() )
101             {
102                 aNumFormat.SetBulletFont( &numfunc::GetDefBulletFont() );
103             }
104             aNumFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
105             aNumFormat.SetBulletChar( cBulletChar );
106             nChrFormatPoolId = RES_POOLCHR_BUL_LEVEL;
107         }
108 
109         sal_Int32 nAbsLSpace = HTML_NUMBUL_MARGINLEFT;
110 
111         sal_Int32 nFirstLineIndent  = HTML_NUMBUL_INDENT;
112         if( nLevel > 0 )
113         {
114             const SwNumFormat& rPrevNumFormat = rInfo.GetNumRule()->Get( nLevel-1 );
115             nAbsLSpace = nAbsLSpace + rPrevNumFormat.GetAbsLSpace();
116             nFirstLineIndent = rPrevNumFormat.GetFirstLineOffset();
117         }
118         aNumFormat.SetAbsLSpace( nAbsLSpace );
119         aNumFormat.SetFirstLineOffset( nFirstLineIndent );
120         aNumFormat.SetCharFormat( m_pCSS1Parser->GetCharFormatFromPool(nChrFormatPoolId) );
121 
122         bChangeNumFormat = true;
123     }
124     else if( 1 != aNumFormat.GetStart() )
125     {
126         // If the layer has already been used, the start value may need to be set hard to the paragraph.
127         rInfo.SetNodeStartValue( nLevel, 1 );
128     }
129 
130     // and set that in the options
131     OUString aId, aStyle, aClass, aLang, aDir;
132     OUString aBulletSrc;
133     sal_Int16 eVertOri = text::VertOrientation::NONE;
134     sal_uInt16 nWidth=USHRT_MAX, nHeight=USHRT_MAX;
135     const HTMLOptions& rHTMLOptions = GetOptions();
136     for (size_t i = rHTMLOptions.size(); i; )
137     {
138         const HTMLOption& rOption = rHTMLOptions[--i];
139         switch( rOption.GetToken() )
140         {
141         case HtmlOptionId::ID:
142             aId = rOption.GetString();
143             break;
144         case HtmlOptionId::TYPE:
145             if( bNewNumFormat && !rOption.GetString().isEmpty() )
146             {
147                 switch( nToken )
148                 {
149                 case HtmlTokenId::ORDERLIST_ON:
150                     bChangeNumFormat = true;
151                     switch( rOption.GetString()[0] )
152                     {
153                     case 'A':   aNumFormat.SetNumberingType(SVX_NUM_CHARS_UPPER_LETTER); break;
154                     case 'a':   aNumFormat.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER); break;
155                     case 'I':   aNumFormat.SetNumberingType(SVX_NUM_ROMAN_UPPER);        break;
156                     case 'i':   aNumFormat.SetNumberingType(SVX_NUM_ROMAN_LOWER);        break;
157                     default:    bChangeNumFormat = false;
158                     }
159                     break;
160 
161                 case HtmlTokenId::UNORDERLIST_ON:
162                     aNumFormat.SetBulletChar( rOption.GetEnum(
163                                     aHTMLULTypeTable,aNumFormat.GetBulletChar() ) );
164                     bChangeNumFormat = true;
165                     break;
166                 default: break;
167                 }
168             }
169             break;
170         case HtmlOptionId::START:
171             {
172                 sal_uInt16 nStart = static_cast<sal_uInt16>(rOption.GetNumber());
173                 if( bNewNumFormat )
174                 {
175                     aNumFormat.SetStart( nStart );
176                     bChangeNumFormat = true;
177                 }
178                 else
179                 {
180                     rInfo.SetNodeStartValue( nLevel, nStart );
181                 }
182             }
183             break;
184         case HtmlOptionId::STYLE:
185             aStyle = rOption.GetString();
186             break;
187         case HtmlOptionId::CLASS:
188             aClass = rOption.GetString();
189             break;
190         case HtmlOptionId::LANG:
191             aLang = rOption.GetString();
192             break;
193         case HtmlOptionId::DIR:
194             aDir = rOption.GetString();
195             break;
196         case HtmlOptionId::SRC:
197             if( bNewNumFormat )
198             {
199                 aBulletSrc = rOption.GetString();
200                 if( !InternalImgToPrivateURL(aBulletSrc) )
201                     aBulletSrc = URIHelper::SmartRel2Abs( INetURLObject( m_sBaseURL ), aBulletSrc, Link<OUString *, bool>(), false );
202             }
203             break;
204         case HtmlOptionId::WIDTH:
205             nWidth = static_cast<sal_uInt16>(rOption.GetNumber());
206             break;
207         case HtmlOptionId::HEIGHT:
208             nHeight = static_cast<sal_uInt16>(rOption.GetNumber());
209             break;
210         case HtmlOptionId::ALIGN:
211             eVertOri = rOption.GetEnum( aHTMLImgVAlignTable, eVertOri );
212             break;
213         default: break;
214         }
215     }
216 
217     if( !aBulletSrc.isEmpty() )
218     {
219         // A bullet list with graphics
220         aNumFormat.SetNumberingType(SVX_NUM_BITMAP);
221 
222         // Create the graphic as a brush
223         SvxBrushItem aBrushItem( RES_BACKGROUND );
224         aBrushItem.SetGraphicLink( aBulletSrc );
225         aBrushItem.SetGraphicPos( GPOS_AREA );
226 
227         // Only set size if given a width and a height
228         Size aTwipSz( nWidth, nHeight), *pTwipSz=nullptr;
229         if( nWidth!=USHRT_MAX && nHeight!=USHRT_MAX )
230         {
231             aTwipSz =
232                 Application::GetDefaultDevice()->PixelToLogic( aTwipSz,
233                                                     MapMode(MapUnit::MapTwip) );
234             pTwipSz = &aTwipSz;
235         }
236 
237         // Only set orientation if given one
238         aNumFormat.SetGraphicBrush( &aBrushItem, pTwipSz,
239                             text::VertOrientation::NONE!=eVertOri ? &eVertOri : nullptr);
240 
241         // Remember the graphic to not put it into the paragraph
242         m_aBulletGrfs[nLevel] = aBulletSrc;
243         bChangeNumFormat = true;
244     }
245     else
246         m_aBulletGrfs[nLevel].clear();
247 
248     // don't number the current paragraph (for now)
249     {
250         sal_uInt8 nLvl = nLevel;
251         SetNodeNum( nLvl );
252     }
253 
254     // create a new context
255     std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
256 
257     // Parse styles
258     if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
259     {
260         SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
261         SvxCSS1PropertyInfo aPropInfo;
262 
263         if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
264         {
265             if( bNewNumFormat )
266             {
267                 if( aPropInfo.m_bLeftMargin )
268                 {
269                     // Default indent has already been added
270                     long nAbsLSpace =
271                         aNumFormat.GetAbsLSpace() - HTML_NUMBUL_MARGINLEFT;
272                     if( aPropInfo.m_nLeftMargin < 0 &&
273                         nAbsLSpace < -aPropInfo.m_nLeftMargin )
274                         nAbsLSpace = 0U;
275                     else if( aPropInfo.m_nLeftMargin > SHRT_MAX ||
276                              nAbsLSpace + aPropInfo.m_nLeftMargin > SHRT_MAX )
277                         nAbsLSpace = SHRT_MAX;
278                     else
279                         nAbsLSpace = nAbsLSpace + aPropInfo.m_nLeftMargin;
280 
281                     aNumFormat.SetAbsLSpace( nAbsLSpace );
282                     bChangeNumFormat = true;
283                 }
284                 if( aPropInfo.m_bTextIndent )
285                 {
286                     short nTextIndent =
287                         aItemSet.Get( RES_LR_SPACE ).GetTextFirstLineOfst();
288                     aNumFormat.SetFirstLineOffset( nTextIndent );
289                     bChangeNumFormat = true;
290                 }
291                 if( aPropInfo.m_bNumbering )
292                 {
293                     aNumFormat.SetNumberingType(aPropInfo.m_nNumberingType);
294                     bChangeNumFormat = true;
295                 }
296                 if( aPropInfo.m_bBullet )
297                 {
298                     aNumFormat.SetBulletChar( aPropInfo.m_cBulletChar );
299                     bChangeNumFormat = true;
300                 }
301             }
302             aPropInfo.m_bLeftMargin = aPropInfo.m_bTextIndent = false;
303             if( !aPropInfo.m_bRightMargin )
304                 aItemSet.ClearItem( RES_LR_SPACE );
305 
306             // #i89812# - Perform change to list style before calling <DoPositioning(..)>,
307             // because <DoPositioning(..)> may open a new context and thus may
308             // clear the <SwHTMLNumRuleInfo> instance hold by local variable <rInfo>.
309             if( bChangeNumFormat )
310             {
311                 rInfo.GetNumRule()->Set( nLevel, aNumFormat );
312                 m_xDoc->ChgNumRuleFormats( *rInfo.GetNumRule() );
313                 bChangeNumFormat = false;
314             }
315 
316             DoPositioning(aItemSet, aPropInfo, xCntxt.get());
317 
318             InsertAttrs(aItemSet, aPropInfo, xCntxt.get());
319         }
320     }
321 
322     if( bChangeNumFormat )
323     {
324         rInfo.GetNumRule()->Set( nLevel, aNumFormat );
325         m_xDoc->ChgNumRuleFormats( *rInfo.GetNumRule() );
326     }
327 
328     PushContext(xCntxt);
329 
330     // set attributes to the current template
331     SetTextCollAttrs(m_aContexts.back().get());
332 }
333 
EndNumBulList(HtmlTokenId nToken)334 void SwHTMLParser::EndNumBulList( HtmlTokenId nToken )
335 {
336     SwHTMLNumRuleInfo& rInfo = GetNumInfo();
337 
338     // A new paragraph needs to be created, when
339     // - the current one isn't empty (it contains text or paragraph-bound objects)
340     // - the current one is numbered
341     bool bAppend = m_pPam->GetPoint()->nContent.GetIndex() > 0;
342     if( !bAppend )
343     {
344         SwTextNode* pTextNode = m_pPam->GetNode().GetTextNode();
345 
346         bAppend = (pTextNode && ! pTextNode->IsOutline() && pTextNode->IsCountedInList()) ||
347 
348             HasCurrentParaFlys();
349     }
350 
351     bool bSpace = (rInfo.GetDepth() + m_nDefListDeep) == 1;
352     if( bAppend )
353         AppendTextNode( bSpace ? AM_SPACE : AM_NOSPACE, false );
354     else if( bSpace )
355         AddParSpace();
356 
357     // get current context from stack
358     std::unique_ptr<HTMLAttrContext> xCntxt(nToken != HtmlTokenId::NONE ? PopContext(getOnToken(nToken)) : nullptr);
359 
360     // Don't end a list because of a token, if the context wasn't created or mustn't be ended
361     if( rInfo.GetDepth()>0 && (nToken == HtmlTokenId::NONE || xCntxt) )
362     {
363         rInfo.DecDepth();
364         if( !rInfo.GetDepth() )     // was that the last level?
365         {
366             // The formats not yet modified are now modified, to ease editing
367             const SwNumFormat *pRefNumFormat = nullptr;
368             bool bChanged = false;
369             for( sal_uInt16 i=0; i<MAXLEVEL; i++ )
370             {
371                 const SwNumFormat *pNumFormat = rInfo.GetNumRule()->GetNumFormat(i);
372                 if( pNumFormat )
373                 {
374                     pRefNumFormat = pNumFormat;
375                 }
376                 else if( pRefNumFormat )
377                 {
378                     SwNumFormat aNumFormat( rInfo.GetNumRule()->Get(i) );
379                     aNumFormat.SetNumberingType(pRefNumFormat->GetNumberingType() != SVX_NUM_BITMAP
380                                                 ? pRefNumFormat->GetNumberingType() : SVX_NUM_CHAR_SPECIAL);
381                     if( SVX_NUM_CHAR_SPECIAL == aNumFormat.GetNumberingType() )
382                     {
383                         // #i63395# - Only apply user defined default bullet font
384                         if ( numfunc::IsDefBulletFontUserDefined() )
385                         {
386                             aNumFormat.SetBulletFont( &numfunc::GetDefBulletFont() );
387                         }
388                         aNumFormat.SetBulletChar( cBulletChar );
389                     }
390                     aNumFormat.SetAbsLSpace( (i+1) * HTML_NUMBUL_MARGINLEFT );
391                     aNumFormat.SetFirstLineOffset( HTML_NUMBUL_INDENT );
392                     aNumFormat.SetCharFormat( pRefNumFormat->GetCharFormat() );
393                     rInfo.GetNumRule()->Set( i, aNumFormat );
394                     bChanged = true;
395                 }
396             }
397             if( bChanged )
398                 m_xDoc->ChgNumRuleFormats( *rInfo.GetNumRule() );
399 
400             // On the last append, the NumRule item and NodeNum object were copied.
401             // Now we need to delete them. ResetAttr deletes the NodeNum object as well
402             if (SwTextNode *pTextNode = m_pPam->GetNode().GetTextNode())
403                 pTextNode->ResetAttr(RES_PARATR_NUMRULE);
404 
405             rInfo.Clear();
406         }
407         else
408         {
409             // the next paragraph not numbered first
410             SetNodeNum( rInfo.GetLevel() );
411         }
412     }
413 
414     // end attributes
415     bool bSetAttrs = false;
416     if (xCntxt)
417     {
418         EndContext(xCntxt.get());
419         xCntxt.reset();
420         bSetAttrs = true;
421     }
422 
423     if( nToken != HtmlTokenId::NONE )
424         SetTextCollAttrs();
425 
426     if( bSetAttrs )
427         SetAttr();  // Set paragraph attributes asap because of Javascript
428 
429 }
430 
NewNumBulListItem(HtmlTokenId nToken)431 void SwHTMLParser::NewNumBulListItem( HtmlTokenId nToken )
432 {
433     sal_uInt8 nLevel = GetNumInfo().GetLevel();
434     OUString aId, aStyle, aClass, aLang, aDir;
435     sal_uInt16 nStart = HtmlTokenId::LISTHEADER_ON != nToken
436                         ? GetNumInfo().GetNodeStartValue( nLevel )
437                         : USHRT_MAX;
438     if( USHRT_MAX != nStart )
439         GetNumInfo().SetNodeStartValue( nLevel );
440 
441     const HTMLOptions& rHTMLOptions = GetOptions();
442     for (size_t i = rHTMLOptions.size(); i; )
443     {
444         const HTMLOption& rOption = rHTMLOptions[--i];
445         switch( rOption.GetToken() )
446         {
447             case HtmlOptionId::VALUE:
448                 nStart = static_cast<sal_uInt16>(rOption.GetNumber());
449                 break;
450             case HtmlOptionId::ID:
451                 aId = rOption.GetString();
452                 break;
453             case HtmlOptionId::STYLE:
454                 aStyle = rOption.GetString();
455                 break;
456             case HtmlOptionId::CLASS:
457                 aClass = rOption.GetString();
458                 break;
459             case HtmlOptionId::LANG:
460                 aLang = rOption.GetString();
461                 break;
462             case HtmlOptionId::DIR:
463                 aDir = rOption.GetString();
464                 break;
465             default: break;
466         }
467     }
468 
469     // create a new paragraph
470     if( m_pPam->GetPoint()->nContent.GetIndex() )
471         AppendTextNode( AM_NOSPACE, false );
472     m_bNoParSpace = false;    // no space in <LI>!
473 
474     SwTextNode* pTextNode = m_pPam->GetNode().GetTextNode();
475     if (!pTextNode)
476     {
477         SAL_WARN("sw.html", "No Text-Node at PaM-Position");
478         return;
479     }
480 
481     const bool bCountedInList = nToken != HtmlTokenId::LISTHEADER_ON;
482 
483     std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(nToken));
484 
485     OUString aNumRuleName;
486     if( GetNumInfo().GetNumRule() )
487     {
488         aNumRuleName = GetNumInfo().GetNumRule()->GetName();
489     }
490     else
491     {
492         aNumRuleName = m_xDoc->GetUniqueNumRuleName();
493         SwNumRule aNumRule( aNumRuleName,
494                             SvxNumberFormat::LABEL_WIDTH_AND_POSITION );
495         SwNumFormat aNumFormat( aNumRule.Get( 0 ) );
496         // #i63395# - Only apply user defined default bullet font
497         if ( numfunc::IsDefBulletFontUserDefined() )
498         {
499             aNumFormat.SetBulletFont( &numfunc::GetDefBulletFont() );
500         }
501         aNumFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
502         aNumFormat.SetBulletChar( cBulletChar );   // the bullet character !!
503         aNumFormat.SetCharFormat( m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_BUL_LEVEL) );
504         aNumFormat.SetFirstLineOffset( HTML_NUMBUL_INDENT );
505         aNumRule.Set( 0, aNumFormat );
506 
507         m_xDoc->MakeNumRule( aNumRuleName, &aNumRule );
508 
509         OSL_ENSURE( m_nOpenParaToken == HtmlTokenId::NONE,
510                 "Now an open paragraph element is lost" );
511         // We'll act like we're in a paragraph. On the next paragraph, at least numbering is gone,
512         // that's gonna be taken over by the next AppendTextNode
513         m_nOpenParaToken = nToken;
514     }
515 
516     static_cast<SwContentNode *>(pTextNode)->SetAttr( SwNumRuleItem(aNumRuleName) );
517     pTextNode->SetAttrListLevel(nLevel);
518     // #i57656# - <IsCounted()> state of text node has to be adjusted accordingly.
519     if ( nLevel < MAXLEVEL )
520     {
521         pTextNode->SetCountedInList( bCountedInList );
522     }
523     // #i57919#
524     // correction of refactoring done by cws swnumtree
525     // - <nStart> contains the start value, if the numbering has to be restarted
526     //   at this text node. Value <USHRT_MAX> indicates, that numbering isn't
527     //   restarted at this text node
528     if ( nStart != USHRT_MAX )
529     {
530         pTextNode->SetListRestart( true );
531         pTextNode->SetAttrListRestartValue( nStart );
532     }
533 
534     if( GetNumInfo().GetNumRule() )
535         GetNumInfo().GetNumRule()->SetInvalidRule( true );
536 
537     // parse styles
538     if( HasStyleOptions( aStyle, aId, aClass, &aLang, &aDir ) )
539     {
540         SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
541         SvxCSS1PropertyInfo aPropInfo;
542 
543         if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
544         {
545             DoPositioning(aItemSet, aPropInfo, xCntxt.get());
546             InsertAttrs(aItemSet, aPropInfo, xCntxt.get());
547         }
548     }
549 
550     PushContext(xCntxt);
551 
552     // set the new template
553     SetTextCollAttrs(m_aContexts.back().get());
554 
555     // Refresh scroll bar
556     ShowStatline();
557 }
558 
EndNumBulListItem(HtmlTokenId nToken,bool bSetColl)559 void SwHTMLParser::EndNumBulListItem( HtmlTokenId nToken, bool bSetColl )
560 {
561     // Create a new paragraph
562     if( nToken == HtmlTokenId::NONE && m_pPam->GetPoint()->nContent.GetIndex() )
563         AppendTextNode( AM_NOSPACE );
564 
565     // Get context to that token and pop it from stack
566     std::unique_ptr<HTMLAttrContext> xCntxt;
567     auto nPos = m_aContexts.size();
568     nToken = getOnToken(nToken);
569     while (!xCntxt && nPos>m_nContextStMin)
570     {
571         HtmlTokenId nCntxtToken = m_aContexts[--nPos]->GetToken();
572         switch( nCntxtToken )
573         {
574         case HtmlTokenId::LI_ON:
575         case HtmlTokenId::LISTHEADER_ON:
576             if( nToken == HtmlTokenId::NONE || nToken == nCntxtToken  )
577             {
578                 xCntxt = std::move(m_aContexts[nPos]);
579                 m_aContexts.erase( m_aContexts.begin() + nPos );
580             }
581             break;
582         case HtmlTokenId::ORDERLIST_ON:
583         case HtmlTokenId::UNORDERLIST_ON:
584         case HtmlTokenId::MENULIST_ON:
585         case HtmlTokenId::DIRLIST_ON:
586             // Don't care about LI/LH outside the current list
587             nPos = m_nContextStMin;
588             break;
589         default: break;
590         }
591     }
592 
593     // end attributes
594     if (xCntxt)
595     {
596         EndContext(xCntxt.get());
597         SetAttr();  // set paragraph attributes asap because of Javascript
598         xCntxt.reset();
599     }
600 
601     // set current template
602     if( bSetColl )
603         SetTextCollAttrs();
604 }
605 
SetNodeNum(sal_uInt8 nLevel)606 void SwHTMLParser::SetNodeNum( sal_uInt8 nLevel )
607 {
608     SwTextNode* pTextNode = m_pPam->GetNode().GetTextNode();
609     if (!pTextNode)
610     {
611         SAL_WARN("sw.html", "No Text-Node at PaM-Position");
612         return;
613     }
614 
615     OSL_ENSURE( GetNumInfo().GetNumRule(), "No numbering rule" );
616     const OUString& rName = GetNumInfo().GetNumRule()->GetName();
617     static_cast<SwContentNode *>(pTextNode)->SetAttr( SwNumRuleItem(rName) );
618 
619     pTextNode->SetAttrListLevel( nLevel );
620     pTextNode->SetCountedInList( false );
621 
622     // Invalidate NumRule, it may have been set valid because of an EndAction
623     GetNumInfo().GetNumRule()->SetInvalidRule( false );
624 }
625 
626 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
627