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 <memory>
21 #include <hintids.hxx>
22 #include <comphelper/string.hxx>
23 #include <comphelper/documentinfo.hxx>
24 #include <vcl/svapp.hxx>
25 #include <svx/svxids.hrc>
26 #include <i18nlangtag/languagetag.hxx>
27 #include <svl/stritem.hxx>
28 #include <svl/urihelper.hxx>
29 #include <editeng/fhgtitem.hxx>
30 #include <editeng/lrspitem.hxx>
31 #include <editeng/adjustitem.hxx>
32 #include <editeng/brushitem.hxx>
33 #include <editeng/colritem.hxx>
34 #include <editeng/boxitem.hxx>
35 #include <editeng/ulspitem.hxx>
36 #include <editeng/langitem.hxx>
37 #include <editeng/scripttypeitem.hxx>
38 #include <sfx2/docfile.hxx>
39 #include <sfx2/event.hxx>
40 #include <vcl/imap.hxx>
41 #include <svtools/htmltokn.h>
42 #include <svtools/htmlkywd.hxx>
43 #include <unotools/eventcfg.hxx>
44 #include <sal/log.hxx>
45 #include <osl/diagnose.h>
46 
47 #include <fmtornt.hxx>
48 #include <fmturl.hxx>
49 #include <fmtsrnd.hxx>
50 #include <fmtinfmt.hxx>
51 #include <fmtcntnt.hxx>
52 #include <fmtanchr.hxx>
53 #include <fmtfsize.hxx>
54 #include <frmatr.hxx>
55 #include <charatr.hxx>
56 #include <frmfmt.hxx>
57 #include <charfmt.hxx>
58 #include <docary.hxx>
59 #include <docsh.hxx>
60 #include <pam.hxx>
61 #include <doc.hxx>
62 #include <ndtxt.hxx>
63 #include <shellio.hxx>
64 #include <poolfmt.hxx>
65 #include <IMark.hxx>
66 #include <ndgrf.hxx>
67 #include "htmlnum.hxx"
68 #include "swcss1.hxx"
69 #include "swhtml.hxx"
70 #include <numrule.hxx>
71 #include <fmtflcnt.hxx>
72 #include <IDocumentMarkAccess.hxx>
73 
74 #include <vcl/graphicfilter.hxx>
75 #include <tools/urlobj.hxx>
76 
77 using namespace ::com::sun::star;
78 
79 HTMLOptionEnum<sal_Int16> const aHTMLImgHAlignTable[] =
80 {
81     { OOO_STRING_SVTOOLS_HTML_AL_left,    text::HoriOrientation::LEFT       },
82     { OOO_STRING_SVTOOLS_HTML_AL_right,   text::HoriOrientation::RIGHT      },
83     { nullptr,                            0               }
84 };
85 
86 HTMLOptionEnum<sal_Int16> const aHTMLImgVAlignTable[] =
87 {
88     { OOO_STRING_SVTOOLS_HTML_VA_top,         text::VertOrientation::LINE_TOP       },
89     { OOO_STRING_SVTOOLS_HTML_VA_texttop,     text::VertOrientation::CHAR_TOP       },
90     { OOO_STRING_SVTOOLS_HTML_VA_middle,      text::VertOrientation::CENTER         },
91     { OOO_STRING_SVTOOLS_HTML_AL_center,      text::VertOrientation::CENTER         },
92     { OOO_STRING_SVTOOLS_HTML_VA_absmiddle,   text::VertOrientation::LINE_CENTER    },
93     { OOO_STRING_SVTOOLS_HTML_VA_bottom,      text::VertOrientation::TOP            },
94     { OOO_STRING_SVTOOLS_HTML_VA_baseline,    text::VertOrientation::TOP            },
95     { OOO_STRING_SVTOOLS_HTML_VA_absbottom,   text::VertOrientation::LINE_BOTTOM    },
96     { nullptr,                                0                   }
97 };
98 
FindImageMap(const OUString & rName) const99 ImageMap *SwHTMLParser::FindImageMap( const OUString& rName ) const
100 {
101     OSL_ENSURE( rName[0] != '#', "FindImageMap: name begins with '#'!" );
102 
103     if (m_pImageMaps)
104     {
105         for (const auto &rpIMap : *m_pImageMaps)
106         {
107             if (rName.equalsIgnoreAsciiCase(rpIMap->GetName()))
108             {
109                 return rpIMap.get();
110             }
111         }
112     }
113     return nullptr;
114 }
115 
ConnectImageMaps()116 void SwHTMLParser::ConnectImageMaps()
117 {
118     SwNodes& rNds = m_xDoc->GetNodes();
119     // on the first node of section #1
120     sal_uLong nIdx = rNds.GetEndOfAutotext().StartOfSectionIndex() + 1;
121     sal_uLong nEndIdx = rNds.GetEndOfAutotext().GetIndex();
122 
123     SwGrfNode* pGrfNd;
124     while( m_nMissingImgMaps > 0 && nIdx < nEndIdx )
125     {
126         SwNode *pNd = rNds[nIdx + 1];
127         if( nullptr != (pGrfNd = pNd->GetGrfNode()) )
128         {
129             SwFrameFormat *pFormat = pGrfNd->GetFlyFormat();
130             SwFormatURL aURL( pFormat->GetURL() );
131             const ImageMap *pIMap = aURL.GetMap();
132             if( pIMap && pIMap->GetIMapObjectCount()==0 )
133             {
134                 // The (empty) image map of the node will be either
135                 // replaced with found image map or deleted.
136                 ImageMap *pNewIMap =
137                     FindImageMap( pIMap->GetName() );
138                 aURL.SetMap( pNewIMap );
139                 pFormat->SetFormatAttr( aURL );
140                 if( !pGrfNd->IsScaleImageMap() )
141                 {
142                     // meanwhile the graphic size is known or the
143                     // graphic don't need scaling
144                     pGrfNd->ScaleImageMap();
145                 }
146                 m_nMissingImgMaps--;  // search a map less
147             }
148         }
149         nIdx = rNds[nIdx]->EndOfSectionIndex() + 1;
150     }
151 }
152 
SetAnchorAndAdjustment(sal_Int16 eVertOri,sal_Int16 eHoriOri,const SvxCSS1PropertyInfo & rCSS1PropInfo,SfxItemSet & rFrameItemSet)153 void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri,
154                                            sal_Int16 eHoriOri,
155                                            const SvxCSS1PropertyInfo &rCSS1PropInfo,
156                                            SfxItemSet& rFrameItemSet )
157 {
158     const SfxItemSet *pCntnrItemSet = nullptr;
159     auto i = m_aContexts.size();
160     while( !pCntnrItemSet && i > m_nContextStMin )
161         pCntnrItemSet = m_aContexts[--i]->GetFrameItemSet();
162 
163     if( pCntnrItemSet )
164     {
165         // If we are in a container then the anchoring of the container is used.
166         rFrameItemSet.Put( *pCntnrItemSet );
167     }
168     else if( SwCSS1Parser::MayBePositioned( rCSS1PropInfo, true ) )
169     {
170         // If the alignment can be set via CSS1 options we use them.
171         SetAnchorAndAdjustment( rCSS1PropInfo, rFrameItemSet );
172     }
173     else
174     {
175         // Otherwise the alignment is set correspondingly the normal HTML options.
176         SetAnchorAndAdjustment( eVertOri, eHoriOri, rFrameItemSet );
177     }
178 }
179 
SetAnchorAndAdjustment(sal_Int16 eVertOri,sal_Int16 eHoriOri,SfxItemSet & rFrameSet,bool bDontAppend)180 void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri,
181                                            sal_Int16 eHoriOri,
182                                            SfxItemSet& rFrameSet,
183                                            bool bDontAppend )
184 {
185     bool bMoveBackward = false;
186     SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR );
187     sal_Int16 eVertRel = text::RelOrientation::FRAME;
188 
189     if( text::HoriOrientation::NONE != eHoriOri )
190     {
191         // determine paragraph indent
192         sal_uInt16 nLeftSpace = 0, nRightSpace = 0;
193         short nIndent = 0;
194         GetMarginsFromContextWithNumBul( nLeftSpace, nRightSpace, nIndent );
195 
196         // determine horizontal alignment and wrapping
197         sal_Int16 eHoriRel;
198         css::text::WrapTextMode eSurround;
199         switch( eHoriOri )
200         {
201         case text::HoriOrientation::LEFT:
202             eHoriRel = nLeftSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
203             eSurround = css::text::WrapTextMode_RIGHT;
204             break;
205         case text::HoriOrientation::RIGHT:
206             eHoriRel = nRightSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
207             eSurround = css::text::WrapTextMode_LEFT;
208             break;
209         case text::HoriOrientation::CENTER:   // for tables
210             eHoriRel = text::RelOrientation::FRAME;
211             eSurround = css::text::WrapTextMode_NONE;
212             break;
213         default:
214             eHoriRel = text::RelOrientation::FRAME;
215             eSurround = css::text::WrapTextMode_PARALLEL;
216             break;
217         }
218 
219         // Create a new paragraph, if the current one has frames
220         // anchored at paragraph/at char without wrapping.
221         if( !bDontAppend && HasCurrentParaFlys( true ) )
222         {
223             // When the paragraph only contains graphics then there
224             // is no need for bottom margin. Since here also with use of
225             // styles no margin should be created, set attributes to
226             // override!
227             sal_uInt16 nUpper=0, nLower=0;
228             GetULSpaceFromContext( nUpper, nLower );
229             InsertAttr( SvxULSpaceItem( nUpper, 0, RES_UL_SPACE ), true );
230 
231             AppendTextNode( AM_NOSPACE );
232 
233             if( nUpper )
234             {
235                 NewAttr(m_xAttrTab, &m_xAttrTab->pULSpace, SvxULSpaceItem(0, nLower, RES_UL_SPACE));
236                 m_aParaAttrs.push_back( m_xAttrTab->pULSpace );
237                 EndAttr( m_xAttrTab->pULSpace, false );
238             }
239         }
240 
241         // determine vertical alignment and anchoring
242         const sal_Int32 nContent = m_pPam->GetPoint()->nContent.GetIndex();
243         if( nContent )
244         {
245             aAnchor.SetType( RndStdIds::FLY_AT_CHAR );
246             bMoveBackward = true;
247             eVertOri = text::VertOrientation::CHAR_BOTTOM;
248             eVertRel = text::RelOrientation::CHAR;
249         }
250         else
251         {
252             aAnchor.SetType( RndStdIds::FLY_AT_PARA );
253             eVertOri = text::VertOrientation::TOP;
254             eVertRel = text::RelOrientation::PRINT_AREA;
255         }
256 
257         rFrameSet.Put( SwFormatHoriOrient( 0, eHoriOri, eHoriRel) );
258 
259         rFrameSet.Put( SwFormatSurround( eSurround ) );
260     }
261     rFrameSet.Put( SwFormatVertOrient( 0, eVertOri, eVertRel) );
262 
263     if( bMoveBackward )
264         m_pPam->Move( fnMoveBackward );
265 
266     if (aAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR && !m_pPam->GetNode().GetTextNode())
267     {
268         eState = SvParserState::Error;
269         return;
270     }
271 
272     aAnchor.SetAnchor( m_pPam->GetPoint() );
273 
274     if( bMoveBackward )
275         m_pPam->Move( fnMoveForward );
276 
277     rFrameSet.Put( aAnchor );
278 }
279 
RegisterFlyFrame(SwFrameFormat * pFlyFormat)280 void SwHTMLParser::RegisterFlyFrame( SwFrameFormat *pFlyFormat )
281 {
282     // automatically anchored frames must be moved forward by one position
283     if( RES_DRAWFRMFMT != pFlyFormat->Which() &&
284         (RndStdIds::FLY_AT_PARA == pFlyFormat->GetAnchor().GetAnchorId()) &&
285         css::text::WrapTextMode_THROUGH == pFlyFormat->GetSurround().GetSurround() )
286     {
287         m_aMoveFlyFrames.push_back( pFlyFormat );
288         m_aMoveFlyCnts.push_back( m_pPam->GetPoint()->nContent.GetIndex() );
289     }
290 }
291 
292 /*  */
293 
GetDefaultScriptType(ScriptType & rType,OUString & rTypeStr) const294 void SwHTMLParser::GetDefaultScriptType( ScriptType& rType,
295                                          OUString& rTypeStr ) const
296 {
297     SwDocShell *pDocSh = m_xDoc->GetDocShell();
298     SvKeyValueIterator* pHeaderAttrs = pDocSh ? pDocSh->GetHeaderAttributes()
299                                               : nullptr;
300     rType = GetScriptType( pHeaderAttrs );
301     rTypeStr = GetScriptTypeString( pHeaderAttrs );
302 }
303 
304 namespace
305 {
allowAccessLink(const SwDoc & rDoc)306     bool allowAccessLink(const SwDoc& rDoc)
307     {
308         OUString sReferer;
309         SfxObjectShell * sh = rDoc.GetPersist();
310         if (sh != nullptr && sh->HasName())
311         {
312             sReferer = sh->GetMedium()->GetName();
313         }
314         return !SvtSecurityOptions().isUntrustedReferer(sReferer);
315     }
316 }
317 
318 /*  */
319 
InsertImage()320 void SwHTMLParser::InsertImage()
321 {
322     // and now analyze
323     OUString sAltNm, aId, aClass, aStyle, aMap, sHTMLGrfName;
324     OUString sGrfNm;
325     OUString aGraphicData;
326     sal_Int16 eVertOri = text::VertOrientation::TOP;
327     sal_Int16 eHoriOri = text::HoriOrientation::NONE;
328     bool bWidthProvided=false, bHeightProvided=false;
329     long nWidth=0, nHeight=0;
330     long nVSpace=0, nHSpace=0;
331 
332     sal_uInt16 nBorder = (m_xAttrTab->pINetFormat ? 1 : 0);
333     bool bIsMap = false;
334     bool bPrcWidth = false;
335     bool bPrcHeight = false;
336     OUString sWidthAsString, sHeightAsString;
337     SvxMacroItem aMacroItem(RES_FRMMACRO);
338 
339     ScriptType eDfltScriptType;
340     OUString sDfltScriptType;
341     GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
342 
343     const HTMLOptions& rHTMLOptions = GetOptions();
344     for (size_t i = rHTMLOptions.size(); i; )
345     {
346         SvMacroItemId nEvent = SvMacroItemId::NONE;
347         ScriptType eScriptType2 = eDfltScriptType;
348         const HTMLOption& rOption = rHTMLOptions[--i];
349         switch( rOption.GetToken() )
350         {
351             case HtmlOptionId::ID:
352                 aId = rOption.GetString();
353                 break;
354             case HtmlOptionId::STYLE:
355                 aStyle = rOption.GetString();
356                 break;
357             case HtmlOptionId::CLASS:
358                 aClass = rOption.GetString();
359                 break;
360             case HtmlOptionId::SRC:
361                 sGrfNm = rOption.GetString();
362                 if( !InternalImgToPrivateURL(sGrfNm) )
363                     sGrfNm = INetURLObject::GetAbsURL( m_sBaseURL, sGrfNm );
364                 break;
365             case HtmlOptionId::DATA:
366                 aGraphicData = rOption.GetString();
367                 if (!InternalImgToPrivateURL(aGraphicData))
368                     aGraphicData = INetURLObject::GetAbsURL(
369                         m_sBaseURL, SwHTMLParser::StripQueryFromPath(m_sBaseURL, aGraphicData));
370                 break;
371             case HtmlOptionId::ALIGN:
372                 eVertOri =
373                     rOption.GetEnum( aHTMLImgVAlignTable,
374                                                     text::VertOrientation::TOP );
375                 eHoriOri =
376                     rOption.GetEnum( aHTMLImgHAlignTable );
377                 break;
378             case HtmlOptionId::WIDTH:
379                 // for now only store as pixel value!
380                 nWidth = rOption.GetNumber();
381                 sWidthAsString = rOption.GetString();
382                 bPrcWidth = (sWidthAsString.indexOf('%') != -1);
383                 if( bPrcWidth && nWidth>100 )
384                     nWidth = 100;
385                 // width|height = "auto" means viewing app decides the size
386                 // i.e. proceed as if no particular size was provided
387                 bWidthProvided = (sWidthAsString != "auto");
388                 break;
389             case HtmlOptionId::HEIGHT:
390                 // for now only store as pixel value!
391                 nHeight = rOption.GetNumber();
392                 sHeightAsString = rOption.GetString();
393                 bPrcHeight = (sHeightAsString.indexOf('%') != -1);
394                 if( bPrcHeight && nHeight>100 )
395                     nHeight = 100;
396                 // the same as above w/ HtmlOptionId::WIDTH
397                 bHeightProvided = (sHeightAsString != "auto");
398                 break;
399             case HtmlOptionId::VSPACE:
400                 nVSpace = rOption.GetNumber();
401                 break;
402             case HtmlOptionId::HSPACE:
403                 nHSpace = rOption.GetNumber();
404                 break;
405             case HtmlOptionId::ALT:
406                 sAltNm = rOption.GetString();
407                 break;
408             case HtmlOptionId::BORDER:
409                 nBorder = static_cast<sal_uInt16>(rOption.GetNumber());
410                 break;
411             case HtmlOptionId::ISMAP:
412                 bIsMap = true;
413                 break;
414             case HtmlOptionId::USEMAP:
415                 aMap = rOption.GetString();
416                 break;
417             case HtmlOptionId::NAME:
418                 sHTMLGrfName = rOption.GetString();
419                 break;
420 
421             case HtmlOptionId::SDONLOAD:
422                 eScriptType2 = STARBASIC;
423                 [[fallthrough]];
424             case HtmlOptionId::ONLOAD:
425                 nEvent = SvMacroItemId::OnImageLoadDone;
426                 goto IMAGE_SETEVENT;
427 
428             case HtmlOptionId::SDONABORT:
429                 eScriptType2 = STARBASIC;
430                 [[fallthrough]];
431             case HtmlOptionId::ONABORT:
432                 nEvent = SvMacroItemId::OnImageLoadCancel;
433                 goto IMAGE_SETEVENT;
434 
435             case HtmlOptionId::SDONERROR:
436                 eScriptType2 = STARBASIC;
437                 [[fallthrough]];
438             case HtmlOptionId::ONERROR:
439                 nEvent = SvMacroItemId::OnImageLoadError;
440                 goto IMAGE_SETEVENT;
441 IMAGE_SETEVENT:
442                 {
443                     OUString sTmp( rOption.GetString() );
444                     if( !sTmp.isEmpty() )
445                     {
446                         sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
447                         OUString sScriptType;
448                         if( EXTENDED_STYPE == eScriptType2 )
449                             sScriptType = sDfltScriptType;
450                         aMacroItem.SetMacro( nEvent,
451                             SvxMacro( sTmp, sScriptType, eScriptType2 ));
452                     }
453                 }
454                 break;
455             default: break;
456         }
457     }
458 
459     if (sGrfNm.isEmpty() && !aGraphicData.isEmpty())
460         sGrfNm = aGraphicData;
461 
462     if( sGrfNm.isEmpty() )
463         return;
464 
465     // When we are in an ordered list and the paragraph is still empty and not
466     // numbered, it may be a graphic for a bullet list.
467     if( !m_pPam->GetPoint()->nContent.GetIndex() &&
468         GetNumInfo().GetDepth() > 0 && GetNumInfo().GetDepth() <= MAXLEVEL &&
469         !m_aBulletGrfs[GetNumInfo().GetDepth()-1].isEmpty() &&
470         m_aBulletGrfs[GetNumInfo().GetDepth()-1]==sGrfNm )
471     {
472         SwTextNode* pTextNode = m_pPam->GetNode().GetTextNode();
473 
474         if( pTextNode && ! pTextNode->IsCountedInList())
475         {
476             OSL_ENSURE( pTextNode->GetActualListLevel() == GetNumInfo().GetLevel(),
477                     "Numbering level is wrong" );
478 
479             pTextNode->SetCountedInList( true );
480 
481             // It's necessary to invalidate the rule, because between the reading
482             // of LI and the graphic an EndAction could be called.
483             if( GetNumInfo().GetNumRule() )
484                 GetNumInfo().GetNumRule()->SetInvalidRule( true );
485 
486             // Set the style again, so that indent of the first line is correct.
487             SetTextCollAttrs();
488 
489             return;
490         }
491     }
492 
493     Graphic aGraphic;
494     INetURLObject aGraphicURL( sGrfNm );
495     if( aGraphicURL.GetProtocol() == INetProtocol::Data )
496     {
497         std::unique_ptr<SvMemoryStream> const pStream(aGraphicURL.getData());
498         if (pStream)
499         {
500             GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
501             aGraphic = rFilter.ImportUnloadedGraphic(*pStream);
502             sGrfNm.clear();
503 
504             if (!sGrfNm.isEmpty())
505             {
506                 if (ERRCODE_NONE == rFilter.ImportGraphic(aGraphic, "", *pStream))
507                     sGrfNm.clear();
508             }
509         }
510     }
511     else if (m_sBaseURL.isEmpty() || !aGraphicData.isEmpty())
512     {
513         // sBaseURL is empty if the source is clipboard
514         // aGraphicData is non-empty for <object data="..."> -> not a linked graphic.
515         if (ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aGraphicURL))
516             sGrfNm.clear();
517     }
518 
519     if (!sGrfNm.isEmpty())
520     {
521         aGraphic.SetDefaultType();
522     }
523 
524     if (!nHeight || !nWidth)
525     {
526         Size aPixelSize = aGraphic.GetSizePixel(Application::GetDefaultDevice());
527         if (!bWidthProvided)
528             nWidth = aPixelSize.Width();
529         if (!bHeightProvided)
530             nHeight = aPixelSize.Height();
531     }
532 
533     SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
534     SvxCSS1PropertyInfo aPropInfo;
535     if( HasStyleOptions( aStyle, aId, aClass ) )
536         ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo );
537 
538     SfxItemSet aFrameSet( m_xDoc->GetAttrPool(),
539                         svl::Items<RES_FRMATR_BEGIN, RES_FRMATR_END-1>{} );
540     if( !IsNewDoc() )
541         Reader::ResetFrameFormatAttrs( aFrameSet );
542 
543     // set the border
544     long nHBorderWidth = 0, nVBorderWidth = 0;
545     if( nBorder )
546     {
547         nHBorderWidth = static_cast<long>(nBorder);
548         nVBorderWidth = static_cast<long>(nBorder);
549         SvxCSS1Parser::PixelToTwip( nVBorderWidth, nHBorderWidth );
550 
551         ::editeng::SvxBorderLine aHBorderLine( nullptr, nHBorderWidth );
552         ::editeng::SvxBorderLine aVBorderLine( nullptr, nVBorderWidth );
553 
554         if( m_xAttrTab->pINetFormat )
555         {
556             const OUString& rURL =
557                 static_cast<const SwFormatINetFormat&>(m_xAttrTab->pINetFormat->GetItem()).GetValue();
558 
559             m_pCSS1Parser->SetATagStyles();
560             sal_uInt16 nPoolId =  static_cast< sal_uInt16 >(m_xDoc->IsVisitedURL( rURL )
561                                     ? RES_POOLCHR_INET_VISIT
562                                     : RES_POOLCHR_INET_NORMAL);
563             const SwCharFormat *pCharFormat = m_pCSS1Parser->GetCharFormatFromPool( nPoolId );
564             aHBorderLine.SetColor( pCharFormat->GetColor().GetValue() );
565             aVBorderLine.SetColor( aHBorderLine.GetColor() );
566         }
567         else
568         {
569             const SvxColorItem& rColorItem = m_xAttrTab->pFontColor ?
570               static_cast<const SvxColorItem &>(m_xAttrTab->pFontColor->GetItem()) :
571               m_xDoc->GetDefault(RES_CHRATR_COLOR);
572             aHBorderLine.SetColor( rColorItem.GetValue() );
573             aVBorderLine.SetColor( aHBorderLine.GetColor() );
574         }
575 
576         SvxBoxItem aBoxItem( RES_BOX );
577         aBoxItem.SetLine( &aHBorderLine, SvxBoxItemLine::TOP );
578         aBoxItem.SetLine( &aHBorderLine, SvxBoxItemLine::BOTTOM );
579         aBoxItem.SetLine( &aVBorderLine, SvxBoxItemLine::LEFT );
580         aBoxItem.SetLine( &aVBorderLine, SvxBoxItemLine::RIGHT );
581         aFrameSet.Put( aBoxItem );
582     }
583 
584     SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, aFrameSet );
585 
586     SetSpace( Size( nHSpace, nVSpace), aItemSet, aPropInfo, aFrameSet );
587 
588     // set other CSS1 attributes
589     SetFrameFormatAttrs( aItemSet, HtmlFrameFormatFlags::Box, aFrameSet );
590 
591     Size aTwipSz( bPrcWidth ? 0 : nWidth, bPrcHeight ? 0 : nHeight );
592     if( (aTwipSz.Width() || aTwipSz.Height()) && Application::GetDefaultDevice() )
593     {
594         if (bWidthProvided || bHeightProvided || // attributes imply pixel!
595             aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
596         {
597             aTwipSz = Application::GetDefaultDevice()
598                     ->PixelToLogic( aTwipSz, MapMode( MapUnit::MapTwip ) );
599         }
600         else
601         {   // some bitmaps may have a size in metric units (e.g. PNG); use that
602             assert(aGraphic.GetPrefMapMode().GetMapUnit() < MapUnit::MapPixel);
603             aTwipSz = OutputDevice::LogicToLogic(aGraphic.GetPrefSize(),
604                     aGraphic.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
605         }
606     }
607 
608     // convert CSS1 size to "normal" size
609     switch( aPropInfo.m_eWidthType )
610     {
611         case SVX_CSS1_LTYPE_TWIP:
612             aTwipSz.setWidth( aPropInfo.m_nWidth );
613             nWidth = 1; // != 0
614             bPrcWidth = false;
615             break;
616         case SVX_CSS1_LTYPE_PERCENTAGE:
617             aTwipSz.setWidth( 0 );
618             nWidth = aPropInfo.m_nWidth;
619             bPrcWidth = true;
620             break;
621         default:
622             ;
623     }
624     switch( aPropInfo.m_eHeightType )
625     {
626         case SVX_CSS1_LTYPE_TWIP:
627             aTwipSz.setHeight( aPropInfo.m_nHeight );
628             nHeight = 1;    // != 0
629             bPrcHeight = false;
630             break;
631         case SVX_CSS1_LTYPE_PERCENTAGE:
632             aTwipSz.setHeight( 0 );
633             nHeight = aPropInfo.m_nHeight;
634             bPrcHeight = true;
635             break;
636         default:
637             ;
638     }
639 
640     Size aGrfSz( 0, 0 );
641     bool bSetTwipSize = true;       // Set Twip-Size on Node?
642     bool bChangeFrameSize = false;    // Change frame format later?
643     bool bRequestGrfNow = false;
644     bool bSetScaleImageMap = false;
645     sal_uInt8 nPrcWidth = 0, nPrcHeight = 0;
646 
647     // bPrcWidth / bPrcHeight means we have a percent size.  If that's not the case and we have no
648     // size from nWidth / nHeight either, then inspect the image header.
649     if ((!bPrcWidth && !nWidth) && (!bPrcHeight && !nHeight) && allowAccessLink(*m_xDoc))
650     {
651         GraphicDescriptor aDescriptor(aGraphicURL);
652         if (aDescriptor.Detect(/*bExtendedInfo=*/true))
653         {
654             // Try to use size info from the image header before defaulting to
655             // HTML_DFLT_IMG_WIDTH/HEIGHT.
656             aTwipSz = Application::GetDefaultDevice()->PixelToLogic(aDescriptor.GetSizePixel(),
657                                                                     MapMode(MapUnit::MapTwip));
658             nWidth = aTwipSz.getWidth();
659             nHeight = aTwipSz.getHeight();
660         }
661     }
662 
663     if( !nWidth || !nHeight )
664     {
665         // When the graphic is in a table, it will be requested immediately,
666         // so that it is available before the table is layouted.
667         if (m_xTable && !nWidth)
668         {
669             bRequestGrfNow = true;
670             IncGrfsThatResizeTable();
671         }
672 
673         // The frame size is set later
674         bChangeFrameSize = true;
675         aGrfSz = aTwipSz;
676         if( !nWidth && !nHeight )
677         {
678             aTwipSz.setWidth( HTML_DFLT_IMG_WIDTH );
679             aTwipSz.setHeight( HTML_DFLT_IMG_HEIGHT );
680         }
681         else if( nWidth )
682         {
683             // a percentage value
684             if( bPrcWidth )
685             {
686                 nPrcWidth = static_cast<sal_uInt8>(nWidth);
687                 nPrcHeight = 255;
688             }
689             else
690             {
691                 aTwipSz.setHeight( HTML_DFLT_IMG_HEIGHT );
692             }
693         }
694         else if( nHeight )
695         {
696             if( bPrcHeight )
697             {
698                 nPrcHeight = static_cast<sal_uInt8>(nHeight);
699                 nPrcWidth = 255;
700             }
701             else
702             {
703                 aTwipSz.setWidth( HTML_DFLT_IMG_WIDTH );
704             }
705         }
706     }
707     else
708     {
709         // Width and height were given and don't need to be set
710         bSetTwipSize = false;
711 
712         if( bPrcWidth )
713             nPrcWidth = static_cast<sal_uInt8>(nWidth);
714 
715         if( bPrcHeight )
716             nPrcHeight = static_cast<sal_uInt8>(nHeight);
717     }
718 
719     // set image map
720     aMap = comphelper::string::stripEnd(aMap, ' ');
721     if( !aMap.isEmpty() )
722     {
723         // Since we only know local image maps we just use everything
724         // after # as name
725         sal_Int32 nPos = aMap.indexOf( '#' );
726         OUString aName;
727         if ( -1 == nPos )
728             aName = aMap ;
729         else
730             aName = aMap.copy(nPos+1);
731 
732         ImageMap *pImgMap = FindImageMap( aName );
733         if( pImgMap )
734         {
735             SwFormatURL aURL; aURL.SetMap( pImgMap );// is copied
736 
737             bSetScaleImageMap = !nPrcWidth || !nPrcHeight;
738             aFrameSet.Put( aURL );
739         }
740         else
741         {
742             ImageMap aEmptyImgMap( aName );
743             SwFormatURL aURL; aURL.SetMap( &aEmptyImgMap );// is copied
744             aFrameSet.Put( aURL );
745             m_nMissingImgMaps++;          // image maps are missing
746 
747             // the graphic has to scaled during SetTwipSize, if we didn't
748             // set a size on the node or the size doesn't match the graphic size.
749             bSetScaleImageMap = true;
750         }
751     }
752 
753     // observe minimum values !!
754     if( nPrcWidth )
755     {
756         OSL_ENSURE( !aTwipSz.Width(),
757                 "Why is a width set if we already have percentage value?" );
758         aTwipSz.setWidth( aGrfSz.Width() ? aGrfSz.Width()
759                                          : HTML_DFLT_IMG_WIDTH );
760     }
761     else
762     {
763         aTwipSz.AdjustWidth(2*nVBorderWidth );
764         if( aTwipSz.Width() < MINFLY )
765             aTwipSz.setWidth( MINFLY );
766     }
767     if( nPrcHeight )
768     {
769         OSL_ENSURE( !aTwipSz.Height(),
770                 "Why is a height set if we already have percentage value?" );
771         aTwipSz.setHeight( aGrfSz.Height() ? aGrfSz.Height()
772                                            : HTML_DFLT_IMG_HEIGHT );
773     }
774     else
775     {
776         aTwipSz.AdjustHeight(2*nHBorderWidth );
777         if( aTwipSz.Height() < MINFLY )
778             aTwipSz.setHeight( MINFLY );
779     }
780 
781     SwFormatFrameSize aFrameSize( ATT_FIX_SIZE, aTwipSz.Width(), aTwipSz.Height() );
782     aFrameSize.SetWidthPercent( nPrcWidth );
783     aFrameSize.SetHeightPercent( nPrcHeight );
784     aFrameSet.Put( aFrameSize );
785 
786     const SwNodeType eNodeType = m_pPam->GetNode().GetNodeType();
787     if (eNodeType != SwNodeType::Text && eNodeType != SwNodeType::Table)
788         return;
789 
790     // passing empty sGrfNm here, means we don't want the graphic to be linked
791     SwFrameFormat *const pFlyFormat =
792         m_xDoc->getIDocumentContentOperations().InsertGraphic(
793             *m_pPam, sGrfNm, OUString(), &aGraphic,
794             &aFrameSet, nullptr, nullptr);
795     SwGrfNode *pGrfNd = m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx()
796                                   ->GetIndex()+1 ]->GetGrfNode();
797 
798     if( !sHTMLGrfName.isEmpty() )
799     {
800         pFlyFormat->SetName( sHTMLGrfName );
801 
802         // maybe jump to graphic
803         if( JumpToMarks::Graphic == m_eJumpTo && sHTMLGrfName == m_sJmpMark )
804         {
805             m_bChkJumpMark = true;
806             m_eJumpTo = JumpToMarks::NONE;
807         }
808     }
809 
810     if (pGrfNd)
811     {
812         if( !sAltNm.isEmpty() )
813             pGrfNd->SetTitle( sAltNm );
814 
815         if( bSetTwipSize )
816             pGrfNd->SetTwipSize( aGrfSz );
817 
818         pGrfNd->SetChgTwipSize( bChangeFrameSize );
819 
820         if( bSetScaleImageMap )
821             pGrfNd->SetScaleImageMap( true );
822     }
823 
824     if( m_xAttrTab->pINetFormat )
825     {
826         const SwFormatINetFormat &rINetFormat =
827             static_cast<const SwFormatINetFormat&>(m_xAttrTab->pINetFormat->GetItem());
828 
829         SwFormatURL aURL( pFlyFormat->GetURL() );
830 
831         aURL.SetURL( rINetFormat.GetValue(), bIsMap );
832         aURL.SetTargetFrameName( rINetFormat.GetTargetFrame() );
833         aURL.SetName( rINetFormat.GetName() );
834         pFlyFormat->SetFormatAttr( aURL );
835 
836         {
837             static const SvMacroItemId aEvents[] = {
838                 SvMacroItemId::OnMouseOver,
839                 SvMacroItemId::OnClick,
840                 SvMacroItemId::OnMouseOut };
841 
842             for( SvMacroItemId id : aEvents )
843             {
844                 const SvxMacro *pMacro = rINetFormat.GetMacro( id );
845                 if( nullptr != pMacro )
846                     aMacroItem.SetMacro( id, *pMacro );
847             }
848         }
849 
850         if ((RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()) &&
851             m_xAttrTab->pINetFormat->GetSttPara() ==
852                         m_pPam->GetPoint()->nNode &&
853             m_xAttrTab->pINetFormat->GetSttCnt() ==
854                         m_pPam->GetPoint()->nContent.GetIndex() - 1 )
855         {
856             // the attribute was insert right before as-character anchored
857             // graphic, therefore we move it
858             m_xAttrTab->pINetFormat->SetStart( *m_pPam->GetPoint() );
859 
860             // When the attribute is also an anchor, we'll insert
861             // a bookmark before the graphic, because SwFormatURL
862             // isn't an anchor.
863             if( !rINetFormat.GetName().isEmpty() )
864             {
865                 m_pPam->Move( fnMoveBackward );
866                 InsertBookmark( rINetFormat.GetName() );
867                 m_pPam->Move( fnMoveForward );
868             }
869         }
870 
871     }
872 
873     if( !aMacroItem.GetMacroTable().empty() )
874     {
875         NotifyMacroEventRead();
876         pFlyFormat->SetFormatAttr( aMacroItem );
877     }
878 
879     // tdf#87083 If the graphic has not been loaded yet, then load it now.
880     // Otherwise it may be loaded during the first paint of the object and it
881     // will be too late to adapt the size of the graphic at that point.
882     if (bRequestGrfNow && pGrfNd)
883     {
884         Size aUpdatedSize = pGrfNd->GetTwipSize();  //trigger a swap-in
885         SAL_WARN_IF(!aUpdatedSize.Width() || !aUpdatedSize.Height(), "sw.html", "html image with no width or height");
886     }
887 
888     // maybe create frames and register auto bound frames
889     RegisterFlyFrame( pFlyFormat );
890 
891     if( !aId.isEmpty() )
892         InsertBookmark( aId );
893 }
894 
895 /*  */
896 
InsertBodyOptions()897 void SwHTMLParser::InsertBodyOptions()
898 {
899     m_xDoc->SetTextFormatColl( *m_pPam,
900                          m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
901 
902     OUString aBackGround, aId, aStyle, aLang, aDir;
903     Color aBGColor, aTextColor, aLinkColor, aVLinkColor;
904     bool bBGColor=false, bTextColor=false;
905     bool bLinkColor=false, bVLinkColor=false;
906 
907     ScriptType eDfltScriptType;
908     OUString sDfltScriptType;
909     GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
910 
911     const HTMLOptions& rHTMLOptions = GetOptions();
912     for (size_t i = rHTMLOptions.size(); i; )
913     {
914         const HTMLOption& rOption = rHTMLOptions[--i];
915         ScriptType eScriptType2 = eDfltScriptType;
916         OUString aEvent;
917         bool bSetEvent = false;
918 
919         switch( rOption.GetToken() )
920         {
921             case HtmlOptionId::ID:
922                 aId = rOption.GetString();
923                 break;
924             case HtmlOptionId::BACKGROUND:
925                 aBackGround = rOption.GetString();
926                 break;
927             case HtmlOptionId::BGCOLOR:
928                 rOption.GetColor( aBGColor );
929                 bBGColor = true;
930                 break;
931             case HtmlOptionId::TEXT:
932                 rOption.GetColor( aTextColor );
933                 bTextColor = true;
934                 break;
935             case HtmlOptionId::LINK:
936                 rOption.GetColor( aLinkColor );
937                 bLinkColor = true;
938                 break;
939             case HtmlOptionId::VLINK:
940                 rOption.GetColor( aVLinkColor );
941                 bVLinkColor = true;
942                 break;
943 
944             case HtmlOptionId::SDONLOAD:
945                 eScriptType2 = STARBASIC;
946                 [[fallthrough]];
947             case HtmlOptionId::ONLOAD:
948                 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC );
949                 bSetEvent = true;
950                 break;
951 
952             case HtmlOptionId::SDONUNLOAD:
953                 eScriptType2 = STARBASIC;
954                 [[fallthrough]];
955             case HtmlOptionId::ONUNLOAD:
956                 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::PREPARECLOSEDOC );
957                 bSetEvent = true;
958                 break;
959 
960             case HtmlOptionId::SDONFOCUS:
961                 eScriptType2 = STARBASIC;
962                 [[fallthrough]];
963             case HtmlOptionId::ONFOCUS:
964                 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC );
965                 bSetEvent = true;
966                 break;
967 
968             case HtmlOptionId::SDONBLUR:
969                 eScriptType2 = STARBASIC;
970                 [[fallthrough]];
971             case HtmlOptionId::ONBLUR:
972                 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC );
973                 bSetEvent = true;
974                 break;
975 
976             case HtmlOptionId::ONERROR:
977                 break;
978 
979             case HtmlOptionId::STYLE:
980                 aStyle = rOption.GetString();
981                 bTextColor = true;
982                 break;
983             case HtmlOptionId::LANG:
984                 aLang = rOption.GetString();
985                 break;
986             case HtmlOptionId::DIR:
987                 aDir = rOption.GetString();
988                 break;
989             default: break;
990         }
991 
992         if( bSetEvent )
993         {
994             const OUString& rEvent = rOption.GetString();
995             if( !rEvent.isEmpty() )
996                 InsertBasicDocEvent( aEvent, rEvent, eScriptType2,
997                                      sDfltScriptType );
998         }
999     }
1000 
1001     if( bTextColor && !m_pCSS1Parser->IsBodyTextSet() )
1002     {
1003         // The font colour is set in the default style
1004         m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD )
1005             ->SetFormatAttr( SvxColorItem(aTextColor, RES_CHRATR_COLOR) );
1006         m_pCSS1Parser->SetBodyTextSet();
1007     }
1008 
1009     // Prepare the items for the page style (background, frame)
1010     // If BrushItem already set values must remain!
1011     std::shared_ptr<SvxBrushItem> aBrushItem( m_pCSS1Parser->makePageDescBackground() );
1012     bool bSetBrush = false;
1013 
1014     if( bBGColor && !m_pCSS1Parser->IsBodyBGColorSet() )
1015     {
1016         // background colour from "BGCOLOR"
1017         OUString aLink;
1018         if( !aBrushItem->GetGraphicLink().isEmpty() )
1019             aLink = aBrushItem->GetGraphicLink();
1020         SvxGraphicPosition ePos = aBrushItem->GetGraphicPos();
1021 
1022         aBrushItem->SetColor( aBGColor );
1023 
1024         if( !aLink.isEmpty() )
1025         {
1026             aBrushItem->SetGraphicLink( aLink );
1027             aBrushItem->SetGraphicPos( ePos );
1028         }
1029         bSetBrush = true;
1030         m_pCSS1Parser->SetBodyBGColorSet();
1031     }
1032 
1033     if( !aBackGround.isEmpty() && !m_pCSS1Parser->IsBodyBackgroundSet() )
1034     {
1035         // background graphic from "BACKGROUND"
1036         aBrushItem->SetGraphicLink( INetURLObject::GetAbsURL( m_sBaseURL, aBackGround ) );
1037         aBrushItem->SetGraphicPos( GPOS_TILED );
1038         bSetBrush = true;
1039         m_pCSS1Parser->SetBodyBackgroundSet();
1040     }
1041 
1042     if( !aStyle.isEmpty() || !aDir.isEmpty() )
1043     {
1044         SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
1045         SvxCSS1PropertyInfo aPropInfo;
1046         OUString aDummy;
1047         ParseStyleOptions( aStyle, aDummy, aDummy, aItemSet, aPropInfo, nullptr, &aDir );
1048 
1049         // Some attributes have to set on the page style, in fact the ones
1050         // which aren't inherited
1051         m_pCSS1Parser->SetPageDescAttrs( bSetBrush ? aBrushItem.get() : nullptr,
1052                                        &aItemSet );
1053 
1054         const SfxPoolItem *pItem;
1055         static const sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONTSIZE,
1056                                        RES_CHRATR_CJK_FONTSIZE,
1057                                        RES_CHRATR_CTL_FONTSIZE };
1058         for(sal_uInt16 i : aWhichIds)
1059         {
1060             if( SfxItemState::SET == aItemSet.GetItemState( i, false,
1061                                                        &pItem ) &&
1062                 static_cast <const SvxFontHeightItem * >(pItem)->GetProp() != 100)
1063             {
1064                 sal_uInt32 nHeight =
1065                     ( m_aFontHeights[2] *
1066                      static_cast <const SvxFontHeightItem * >(pItem)->GetProp() ) / 100;
1067                 SvxFontHeightItem aNewItem( nHeight, 100, i );
1068                 aItemSet.Put( aNewItem );
1069             }
1070         }
1071 
1072         // all remaining options can be set on the default style
1073         m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD )
1074             ->SetFormatAttr( aItemSet );
1075     }
1076     else if( bSetBrush )
1077     {
1078         m_pCSS1Parser->SetPageDescAttrs( aBrushItem.get() );
1079     }
1080 
1081     if( bLinkColor && !m_pCSS1Parser->IsBodyLinkSet() )
1082     {
1083         SwCharFormat *pCharFormat =
1084             m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_INET_NORMAL);
1085         pCharFormat->SetFormatAttr( SvxColorItem(aLinkColor, RES_CHRATR_COLOR) );
1086         m_pCSS1Parser->SetBodyLinkSet();
1087     }
1088     if( bVLinkColor && !m_pCSS1Parser->IsBodyVLinkSet() )
1089     {
1090         SwCharFormat *pCharFormat =
1091             m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_INET_VISIT);
1092         pCharFormat->SetFormatAttr( SvxColorItem(aVLinkColor, RES_CHRATR_COLOR) );
1093         m_pCSS1Parser->SetBodyVLinkSet();
1094     }
1095     if( !aLang.isEmpty() )
1096     {
1097         LanguageType eLang = LanguageTag::convertToLanguageTypeWithFallback( aLang );
1098         if( LANGUAGE_DONTKNOW != eLang )
1099         {
1100             sal_uInt16 nWhich = 0;
1101             switch( SvtLanguageOptions::GetScriptTypeOfLanguage( eLang ) )
1102             {
1103             case SvtScriptType::LATIN:
1104                 nWhich = RES_CHRATR_LANGUAGE;
1105                 break;
1106             case SvtScriptType::ASIAN:
1107                 nWhich = RES_CHRATR_CJK_LANGUAGE;
1108                 break;
1109             case SvtScriptType::COMPLEX:
1110                 nWhich = RES_CHRATR_CTL_LANGUAGE;
1111                 break;
1112             default: break;
1113             }
1114             if( nWhich )
1115             {
1116                 SvxLanguageItem aLanguage( eLang, nWhich );
1117                 aLanguage.SetWhich( nWhich );
1118                 m_xDoc->SetDefault( aLanguage );
1119             }
1120         }
1121     }
1122 
1123     if( !aId.isEmpty() )
1124         InsertBookmark( aId );
1125 }
1126 
1127 /*  */
1128 
NewAnchor()1129 void SwHTMLParser::NewAnchor()
1130 {
1131     // end previous link if there was one
1132     std::unique_ptr<HTMLAttrContext> xOldCntxt(PopContext(HtmlTokenId::ANCHOR_ON));
1133     if (xOldCntxt)
1134     {
1135         // and maybe end attributes
1136         EndContext(xOldCntxt.get());
1137     }
1138 
1139     SvxMacroTableDtor aMacroTable;
1140     OUString sHRef, aName, sTarget;
1141     OUString aId, aStyle, aClass, aLang, aDir;
1142     bool bHasHRef = false, bFixed = false;
1143 
1144     ScriptType eDfltScriptType;
1145     OUString sDfltScriptType;
1146     GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
1147 
1148     const HTMLOptions& rHTMLOptions = GetOptions();
1149     for (size_t i = rHTMLOptions.size(); i; )
1150     {
1151         SvMacroItemId nEvent = SvMacroItemId::NONE;
1152         ScriptType eScriptType2 = eDfltScriptType;
1153         const HTMLOption& rOption = rHTMLOptions[--i];
1154         switch( rOption.GetToken() )
1155         {
1156             case HtmlOptionId::NAME:
1157                 aName = rOption.GetString();
1158                 break;
1159 
1160             case HtmlOptionId::HREF:
1161                 sHRef = rOption.GetString();
1162                 bHasHRef = true;
1163                 break;
1164             case HtmlOptionId::TARGET:
1165                 sTarget = rOption.GetString();
1166                 break;
1167 
1168             case HtmlOptionId::STYLE:
1169                 aStyle = rOption.GetString();
1170                 break;
1171             case HtmlOptionId::ID:
1172                 aId = rOption.GetString();
1173                 break;
1174             case HtmlOptionId::CLASS:
1175                 aClass = rOption.GetString();
1176                 break;
1177             case HtmlOptionId::SDFIXED:
1178                 bFixed = true;
1179                 break;
1180             case HtmlOptionId::LANG:
1181                 aLang = rOption.GetString();
1182                 break;
1183             case HtmlOptionId::DIR:
1184                 aDir = rOption.GetString();
1185                 break;
1186 
1187             case HtmlOptionId::SDONCLICK:
1188                 eScriptType2 = STARBASIC;
1189                 [[fallthrough]];
1190             case HtmlOptionId::ONCLICK:
1191                 nEvent = SvMacroItemId::OnClick;
1192                 goto ANCHOR_SETEVENT;
1193 
1194             case HtmlOptionId::SDONMOUSEOVER:
1195                 eScriptType2 = STARBASIC;
1196                 [[fallthrough]];
1197             case HtmlOptionId::ONMOUSEOVER:
1198                 nEvent = SvMacroItemId::OnMouseOver;
1199                 goto ANCHOR_SETEVENT;
1200 
1201             case HtmlOptionId::SDONMOUSEOUT:
1202                 eScriptType2 = STARBASIC;
1203                 [[fallthrough]];
1204             case HtmlOptionId::ONMOUSEOUT:
1205                 nEvent = SvMacroItemId::OnMouseOut;
1206                 goto ANCHOR_SETEVENT;
1207 ANCHOR_SETEVENT:
1208                 {
1209                     OUString sTmp( rOption.GetString() );
1210                     if( !sTmp.isEmpty() )
1211                     {
1212                         sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
1213                         OUString sScriptType;
1214                         if( EXTENDED_STYPE == eScriptType2 )
1215                             sScriptType = sDfltScriptType;
1216                         aMacroTable.Insert( nEvent, SvxMacro( sTmp, sScriptType, eScriptType2 ));
1217                     }
1218                 }
1219                 break;
1220             default: break;
1221         }
1222     }
1223 
1224     // Jump targets, which match our implicit targets,
1225     // here we throw out rigorously.
1226     if( !aName.isEmpty() )
1227     {
1228         OUString sDecoded( INetURLObject::decode( aName,
1229                                            INetURLObject::DecodeMechanism::Unambiguous ));
1230         sal_Int32 nPos = sDecoded.lastIndexOf( cMarkSeparator );
1231         if( nPos != -1 )
1232         {
1233             OUString sCmp= sDecoded.copy(nPos+1).replaceAll(" ","");
1234             if( !sCmp.isEmpty() )
1235             {
1236                 sCmp = sCmp.toAsciiLowerCase();
1237                 if( sCmp == "region" ||
1238                     sCmp == "frame" ||
1239                     sCmp == "graphic" ||
1240                     sCmp == "ole" ||
1241                     sCmp == "table" ||
1242                     sCmp == "outline" ||
1243                     sCmp == "text" )
1244                 {
1245                     aName.clear();
1246                 }
1247             }
1248         }
1249     }
1250 
1251     // create a new context
1252     std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::ANCHOR_ON));
1253 
1254     bool bEnAnchor = false, bFootnoteAnchor = false, bFootnoteEnSymbol = false;
1255     OUString aFootnoteName;
1256     OUString aStrippedClass( aClass );
1257     SwCSS1Parser::GetScriptFromClass( aStrippedClass, false );
1258     if( aStrippedClass.getLength() >=9  && bHasHRef && sHRef.getLength() > 1 &&
1259         ('s' == aStrippedClass[0] || 'S' == aStrippedClass[0]) &&
1260         ('d' == aStrippedClass[1] || 'D' == aStrippedClass[1]) )
1261     {
1262         if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote_anc ) )
1263             bEnAnchor = true;
1264         else if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote_anc ) )
1265             bFootnoteAnchor = true;
1266         else if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote_sym ) ||
1267                  aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote_sym ) )
1268             bFootnoteEnSymbol = true;
1269         if( bEnAnchor || bFootnoteAnchor || bFootnoteEnSymbol )
1270         {
1271             aFootnoteName = sHRef.copy( 1 );
1272             aClass.clear();
1273             aStrippedClass.clear();
1274             aName.clear();
1275             bHasHRef = false;
1276         }
1277     }
1278 
1279     // Styles parsen
1280     if( HasStyleOptions( aStyle, aId, aStrippedClass, &aLang, &aDir ) )
1281     {
1282         SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
1283         SvxCSS1PropertyInfo aPropInfo;
1284 
1285         if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
1286         {
1287             DoPositioning(aItemSet, aPropInfo, xCntxt.get());
1288             InsertAttrs(aItemSet, aPropInfo, xCntxt.get(), true);
1289         }
1290     }
1291 
1292     if( bHasHRef )
1293     {
1294         if( !sHRef.isEmpty() )
1295         {
1296             sHRef = URIHelper::SmartRel2Abs( INetURLObject(m_sBaseURL), sHRef, Link<OUString *, bool>(), false );
1297         }
1298         else
1299         {
1300             // use directory if empty URL
1301             INetURLObject aURLObj( m_aPathToFile );
1302             sHRef = aURLObj.GetPartBeforeLastName();
1303         }
1304 
1305         m_pCSS1Parser->SetATagStyles();
1306         SwFormatINetFormat aINetFormat( sHRef, sTarget );
1307         aINetFormat.SetName( aName );
1308 
1309         if( !aMacroTable.empty() )
1310         {
1311             NotifyMacroEventRead();
1312             aINetFormat.SetMacroTable( &aMacroTable );
1313         }
1314 
1315         // set the default attribute
1316         InsertAttr(&m_xAttrTab->pINetFormat, aINetFormat, xCntxt.get());
1317     }
1318     else if( !aName.isEmpty() )
1319     {
1320         InsertBookmark( aName );
1321     }
1322 
1323     if( bEnAnchor || bFootnoteAnchor )
1324     {
1325         InsertFootEndNote( aFootnoteName, bEnAnchor, bFixed );
1326         m_bInFootEndNoteAnchor = m_bCallNextToken = true;
1327     }
1328     else if( bFootnoteEnSymbol )
1329     {
1330         m_bInFootEndNoteSymbol = m_bCallNextToken = true;
1331     }
1332 
1333     // save context
1334     PushContext(xCntxt);
1335 }
1336 
EndAnchor()1337 void SwHTMLParser::EndAnchor()
1338 {
1339     if( m_bInFootEndNoteAnchor )
1340     {
1341         FinishFootEndNote();
1342         m_bInFootEndNoteAnchor = false;
1343     }
1344     else if( m_bInFootEndNoteSymbol )
1345     {
1346         m_bInFootEndNoteSymbol = false;
1347     }
1348 
1349     EndTag( HtmlTokenId::ANCHOR_OFF );
1350 }
1351 
1352 /*  */
1353 
InsertBookmark(const OUString & rName)1354 void SwHTMLParser::InsertBookmark( const OUString& rName )
1355 {
1356     HTMLAttr* pTmp = new HTMLAttr( *m_pPam->GetPoint(),
1357             SfxStringItem(RES_FLTR_BOOKMARK, rName), nullptr, std::shared_ptr<HTMLAttrTable>());
1358     m_aSetAttrTab.push_back( pTmp );
1359 }
1360 
HasCurrentParaBookmarks(bool bIgnoreStack) const1361 bool SwHTMLParser::HasCurrentParaBookmarks( bool bIgnoreStack ) const
1362 {
1363     bool bHasMarks = false;
1364     sal_uLong nNodeIdx = m_pPam->GetPoint()->nNode.GetIndex();
1365 
1366     // first step: are there still bookmark in the attribute-stack?
1367     // bookmarks are added to the end of the stack - thus we only have
1368     // to check the last bookmark
1369     if( !bIgnoreStack )
1370     {
1371         for( auto i = m_aSetAttrTab.size(); i; )
1372         {
1373             HTMLAttr* pAttr = m_aSetAttrTab[ --i ];
1374             if( RES_FLTR_BOOKMARK == pAttr->m_pItem->Which() )
1375             {
1376                 if( pAttr->GetSttParaIdx() == nNodeIdx )
1377                     bHasMarks = true;
1378                 break;
1379             }
1380         }
1381     }
1382 
1383     if( !bHasMarks )
1384     {
1385         // second step: when we didn't find a bookmark, check if there is one set already
1386         IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
1387         for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
1388             ppMark != pMarkAccess->getAllMarksEnd();
1389             ++ppMark)
1390         {
1391             const ::sw::mark::IMark* pBookmark = *ppMark;
1392 
1393             const sal_uLong nBookNdIdx = pBookmark->GetMarkPos().nNode.GetIndex();
1394             if( nBookNdIdx==nNodeIdx )
1395             {
1396                 bHasMarks = true;
1397                 break;
1398             }
1399             else if( nBookNdIdx > nNodeIdx )
1400                 break;
1401         }
1402     }
1403 
1404     return bHasMarks;
1405 }
1406 
1407 /*  */
1408 
StripTrailingPara()1409 void SwHTMLParser::StripTrailingPara()
1410 {
1411     bool bSetSmallFont = false;
1412 
1413     SwContentNode* pCNd = m_pPam->GetContentNode();
1414     sal_uLong nNodeIdx = m_pPam->GetPoint()->nNode.GetIndex();
1415     if( !m_pPam->GetPoint()->nContent.GetIndex() )
1416     {
1417         if( pCNd && pCNd->StartOfSectionIndex() + 2 <
1418             pCNd->EndOfSectionIndex() && CanRemoveNode(nNodeIdx))
1419         {
1420             const SwFrameFormats& rFrameFormatTable = *m_xDoc->GetSpzFrameFormats();
1421 
1422             for( auto pFormat : rFrameFormatTable )
1423             {
1424                 SwFormatAnchor const*const pAnchor = &pFormat->GetAnchor();
1425                 SwPosition const*const pAPos = pAnchor->GetContentAnchor();
1426                 if (pAPos &&
1427                     ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
1428                      (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
1429                     pAPos->nNode == nNodeIdx )
1430 
1431                     return;     // we can't delete the node
1432             }
1433 
1434             SetAttr( false );   // the still open attributes must be
1435                                 // closed before the node is deleted,
1436                                 // otherwise the last index is dangling
1437 
1438             if( pCNd->Len() && pCNd->IsTextNode() )
1439             {
1440                 // fields were inserted into the node, now they have
1441                 // to be moved
1442                 SwTextNode *pPrvNd = m_xDoc->GetNodes()[nNodeIdx-1]->GetTextNode();
1443                 if( pPrvNd )
1444                 {
1445                     SwIndex aSrc( pCNd, 0 );
1446                     pCNd->GetTextNode()->CutText( pPrvNd, aSrc, pCNd->Len() );
1447                 }
1448             }
1449 
1450             // now we have to move maybe existing bookmarks
1451             IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
1452             for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
1453                 ppMark != pMarkAccess->getAllMarksEnd();
1454                 ++ppMark)
1455             {
1456                 ::sw::mark::IMark* pMark = *ppMark;
1457 
1458                 sal_uLong nBookNdIdx = pMark->GetMarkPos().nNode.GetIndex();
1459                 if(nBookNdIdx==nNodeIdx)
1460                 {
1461                     SwNodeIndex nNewNdIdx(m_pPam->GetPoint()->nNode);
1462                     SwContentNode* pNd = SwNodes::GoPrevious(&nNewNdIdx);
1463                     if(!pNd)
1464                     {
1465                         OSL_ENSURE(false, "Oops, where is my predecessor node?");
1466                         return;
1467                     }
1468                     // #i81002# - refactoring
1469                     // Do not directly manipulate member of <SwBookmark>
1470                     {
1471                         SwPosition aNewPos(*pNd);
1472                         aNewPos.nContent.Assign(pNd, pNd->Len());
1473                         const SwPaM aPaM(aNewPos);
1474                         pMarkAccess->repositionMark(*ppMark, aPaM);
1475                     }
1476                 }
1477                 else if( nBookNdIdx > nNodeIdx )
1478                     break;
1479             }
1480 
1481             m_pPam->GetPoint()->nContent.Assign( nullptr, 0 );
1482             m_pPam->SetMark();
1483             m_pPam->DeleteMark();
1484             m_xDoc->GetNodes().Delete( m_pPam->GetPoint()->nNode );
1485             m_pPam->Move( fnMoveBackward, GoInNode );
1486         }
1487         else if (pCNd && pCNd->IsTextNode() && m_xTable)
1488         {
1489             // In empty cells we set a small font, so that the cell doesn't
1490             // get higher than the graphic resp. as low as possible.
1491             bSetSmallFont = true;
1492         }
1493     }
1494     else if( pCNd && pCNd->IsTextNode() && m_xTable &&
1495              pCNd->StartOfSectionIndex()+2 ==
1496              pCNd->EndOfSectionIndex() )
1497     {
1498         // When the cell contains only as-character anchored graphics/frames,
1499         // then we also set a small font.
1500         bSetSmallFont = true;
1501         SwTextNode* pTextNd = pCNd->GetTextNode();
1502 
1503         sal_Int32 nPos = m_pPam->GetPoint()->nContent.GetIndex();
1504         while( bSetSmallFont && nPos>0 )
1505         {
1506             --nPos;
1507             bSetSmallFont =
1508                 (CH_TXTATR_BREAKWORD == pTextNd->GetText()[nPos]) &&
1509                 (nullptr != pTextNd->GetTextAttrForCharAt( nPos, RES_TXTATR_FLYCNT ));
1510         }
1511     }
1512 
1513     if( bSetSmallFont )
1514     {
1515         // Added default to CJK and CTL
1516         SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
1517         pCNd->SetAttr( aFontHeight );
1518         SvxFontHeightItem aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE );
1519         pCNd->SetAttr( aFontHeightCJK );
1520         SvxFontHeightItem aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE );
1521         pCNd->SetAttr( aFontHeightCTL );
1522     }
1523 }
1524 
NotifyMacroEventRead()1525 void SwHTMLParser::NotifyMacroEventRead()
1526 {
1527     if (m_bNotifyMacroEventRead)
1528         return;
1529     SwDocShell *pDocSh = m_xDoc->GetDocShell();
1530     if (!pDocSh)
1531         return;
1532     uno::Reference<frame::XModel> const xModel(pDocSh->GetBaseModel());
1533     comphelper::DocumentInfo::notifyMacroEventRead(xModel);
1534     m_bNotifyMacroEventRead = true;
1535 }
1536 
1537 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1538