Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / filter / html / htmlgrin.cxx
blob1deccee5f9b23627b6ac6d232073767b12223aa1
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 <hintids.hxx>
22 #include <comphelper/string.hxx>
23 #include <comphelper/documentinfo.hxx>
24 #include <vcl/svapp.hxx>
25 #include <i18nlangtag/languagetag.hxx>
26 #include <svl/stritem.hxx>
27 #include <svl/urihelper.hxx>
28 #include <svl/languageoptions.hxx>
29 #include <editeng/fhgtitem.hxx>
30 #include <editeng/brushitem.hxx>
31 #include <editeng/colritem.hxx>
32 #include <editeng/boxitem.hxx>
33 #include <editeng/ulspitem.hxx>
34 #include <editeng/langitem.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <sfx2/event.hxx>
37 #include <vcl/imap.hxx>
38 #include <svtools/htmltokn.h>
39 #include <svtools/htmlkywd.hxx>
40 #include <unotools/eventcfg.hxx>
41 #include <sal/log.hxx>
42 #include <osl/diagnose.h>
43 #include <o3tl/string_view.hxx>
45 #include <fmtornt.hxx>
46 #include <fmturl.hxx>
47 #include <fmtsrnd.hxx>
48 #include <fmtinfmt.hxx>
49 #include <fmtcntnt.hxx>
50 #include <fmtanchr.hxx>
51 #include <fmtfsize.hxx>
52 #include <charatr.hxx>
53 #include <frmfmt.hxx>
54 #include <charfmt.hxx>
55 #include <docsh.hxx>
56 #include <pam.hxx>
57 #include <doc.hxx>
58 #include <ndtxt.hxx>
59 #include <shellio.hxx>
60 #include <poolfmt.hxx>
61 #include <IMark.hxx>
62 #include <ndgrf.hxx>
63 #include "htmlnum.hxx"
64 #include "swcss1.hxx"
65 #include "swhtml.hxx"
66 #include <numrule.hxx>
67 #include <IDocumentMarkAccess.hxx>
68 #include <frameformats.hxx>
70 #include <vcl/graphicfilter.hxx>
71 #include <tools/UnitConversion.hxx>
72 #include <tools/urlobj.hxx>
73 #include <unotools/securityoptions.hxx>
75 using namespace ::com::sun::star;
77 HTMLOptionEnum<sal_Int16> const aHTMLImgHAlignTable[] =
79 { OOO_STRING_SVTOOLS_HTML_AL_left, text::HoriOrientation::LEFT },
80 { OOO_STRING_SVTOOLS_HTML_AL_right, text::HoriOrientation::RIGHT },
81 { nullptr, 0 }
84 HTMLOptionEnum<sal_Int16> const aHTMLImgVAlignTable[] =
86 { OOO_STRING_SVTOOLS_HTML_VA_top, text::VertOrientation::LINE_TOP },
87 { OOO_STRING_SVTOOLS_HTML_VA_texttop, text::VertOrientation::CHAR_TOP },
88 { OOO_STRING_SVTOOLS_HTML_VA_middle, text::VertOrientation::CENTER },
89 { OOO_STRING_SVTOOLS_HTML_AL_center, text::VertOrientation::CENTER },
90 { OOO_STRING_SVTOOLS_HTML_VA_absmiddle, text::VertOrientation::LINE_CENTER },
91 { OOO_STRING_SVTOOLS_HTML_VA_bottom, text::VertOrientation::TOP },
92 { OOO_STRING_SVTOOLS_HTML_VA_baseline, text::VertOrientation::TOP },
93 { OOO_STRING_SVTOOLS_HTML_VA_absbottom, text::VertOrientation::LINE_BOTTOM },
94 { nullptr, 0 }
97 ImageMap *SwHTMLParser::FindImageMap( std::u16string_view rName ) const
99 OSL_ENSURE( rName[0] != '#', "FindImageMap: name begins with '#'!" );
101 if (m_pImageMaps)
103 for (const auto &rpIMap : *m_pImageMaps)
105 if (o3tl::equalsIgnoreAsciiCase(rName, rpIMap->GetName()))
107 return rpIMap.get();
111 return nullptr;
114 void SwHTMLParser::ConnectImageMaps()
116 SwNodes& rNds = m_xDoc->GetNodes();
117 // on the first node of section #1
118 SwNodeOffset nIdx = rNds.GetEndOfAutotext().StartOfSectionIndex() + 1;
119 SwNodeOffset nEndIdx = rNds.GetEndOfAutotext().GetIndex();
121 SwGrfNode* pGrfNd;
122 while( m_nMissingImgMaps > 0 && nIdx < nEndIdx )
124 SwNode *pNd = rNds[nIdx + 1];
125 pGrfNd = pNd->GetGrfNode();
126 if( nullptr != pGrfNd )
128 SwFrameFormat *pFormat = pGrfNd->GetFlyFormat();
129 SwFormatURL aURL( pFormat->GetURL() );
130 const ImageMap *pIMap = aURL.GetMap();
131 if( pIMap && pIMap->GetIMapObjectCount()==0 )
133 // The (empty) image map of the node will be either
134 // replaced with found image map or deleted.
135 ImageMap *pNewIMap =
136 FindImageMap( pIMap->GetName() );
137 aURL.SetMap( pNewIMap );
138 pFormat->SetFormatAttr( aURL );
139 if( !pGrfNd->IsScaleImageMap() )
141 // meanwhile the graphic size is known or the
142 // graphic don't need scaling
143 pGrfNd->ScaleImageMap();
145 m_nMissingImgMaps--; // search a map less
148 nIdx = rNds[nIdx]->EndOfSectionIndex() + 1;
152 void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri,
153 sal_Int16 eHoriOri,
154 const SvxCSS1PropertyInfo &rCSS1PropInfo,
155 SfxItemSet& rFrameItemSet )
157 const SfxItemSet *pCntnrItemSet = nullptr;
158 auto i = m_aContexts.size();
159 while( !pCntnrItemSet && i > m_nContextStMin )
160 pCntnrItemSet = m_aContexts[--i]->GetFrameItemSet();
162 if( pCntnrItemSet )
164 // If we are in a container then the anchoring of the container is used.
165 rFrameItemSet.Put( *pCntnrItemSet );
167 else if( SwCSS1Parser::MayBePositioned( rCSS1PropInfo, true ) )
169 // If the alignment can be set via CSS1 options we use them.
170 SetAnchorAndAdjustment( rCSS1PropInfo, rFrameItemSet );
172 else
174 // Otherwise the alignment is set correspondingly the normal HTML options.
175 SetAnchorAndAdjustment( eVertOri, eHoriOri, rFrameItemSet );
179 void SwHTMLParser::SetAnchorAndAdjustment( sal_Int16 eVertOri,
180 sal_Int16 eHoriOri,
181 SfxItemSet& rFrameSet,
182 bool bDontAppend )
184 bool bMoveBackward = false;
185 SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR );
186 sal_Int16 eVertRel = text::RelOrientation::FRAME;
188 if( text::HoriOrientation::NONE != eHoriOri )
190 // determine paragraph indent
191 sal_uInt16 nLeftSpace = 0, nRightSpace = 0;
192 short nIndent = 0;
193 GetMarginsFromContextWithNumberBullet( nLeftSpace, nRightSpace, nIndent );
195 // determine horizontal alignment and wrapping
196 sal_Int16 eHoriRel;
197 css::text::WrapTextMode eSurround;
198 switch( eHoriOri )
200 case text::HoriOrientation::LEFT:
201 eHoriRel = nLeftSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
202 eSurround = css::text::WrapTextMode_RIGHT;
203 break;
204 case text::HoriOrientation::RIGHT:
205 eHoriRel = nRightSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
206 eSurround = css::text::WrapTextMode_LEFT;
207 break;
208 case text::HoriOrientation::CENTER: // for tables
209 eHoriRel = text::RelOrientation::FRAME;
210 eSurround = css::text::WrapTextMode_NONE;
211 break;
212 default:
213 eHoriRel = text::RelOrientation::FRAME;
214 eSurround = css::text::WrapTextMode_PARALLEL;
215 break;
218 // Create a new paragraph, if the current one has frames
219 // anchored at paragraph/at char without wrapping.
220 if( !bDontAppend && HasCurrentParaFlys( true ) )
222 // When the paragraph only contains graphics then there
223 // is no need for bottom margin. Since here also with use of
224 // styles no margin should be created, set attributes to
225 // override!
226 sal_uInt16 nUpper=0, nLower=0;
227 GetULSpaceFromContext( nUpper, nLower );
228 InsertAttr( SvxULSpaceItem( nUpper, 0, RES_UL_SPACE ), true );
230 AppendTextNode( AM_NOSPACE );
232 if( nUpper )
234 NewAttr(m_xAttrTab, &m_xAttrTab->pULSpace, SvxULSpaceItem(0, nLower, RES_UL_SPACE));
235 m_aParaAttrs.push_back( m_xAttrTab->pULSpace );
236 EndAttr( m_xAttrTab->pULSpace, false );
240 // determine vertical alignment and anchoring
241 const sal_Int32 nContent = m_pPam->GetPoint()->GetContentIndex();
242 if( nContent )
244 aAnchor.SetType( RndStdIds::FLY_AT_CHAR );
245 bMoveBackward = true;
246 eVertOri = text::VertOrientation::CHAR_BOTTOM;
247 eVertRel = text::RelOrientation::CHAR;
249 else
251 aAnchor.SetType( RndStdIds::FLY_AT_PARA );
252 eVertOri = text::VertOrientation::TOP;
253 eVertRel = text::RelOrientation::PRINT_AREA;
256 rFrameSet.Put( SwFormatHoriOrient( 0, eHoriOri, eHoriRel) );
258 rFrameSet.Put( SwFormatSurround( eSurround ) );
260 rFrameSet.Put( SwFormatVertOrient( 0, eVertOri, eVertRel) );
262 if( bMoveBackward )
263 m_pPam->Move( fnMoveBackward );
265 if (aAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR && !m_pPam->GetPointNode().GetTextNode())
267 eState = SvParserState::Error;
268 return;
271 aAnchor.SetAnchor( m_pPam->GetPoint() );
273 if( bMoveBackward )
274 m_pPam->Move( fnMoveForward );
276 rFrameSet.Put( aAnchor );
279 void SwHTMLParser::RegisterFlyFrame( SwFrameFormat *pFlyFormat )
281 // automatically anchored frames must be moved forward by one position
282 if( RES_DRAWFRMFMT != pFlyFormat->Which() &&
283 (RndStdIds::FLY_AT_PARA == pFlyFormat->GetAnchor().GetAnchorId()) &&
284 css::text::WrapTextMode_THROUGH == pFlyFormat->GetSurround().GetSurround() )
286 m_aMoveFlyFrames.emplace_back(std::make_unique<SwHTMLFrameFormatListener>(pFlyFormat));
287 m_aMoveFlyCnts.push_back( m_pPam->GetPoint()->GetContentIndex() );
291 /* */
293 void SwHTMLParser::GetDefaultScriptType( ScriptType& rType,
294 OUString& rTypeStr ) const
296 SwDocShell *pDocSh = m_xDoc->GetDocShell();
297 SvKeyValueIterator* pHeaderAttrs = pDocSh ? pDocSh->GetHeaderAttributes()
298 : nullptr;
299 rType = GetScriptType( pHeaderAttrs );
300 rTypeStr = GetScriptTypeString( pHeaderAttrs );
303 namespace
305 bool allowAccessLink(const SwDoc& rDoc)
307 OUString sReferer;
308 SfxObjectShell * sh = rDoc.GetPersist();
309 if (sh != nullptr && sh->HasName())
311 sReferer = sh->GetMedium()->GetName();
313 return !SvtSecurityOptions::isUntrustedReferer(sReferer);
317 /* */
319 void SwHTMLParser::InsertImage()
321 // and now analyze
322 OUString sAltNm, aId, aClass, aStyle, aMap, sHTMLGrfName;
323 OUString sGrfNm;
324 OUString aGraphicData;
325 sal_Int16 eVertOri = text::VertOrientation::TOP;
326 sal_Int16 eHoriOri = text::HoriOrientation::NONE;
327 bool bWidthProvided=false, bHeightProvided=false;
328 tools::Long nWidth=0, nHeight=0;
329 tools::Long nVSpace=0, nHSpace=0;
331 sal_uInt16 nBorder = (m_xAttrTab->pINetFormat ? 1 : 0);
332 bool bIsMap = false;
333 bool bPercentWidth = false;
334 bool bPercentHeight = false;
335 OUString sWidthAsString, sHeightAsString;
336 SvxMacroItem aMacroItem(RES_FRMMACRO);
338 ScriptType eDfltScriptType;
339 OUString sDfltScriptType;
340 GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
342 const HTMLOptions& rHTMLOptions = GetOptions();
343 for (size_t i = rHTMLOptions.size(); i; )
345 SvMacroItemId nEvent = SvMacroItemId::NONE;
346 ScriptType eScriptType2 = eDfltScriptType;
347 const HTMLOption& rOption = rHTMLOptions[--i];
348 switch( rOption.GetToken() )
350 case HtmlOptionId::ID:
351 aId = rOption.GetString();
352 break;
353 case HtmlOptionId::STYLE:
354 aStyle = rOption.GetString();
355 break;
356 case HtmlOptionId::CLASS:
357 aClass = rOption.GetString();
358 break;
359 case HtmlOptionId::SRC:
360 sGrfNm = rOption.GetString();
361 if( !InternalImgToPrivateURL(sGrfNm) )
362 sGrfNm = INetURLObject::GetAbsURL( m_sBaseURL, sGrfNm );
363 break;
364 case HtmlOptionId::DATA:
365 aGraphicData = rOption.GetString();
366 if (!InternalImgToPrivateURL(aGraphicData))
367 aGraphicData = INetURLObject::GetAbsURL(
368 m_sBaseURL, SwHTMLParser::StripQueryFromPath(m_sBaseURL, aGraphicData));
369 break;
370 case HtmlOptionId::ALIGN:
371 eVertOri =
372 rOption.GetEnum( aHTMLImgVAlignTable,
373 text::VertOrientation::TOP );
374 eHoriOri =
375 rOption.GetEnum( aHTMLImgHAlignTable );
376 break;
377 case HtmlOptionId::WIDTH:
378 // for now only store as pixel value!
379 nWidth = rOption.GetNumber();
380 sWidthAsString = rOption.GetString();
381 bPercentWidth = (sWidthAsString.indexOf('%') != -1);
382 if( bPercentWidth && nWidth>100 )
383 nWidth = 100;
384 // width|height = "auto" means viewing app decides the size
385 // i.e. proceed as if no particular size was provided
386 bWidthProvided = (sWidthAsString != "auto");
387 break;
388 case HtmlOptionId::HEIGHT:
389 // for now only store as pixel value!
390 nHeight = rOption.GetNumber();
391 sHeightAsString = rOption.GetString();
392 bPercentHeight = (sHeightAsString.indexOf('%') != -1);
393 if( bPercentHeight && nHeight>100 )
394 nHeight = 100;
395 // the same as above w/ HtmlOptionId::WIDTH
396 bHeightProvided = (sHeightAsString != "auto");
397 break;
398 case HtmlOptionId::VSPACE:
399 nVSpace = rOption.GetNumber();
400 break;
401 case HtmlOptionId::HSPACE:
402 nHSpace = rOption.GetNumber();
403 break;
404 case HtmlOptionId::ALT:
405 sAltNm = rOption.GetString();
406 break;
407 case HtmlOptionId::BORDER:
408 nBorder = o3tl::narrowing<sal_uInt16>(rOption.GetNumber());
409 break;
410 case HtmlOptionId::ISMAP:
411 bIsMap = true;
412 break;
413 case HtmlOptionId::USEMAP:
414 aMap = rOption.GetString();
415 break;
416 case HtmlOptionId::NAME:
417 sHTMLGrfName = rOption.GetString();
418 break;
420 case HtmlOptionId::SDONLOAD:
421 eScriptType2 = STARBASIC;
422 [[fallthrough]];
423 case HtmlOptionId::ONLOAD:
424 nEvent = SvMacroItemId::OnImageLoadDone;
425 goto IMAGE_SETEVENT;
427 case HtmlOptionId::SDONABORT:
428 eScriptType2 = STARBASIC;
429 [[fallthrough]];
430 case HtmlOptionId::ONABORT:
431 nEvent = SvMacroItemId::OnImageLoadCancel;
432 goto IMAGE_SETEVENT;
434 case HtmlOptionId::SDONERROR:
435 eScriptType2 = STARBASIC;
436 [[fallthrough]];
437 case HtmlOptionId::ONERROR:
438 nEvent = SvMacroItemId::OnImageLoadError;
439 goto IMAGE_SETEVENT;
440 IMAGE_SETEVENT:
442 OUString sTmp( rOption.GetString() );
443 if( !sTmp.isEmpty() )
445 sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
446 OUString sScriptType;
447 if( EXTENDED_STYPE == eScriptType2 )
448 sScriptType = sDfltScriptType;
449 aMacroItem.SetMacro( nEvent,
450 SvxMacro( sTmp, sScriptType, eScriptType2 ));
453 break;
454 default: break;
458 if (sGrfNm.isEmpty() && !aGraphicData.isEmpty())
459 sGrfNm = aGraphicData;
461 if( sGrfNm.isEmpty() )
462 return;
464 // When we are in an ordered list and the paragraph is still empty and not
465 // numbered, it may be a graphic for a bullet list.
466 if( !m_pPam->GetPoint()->GetContentIndex() &&
467 GetNumInfo().GetDepth() > 0 && GetNumInfo().GetDepth() <= MAXLEVEL &&
468 !m_aBulletGrfs[GetNumInfo().GetDepth()-1].isEmpty() &&
469 m_aBulletGrfs[GetNumInfo().GetDepth()-1]==sGrfNm )
471 SwTextNode* pTextNode = m_pPam->GetPointNode().GetTextNode();
473 if( pTextNode && ! pTextNode->IsCountedInList())
475 OSL_ENSURE( pTextNode->GetActualListLevel() == GetNumInfo().GetLevel(),
476 "Numbering level is wrong" );
478 pTextNode->SetCountedInList( true );
480 // It's necessary to invalidate the rule, because between the reading
481 // of LI and the graphic an EndAction could be called.
482 if( GetNumInfo().GetNumRule() )
483 GetNumInfo().GetNumRule()->SetInvalidRule( true );
485 // Set the style again, so that indent of the first line is correct.
486 SetTextCollAttrs();
488 return;
492 Graphic aGraphic;
493 INetURLObject aGraphicURL( sGrfNm );
494 if( aGraphicURL.GetProtocol() == INetProtocol::Data )
496 std::unique_ptr<SvMemoryStream> const pStream(aGraphicURL.getData());
497 if (pStream)
499 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
500 aGraphic = rFilter.ImportUnloadedGraphic(*pStream);
501 sGrfNm.clear();
503 if (!sGrfNm.isEmpty())
505 if (ERRCODE_NONE == rFilter.ImportGraphic(aGraphic, u"", *pStream))
506 sGrfNm.clear();
510 else if (m_sBaseURL.isEmpty() || !aGraphicData.isEmpty())
512 // sBaseURL is empty if the source is clipboard
513 // aGraphicData is non-empty for <object data="..."> -> not a linked graphic.
514 if (ERRCODE_NONE == GraphicFilter::GetGraphicFilter().ImportGraphic(aGraphic, aGraphicURL))
515 sGrfNm.clear();
518 if (!sGrfNm.isEmpty())
520 aGraphic.SetDefaultType();
523 if (!nHeight || !nWidth)
525 Size aPixelSize = aGraphic.GetSizePixel(Application::GetDefaultDevice());
526 if (!bWidthProvided)
527 nWidth = aPixelSize.Width();
528 if (!bHeightProvided)
529 nHeight = aPixelSize.Height();
530 // tdf#142781 - calculate the width/height keeping the aspect ratio
531 if (bWidthProvided && !bHeightProvided && aPixelSize.Width())
533 if (bPercentWidth)
535 nHeight = SwFormatFrameSize::SYNCED;
536 bPercentHeight = true;
538 else
540 nHeight = nWidth * aPixelSize.Height() / aPixelSize.Width();
543 else if (!bWidthProvided && bHeightProvided && aPixelSize.Height())
545 if (bPercentHeight)
547 nWidth = SwFormatFrameSize::SYNCED;
548 bPercentWidth = true;
550 else
552 nWidth = nHeight * aPixelSize.Width() / aPixelSize.Height();
557 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
558 SvxCSS1PropertyInfo aPropInfo;
559 if( HasStyleOptions( aStyle, aId, aClass ) )
560 ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo );
562 SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END-1> aFrameSet( m_xDoc->GetAttrPool() );
563 if( !IsNewDoc() )
564 Reader::ResetFrameFormatAttrs( aFrameSet );
566 // set the border
567 tools::Long nHBorderWidth = 0, nVBorderWidth = 0;
568 if( nBorder )
570 nHBorderWidth = static_cast<tools::Long>(nBorder);
571 nVBorderWidth = static_cast<tools::Long>(nBorder);
572 SvxCSS1Parser::PixelToTwip( nVBorderWidth, nHBorderWidth );
574 ::editeng::SvxBorderLine aHBorderLine( nullptr, nHBorderWidth );
575 ::editeng::SvxBorderLine aVBorderLine( nullptr, nVBorderWidth );
577 if( m_xAttrTab->pINetFormat )
579 const OUString& rURL =
580 static_cast<const SwFormatINetFormat&>(m_xAttrTab->pINetFormat->GetItem()).GetValue();
582 m_pCSS1Parser->SetATagStyles();
583 sal_uInt16 nPoolId = static_cast< sal_uInt16 >(m_xDoc->IsVisitedURL( rURL )
584 ? RES_POOLCHR_INET_VISIT
585 : RES_POOLCHR_INET_NORMAL);
586 const SwCharFormat *pCharFormat = m_pCSS1Parser->GetCharFormatFromPool( nPoolId );
587 aHBorderLine.SetColor( pCharFormat->GetColor().GetValue() );
588 aVBorderLine.SetColor( aHBorderLine.GetColor() );
590 else
592 const SvxColorItem& rColorItem = m_xAttrTab->pFontColor ?
593 static_cast<const SvxColorItem &>(m_xAttrTab->pFontColor->GetItem()) :
594 m_xDoc->GetDefault(RES_CHRATR_COLOR);
595 aHBorderLine.SetColor( rColorItem.GetValue() );
596 aVBorderLine.SetColor( aHBorderLine.GetColor() );
599 SvxBoxItem aBoxItem( RES_BOX );
600 aBoxItem.SetLine( &aHBorderLine, SvxBoxItemLine::TOP );
601 aBoxItem.SetLine( &aHBorderLine, SvxBoxItemLine::BOTTOM );
602 aBoxItem.SetLine( &aVBorderLine, SvxBoxItemLine::LEFT );
603 aBoxItem.SetLine( &aVBorderLine, SvxBoxItemLine::RIGHT );
604 aFrameSet.Put( aBoxItem );
607 SetAnchorAndAdjustment( eVertOri, eHoriOri, aPropInfo, aFrameSet );
609 SetSpace( Size( nHSpace, nVSpace), aItemSet, aPropInfo, aFrameSet );
611 // set other CSS1 attributes
612 SetFrameFormatAttrs( aItemSet, HtmlFrameFormatFlags::Box, aFrameSet );
614 Size aTwipSz( bPercentWidth ? 0 : nWidth, bPercentHeight ? 0 : nHeight );
615 if( aTwipSz.Width() || aTwipSz.Height() )
617 if (bWidthProvided || bHeightProvided || // attributes imply pixel!
618 aGraphic.GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
620 aTwipSz = o3tl::convert(aTwipSz, o3tl::Length::px, o3tl::Length::twip);
622 else
623 { // some bitmaps may have a size in metric units (e.g. PNG); use that
624 assert(aGraphic.GetPrefMapMode().GetMapUnit() < MapUnit::MapPixel);
625 aTwipSz = o3tl::convert(aGraphic.GetPrefSize(),
626 MapToO3tlLength(aGraphic.GetPrefMapMode().GetMapUnit()),
627 o3tl::Length::twip);
631 // convert CSS1 size to "normal" size
632 switch( aPropInfo.m_eWidthType )
634 case SVX_CSS1_LTYPE_TWIP:
635 aTwipSz.setWidth( aPropInfo.m_nWidth );
636 nWidth = 1; // != 0
637 bPercentWidth = false;
638 break;
639 case SVX_CSS1_LTYPE_PERCENTAGE:
640 aTwipSz.setWidth( 0 );
641 nWidth = aPropInfo.m_nWidth;
642 bPercentWidth = true;
643 break;
644 default:
647 switch( aPropInfo.m_eHeightType )
649 case SVX_CSS1_LTYPE_TWIP:
650 aTwipSz.setHeight( aPropInfo.m_nHeight );
651 nHeight = 1; // != 0
652 bPercentHeight = false;
653 break;
654 case SVX_CSS1_LTYPE_PERCENTAGE:
655 aTwipSz.setHeight( 0 );
656 nHeight = aPropInfo.m_nHeight;
657 bPercentHeight = true;
658 break;
659 default:
663 Size aGrfSz( 0, 0 );
664 bool bSetTwipSize = true; // Set Twip-Size on Node?
665 bool bChangeFrameSize = false; // Change frame format later?
666 bool bRequestGrfNow = false;
667 bool bSetScaleImageMap = false;
668 sal_uInt8 nPercentWidth = 0, nPercentHeight = 0;
670 // bPercentWidth / bPercentHeight means we have a percent size. If that's not the case and we have no
671 // size from nWidth / nHeight either, then inspect the image header.
672 bool bRelWidthScale = bPercentWidth && nWidth == SwFormatFrameSize::SYNCED;
673 bool bNeedWidth = (!bPercentWidth && !nWidth) || bRelWidthScale;
674 bool bRelHeightScale = bPercentHeight && nHeight == SwFormatFrameSize::SYNCED;
675 bool bNeedHeight = (!bPercentHeight && !nHeight) || bRelHeightScale;
676 if ((bNeedWidth || bNeedHeight) && !bFuzzing && allowAccessLink(*m_xDoc))
678 GraphicDescriptor aDescriptor(aGraphicURL);
679 if (aDescriptor.Detect(/*bExtendedInfo=*/true))
681 // Try to use size info from the image header before defaulting to
682 // HTML_DFLT_IMG_WIDTH/HEIGHT.
683 aTwipSz
684 = o3tl::convert(aDescriptor.GetSizePixel(), o3tl::Length::px, o3tl::Length::twip);
685 if (!bPercentWidth && !nWidth)
687 nWidth = aTwipSz.getWidth();
689 if (!bPercentHeight && !nHeight)
691 nHeight = aTwipSz.getHeight();
696 if( !(nWidth && !bRelWidthScale) || !(nHeight && !bRelHeightScale) )
698 // When the graphic is in a table, it will be requested immediately,
699 // so that it is available before the table is layouted.
700 if (m_xTable && !nWidth)
702 bRequestGrfNow = true;
703 IncGrfsThatResizeTable();
706 // The frame size is set later
707 bChangeFrameSize = true;
708 aGrfSz = aTwipSz;
709 if( !nWidth && !nHeight )
711 aTwipSz.setWidth( HTML_DFLT_IMG_WIDTH );
712 aTwipSz.setHeight( HTML_DFLT_IMG_HEIGHT );
714 else if( nWidth )
716 // a percentage value
717 if( bPercentWidth )
719 nPercentWidth = static_cast<sal_uInt8>(nWidth);
720 nPercentHeight = 255;
722 else
724 aTwipSz.setHeight( HTML_DFLT_IMG_HEIGHT );
727 else if( nHeight )
729 if( bPercentHeight )
731 nPercentHeight = static_cast<sal_uInt8>(nHeight);
732 nPercentWidth = 255;
734 else
736 aTwipSz.setWidth( HTML_DFLT_IMG_WIDTH );
740 else
742 // Width and height were given and don't need to be set
743 bSetTwipSize = false;
745 if( bPercentWidth )
746 nPercentWidth = static_cast<sal_uInt8>(nWidth);
748 if( bPercentHeight )
749 nPercentHeight = static_cast<sal_uInt8>(nHeight);
752 // set image map
753 aMap = comphelper::string::stripEnd(aMap, ' ');
754 if( !aMap.isEmpty() )
756 // Since we only know local image maps we just use everything
757 // after # as name
758 sal_Int32 nPos = aMap.indexOf( '#' );
759 OUString aName;
760 if ( -1 == nPos )
761 aName = aMap ;
762 else
763 aName = aMap.copy(nPos+1);
765 ImageMap *pImgMap = FindImageMap( aName );
766 if( pImgMap )
768 SwFormatURL aURL; aURL.SetMap( pImgMap );// is copied
770 bSetScaleImageMap = !nPercentWidth || !nPercentHeight;
771 aFrameSet.Put( aURL );
773 else
775 ImageMap aEmptyImgMap( aName );
776 SwFormatURL aURL; aURL.SetMap( &aEmptyImgMap );// is copied
777 aFrameSet.Put( aURL );
778 m_nMissingImgMaps++; // image maps are missing
780 // the graphic has to scaled during SetTwipSize, if we didn't
781 // set a size on the node or the size doesn't match the graphic size.
782 bSetScaleImageMap = true;
786 // observe minimum values !!
787 bool bRelSizeScale = bRelWidthScale || bRelHeightScale;
788 if( nPercentWidth )
790 OSL_ENSURE( !aTwipSz.Width() || bRelSizeScale,
791 "Why is a width set if we already have percentage value?" );
792 aTwipSz.setWidth( aGrfSz.Width() ? aGrfSz.Width()
793 : HTML_DFLT_IMG_WIDTH );
795 else
797 aTwipSz.AdjustWidth(2*nVBorderWidth );
798 if( aTwipSz.Width() < MINFLY )
799 aTwipSz.setWidth( MINFLY );
801 if( nPercentHeight )
803 OSL_ENSURE( !aTwipSz.Height() || bRelSizeScale,
804 "Why is a height set if we already have percentage value?" );
805 aTwipSz.setHeight( aGrfSz.Height() ? aGrfSz.Height()
806 : HTML_DFLT_IMG_HEIGHT );
808 else
810 aTwipSz.AdjustHeight(2*nHBorderWidth );
811 if( aTwipSz.Height() < MINFLY )
812 aTwipSz.setHeight( MINFLY );
815 SwFormatFrameSize aFrameSize( SwFrameSize::Fixed, aTwipSz.Width(), aTwipSz.Height() );
816 aFrameSize.SetWidthPercent( nPercentWidth );
817 aFrameSize.SetHeightPercent( nPercentHeight );
818 aFrameSet.Put( aFrameSize );
820 const SwNodeType eNodeType = m_pPam->GetPointNode().GetNodeType();
821 if (eNodeType != SwNodeType::Text && eNodeType != SwNodeType::Table)
822 return;
824 // passing empty sGrfNm here, means we don't want the graphic to be linked
825 SwFrameFormat *const pFlyFormat =
826 m_xDoc->getIDocumentContentOperations().InsertGraphic(
827 *m_pPam, sGrfNm, OUString(), &aGraphic,
828 &aFrameSet, nullptr, nullptr);
829 SwGrfNode *pGrfNd = m_xDoc->GetNodes()[ pFlyFormat->GetContent().GetContentIdx()
830 ->GetIndex()+1 ]->GetGrfNode();
832 if( !sHTMLGrfName.isEmpty() )
834 pFlyFormat->SetFormatName( sHTMLGrfName );
836 // maybe jump to graphic
837 if( JumpToMarks::Graphic == m_eJumpTo && sHTMLGrfName == m_sJmpMark )
839 m_bChkJumpMark = true;
840 m_eJumpTo = JumpToMarks::NONE;
844 if (pGrfNd)
846 if( !sAltNm.isEmpty() )
847 pGrfNd->SetTitle( sAltNm );
849 if( bSetTwipSize )
850 pGrfNd->SetTwipSize( aGrfSz );
852 pGrfNd->SetChgTwipSize( bChangeFrameSize );
854 if( bSetScaleImageMap )
855 pGrfNd->SetScaleImageMap( true );
858 if( m_xAttrTab->pINetFormat )
860 const SwFormatINetFormat &rINetFormat =
861 static_cast<const SwFormatINetFormat&>(m_xAttrTab->pINetFormat->GetItem());
863 SwFormatURL aURL( pFlyFormat->GetURL() );
865 aURL.SetURL( rINetFormat.GetValue(), bIsMap );
866 aURL.SetTargetFrameName( rINetFormat.GetTargetFrame() );
867 aURL.SetName( rINetFormat.GetName() );
868 pFlyFormat->SetFormatAttr( aURL );
871 static const SvMacroItemId aEvents[] = {
872 SvMacroItemId::OnMouseOver,
873 SvMacroItemId::OnClick,
874 SvMacroItemId::OnMouseOut };
876 for( SvMacroItemId id : aEvents )
878 const SvxMacro *pMacro = rINetFormat.GetMacro( id );
879 if( nullptr != pMacro )
880 aMacroItem.SetMacro( id, *pMacro );
884 if ((RndStdIds::FLY_AS_CHAR == pFlyFormat->GetAnchor().GetAnchorId()) &&
885 m_xAttrTab->pINetFormat->GetStartParagraph() ==
886 m_pPam->GetPoint()->GetNode() &&
887 m_xAttrTab->pINetFormat->GetStartContent() ==
888 m_pPam->GetPoint()->GetContentIndex() - 1 )
890 // the attribute was insert right before as-character anchored
891 // graphic, therefore we move it
892 m_xAttrTab->pINetFormat->SetStart( *m_pPam->GetPoint() );
894 // When the attribute is also an anchor, we'll insert
895 // a bookmark before the graphic, because SwFormatURL
896 // isn't an anchor.
897 if( !rINetFormat.GetName().isEmpty() )
899 m_pPam->Move( fnMoveBackward );
900 InsertBookmark( rINetFormat.GetName() );
901 m_pPam->Move( fnMoveForward );
906 else if (!m_aEmbedURL.isEmpty())
908 // This is an inner <object> image and the outer <object> has a URL for us. Set that on the
909 // image.
910 SwFormatURL aURL(pFlyFormat->GetURL());
911 aURL.SetURL(m_aEmbedURL, bIsMap);
912 m_aEmbedURL.clear();
913 pFlyFormat->SetFormatAttr(aURL);
916 if( !aMacroItem.GetMacroTable().empty() )
918 NotifyMacroEventRead();
919 pFlyFormat->SetFormatAttr( aMacroItem );
922 // tdf#87083 If the graphic has not been loaded yet, then load it now.
923 // Otherwise it may be loaded during the first paint of the object and it
924 // will be too late to adapt the size of the graphic at that point.
925 if (bRequestGrfNow && pGrfNd)
927 Size aUpdatedSize = pGrfNd->GetTwipSize(); //trigger a swap-in
928 SAL_WARN_IF(!aUpdatedSize.Width() || !aUpdatedSize.Height(), "sw.html", "html image with no width or height");
931 // maybe create frames and register auto bound frames
932 RegisterFlyFrame( pFlyFormat );
934 if( !aId.isEmpty() )
935 InsertBookmark( aId );
938 /* */
940 void SwHTMLParser::InsertBodyOptions()
942 m_xDoc->SetTextFormatColl( *m_pPam,
943 m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
945 OUString aBackGround, aId, aStyle, aLang, aDir;
946 Color aBGColor, aTextColor, aLinkColor, aVLinkColor;
947 bool bBGColor=false, bTextColor=false;
948 bool bLinkColor=false, bVLinkColor=false;
950 ScriptType eDfltScriptType;
951 OUString sDfltScriptType;
952 GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
954 const HTMLOptions& rHTMLOptions = GetOptions();
955 for (size_t i = rHTMLOptions.size(); i; )
957 const HTMLOption& rOption = rHTMLOptions[--i];
958 ScriptType eScriptType2 = eDfltScriptType;
959 OUString aEvent;
960 bool bSetEvent = false;
962 switch( rOption.GetToken() )
964 case HtmlOptionId::ID:
965 aId = rOption.GetString();
966 break;
967 case HtmlOptionId::BACKGROUND:
968 aBackGround = rOption.GetString();
969 break;
970 case HtmlOptionId::BGCOLOR:
971 rOption.GetColor( aBGColor );
972 bBGColor = true;
973 break;
974 case HtmlOptionId::TEXT:
975 rOption.GetColor( aTextColor );
976 bTextColor = true;
977 break;
978 case HtmlOptionId::LINK:
979 rOption.GetColor( aLinkColor );
980 bLinkColor = true;
981 break;
982 case HtmlOptionId::VLINK:
983 rOption.GetColor( aVLinkColor );
984 bVLinkColor = true;
985 break;
987 case HtmlOptionId::SDONLOAD:
988 eScriptType2 = STARBASIC;
989 [[fallthrough]];
990 case HtmlOptionId::ONLOAD:
991 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC );
992 bSetEvent = true;
993 break;
995 case HtmlOptionId::SDONUNLOAD:
996 eScriptType2 = STARBASIC;
997 [[fallthrough]];
998 case HtmlOptionId::ONUNLOAD:
999 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::PREPARECLOSEDOC );
1000 bSetEvent = true;
1001 break;
1003 case HtmlOptionId::SDONFOCUS:
1004 eScriptType2 = STARBASIC;
1005 [[fallthrough]];
1006 case HtmlOptionId::ONFOCUS:
1007 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC );
1008 bSetEvent = true;
1009 break;
1011 case HtmlOptionId::SDONBLUR:
1012 eScriptType2 = STARBASIC;
1013 [[fallthrough]];
1014 case HtmlOptionId::ONBLUR:
1015 aEvent = GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC );
1016 bSetEvent = true;
1017 break;
1019 case HtmlOptionId::ONERROR:
1020 break;
1022 case HtmlOptionId::STYLE:
1023 aStyle = rOption.GetString();
1024 bTextColor = true;
1025 break;
1026 case HtmlOptionId::LANG:
1027 aLang = rOption.GetString();
1028 break;
1029 case HtmlOptionId::DIR:
1030 aDir = rOption.GetString();
1031 break;
1032 default: break;
1035 if( bSetEvent )
1037 const OUString& rEvent = rOption.GetString();
1038 if( !rEvent.isEmpty() )
1039 InsertBasicDocEvent( aEvent, rEvent, eScriptType2,
1040 sDfltScriptType );
1044 if( bTextColor && !m_pCSS1Parser->IsBodyTextSet() )
1046 // The font colour is set in the default style
1047 m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD )
1048 ->SetFormatAttr( SvxColorItem(aTextColor, RES_CHRATR_COLOR) );
1049 m_pCSS1Parser->SetBodyTextSet();
1052 // Prepare the items for the page style (background, frame)
1053 // If BrushItem already set values must remain!
1054 std::unique_ptr<SvxBrushItem> aBrushItem( m_pCSS1Parser->makePageDescBackground() );
1055 bool bSetBrush = false;
1057 if( bBGColor && !m_pCSS1Parser->IsBodyBGColorSet() )
1059 // background colour from "BGCOLOR"
1060 OUString aLink;
1061 if( !aBrushItem->GetGraphicLink().isEmpty() )
1062 aLink = aBrushItem->GetGraphicLink();
1063 SvxGraphicPosition ePos = aBrushItem->GetGraphicPos();
1065 aBrushItem->SetColor( aBGColor );
1067 if( !aLink.isEmpty() )
1069 aBrushItem->SetGraphicLink( aLink );
1070 aBrushItem->SetGraphicPos( ePos );
1072 bSetBrush = true;
1073 m_pCSS1Parser->SetBodyBGColorSet();
1076 if( !aBackGround.isEmpty() && !m_pCSS1Parser->IsBodyBackgroundSet() )
1078 // background graphic from "BACKGROUND"
1079 aBrushItem->SetGraphicLink( INetURLObject::GetAbsURL( m_sBaseURL, aBackGround ) );
1080 aBrushItem->SetGraphicPos( GPOS_TILED );
1081 bSetBrush = true;
1082 m_pCSS1Parser->SetBodyBackgroundSet();
1085 if( !aStyle.isEmpty() || !aDir.isEmpty() )
1087 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
1088 SvxCSS1PropertyInfo aPropInfo;
1089 OUString aDummy;
1090 ParseStyleOptions( aStyle, aDummy, aDummy, aItemSet, aPropInfo, nullptr, &aDir );
1092 // Some attributes have to set on the page style, in fact the ones
1093 // which aren't inherited
1094 m_pCSS1Parser->SetPageDescAttrs( bSetBrush ? aBrushItem.get() : nullptr,
1095 &aItemSet );
1097 static const TypedWhichId<SvxFontHeightItem> aWhichIds[3] = { RES_CHRATR_FONTSIZE,
1098 RES_CHRATR_CJK_FONTSIZE,
1099 RES_CHRATR_CTL_FONTSIZE };
1100 for(auto const & i : aWhichIds)
1102 const SvxFontHeightItem *pItem = aItemSet.GetItemIfSet( i, false );
1103 if( pItem && pItem->GetProp() != 100)
1105 sal_uInt32 nHeight =
1106 ( m_aFontHeights[2] * pItem->GetProp() ) / 100;
1107 SvxFontHeightItem aNewItem( nHeight, 100, i );
1108 aItemSet.Put( aNewItem );
1112 // all remaining options can be set on the default style
1113 m_pCSS1Parser->GetTextCollFromPool( RES_POOLCOLL_STANDARD )
1114 ->SetFormatAttr( aItemSet );
1116 else if( bSetBrush )
1118 m_pCSS1Parser->SetPageDescAttrs( aBrushItem.get() );
1121 if( bLinkColor && !m_pCSS1Parser->IsBodyLinkSet() )
1123 SwCharFormat *pCharFormat =
1124 m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_INET_NORMAL);
1125 pCharFormat->SetFormatAttr( SvxColorItem(aLinkColor, RES_CHRATR_COLOR) );
1126 m_pCSS1Parser->SetBodyLinkSet();
1128 if( bVLinkColor && !m_pCSS1Parser->IsBodyVLinkSet() )
1130 SwCharFormat *pCharFormat =
1131 m_pCSS1Parser->GetCharFormatFromPool(RES_POOLCHR_INET_VISIT);
1132 pCharFormat->SetFormatAttr( SvxColorItem(aVLinkColor, RES_CHRATR_COLOR) );
1133 m_pCSS1Parser->SetBodyVLinkSet();
1135 if( !aLang.isEmpty() )
1137 LanguageType eLang = LanguageTag::convertToLanguageTypeWithFallback( aLang );
1138 if( LANGUAGE_DONTKNOW != eLang )
1140 sal_uInt16 nWhich = 0;
1141 switch( SvtLanguageOptions::GetScriptTypeOfLanguage( eLang ) )
1143 case SvtScriptType::LATIN:
1144 nWhich = RES_CHRATR_LANGUAGE;
1145 break;
1146 case SvtScriptType::ASIAN:
1147 nWhich = RES_CHRATR_CJK_LANGUAGE;
1148 break;
1149 case SvtScriptType::COMPLEX:
1150 nWhich = RES_CHRATR_CTL_LANGUAGE;
1151 break;
1152 default: break;
1154 if( nWhich )
1156 SvxLanguageItem aLanguage( eLang, nWhich );
1157 aLanguage.SetWhich( nWhich );
1158 m_xDoc->SetDefault( aLanguage );
1163 if( !aId.isEmpty() )
1164 InsertBookmark( aId );
1167 /* */
1169 void SwHTMLParser::NewAnchor()
1171 // end previous link if there was one
1172 std::unique_ptr<HTMLAttrContext> xOldCntxt(PopContext(HtmlTokenId::ANCHOR_ON));
1173 if (xOldCntxt)
1175 // and maybe end attributes
1176 EndContext(xOldCntxt.get());
1179 SvxMacroTableDtor aMacroTable;
1180 OUString sHRef, aName, sTarget;
1181 OUString aId, aStyle, aClass, aLang, aDir;
1182 bool bHasHRef = false, bFixed = false;
1184 ScriptType eDfltScriptType;
1185 OUString sDfltScriptType;
1186 GetDefaultScriptType( eDfltScriptType, sDfltScriptType );
1188 const HTMLOptions& rHTMLOptions = GetOptions();
1189 for (size_t i = rHTMLOptions.size(); i; )
1191 SvMacroItemId nEvent = SvMacroItemId::NONE;
1192 ScriptType eScriptType2 = eDfltScriptType;
1193 const HTMLOption& rOption = rHTMLOptions[--i];
1194 switch( rOption.GetToken() )
1196 case HtmlOptionId::NAME:
1197 aName = rOption.GetString();
1198 break;
1200 case HtmlOptionId::HREF:
1201 sHRef = rOption.GetString();
1202 bHasHRef = true;
1203 break;
1204 case HtmlOptionId::TARGET:
1205 sTarget = rOption.GetString();
1206 break;
1208 case HtmlOptionId::STYLE:
1209 aStyle = rOption.GetString();
1210 break;
1211 case HtmlOptionId::ID:
1212 aId = rOption.GetString();
1213 break;
1214 case HtmlOptionId::CLASS:
1215 aClass = rOption.GetString();
1216 break;
1217 case HtmlOptionId::SDFIXED:
1218 bFixed = true;
1219 break;
1220 case HtmlOptionId::LANG:
1221 aLang = rOption.GetString();
1222 break;
1223 case HtmlOptionId::DIR:
1224 aDir = rOption.GetString();
1225 break;
1227 case HtmlOptionId::SDONCLICK:
1228 eScriptType2 = STARBASIC;
1229 [[fallthrough]];
1230 case HtmlOptionId::ONCLICK:
1231 nEvent = SvMacroItemId::OnClick;
1232 goto ANCHOR_SETEVENT;
1234 case HtmlOptionId::SDONMOUSEOVER:
1235 eScriptType2 = STARBASIC;
1236 [[fallthrough]];
1237 case HtmlOptionId::ONMOUSEOVER:
1238 nEvent = SvMacroItemId::OnMouseOver;
1239 goto ANCHOR_SETEVENT;
1241 case HtmlOptionId::SDONMOUSEOUT:
1242 eScriptType2 = STARBASIC;
1243 [[fallthrough]];
1244 case HtmlOptionId::ONMOUSEOUT:
1245 nEvent = SvMacroItemId::OnMouseOut;
1246 goto ANCHOR_SETEVENT;
1247 ANCHOR_SETEVENT:
1249 OUString sTmp( rOption.GetString() );
1250 if( !sTmp.isEmpty() )
1252 sTmp = convertLineEnd(sTmp, GetSystemLineEnd());
1253 OUString sScriptType;
1254 if( EXTENDED_STYPE == eScriptType2 )
1255 sScriptType = sDfltScriptType;
1256 aMacroTable.Insert( nEvent, SvxMacro( sTmp, sScriptType, eScriptType2 ));
1259 break;
1260 default: break;
1264 // Jump targets, which match our implicit targets,
1265 // here we throw out rigorously.
1266 if( !aName.isEmpty() )
1268 OUString sDecoded( INetURLObject::decode( aName,
1269 INetURLObject::DecodeMechanism::Unambiguous ));
1270 sal_Int32 nPos = sDecoded.lastIndexOf( cMarkSeparator );
1271 if( nPos != -1 )
1273 OUString sCmp= sDecoded.copy(nPos+1).replaceAll(" ","");
1274 if( !sCmp.isEmpty() )
1276 sCmp = sCmp.toAsciiLowerCase();
1277 if( sCmp == "region" ||
1278 sCmp == "frame" ||
1279 sCmp == "graphic" ||
1280 sCmp == "ole" ||
1281 sCmp == "table" ||
1282 sCmp == "outline" ||
1283 sCmp == "text" )
1285 aName.clear();
1291 // create a new context
1292 std::unique_ptr<HTMLAttrContext> xCntxt(new HTMLAttrContext(HtmlTokenId::ANCHOR_ON));
1294 bool bEnAnchor = false, bFootnoteAnchor = false, bFootnoteEnSymbol = false;
1295 OUString aFootnoteName;
1296 OUString aStrippedClass( aClass );
1297 SwCSS1Parser::GetScriptFromClass( aStrippedClass, false );
1298 if( aStrippedClass.getLength() >=9 && bHasHRef && sHRef.getLength() > 1 &&
1299 ('s' == aStrippedClass[0] || 'S' == aStrippedClass[0]) &&
1300 ('d' == aStrippedClass[1] || 'D' == aStrippedClass[1]) )
1302 if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote_anc ) )
1303 bEnAnchor = true;
1304 else if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote_anc ) )
1305 bFootnoteAnchor = true;
1306 else if( aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdendnote_sym ) ||
1307 aStrippedClass.equalsIgnoreAsciiCase( OOO_STRING_SVTOOLS_HTML_sdfootnote_sym ) )
1308 bFootnoteEnSymbol = true;
1309 if( bEnAnchor || bFootnoteAnchor || bFootnoteEnSymbol )
1311 aFootnoteName = sHRef.copy( 1 );
1312 aClass.clear();
1313 aStrippedClass.clear();
1314 aName.clear();
1315 bHasHRef = false;
1319 // Styles parsen
1320 if( HasStyleOptions( aStyle, aId, aStrippedClass, &aLang, &aDir ) )
1322 SfxItemSet aItemSet( m_xDoc->GetAttrPool(), m_pCSS1Parser->GetWhichMap() );
1323 SvxCSS1PropertyInfo aPropInfo;
1325 if( ParseStyleOptions( aStyle, aId, aClass, aItemSet, aPropInfo, &aLang, &aDir ) )
1327 DoPositioning(aItemSet, aPropInfo, xCntxt.get());
1328 InsertAttrs(aItemSet, aPropInfo, xCntxt.get(), true);
1332 if( bHasHRef )
1334 if( !sHRef.isEmpty() )
1336 sHRef = URIHelper::SmartRel2Abs( INetURLObject(m_sBaseURL), sHRef, Link<OUString *, bool>(), false );
1338 else
1340 // use directory if empty URL
1341 INetURLObject aURLObj( m_aPathToFile );
1342 sHRef = aURLObj.GetPartBeforeLastName();
1345 m_pCSS1Parser->SetATagStyles();
1346 SwFormatINetFormat aINetFormat( sHRef, sTarget );
1347 aINetFormat.SetName( aName );
1349 if( !aMacroTable.empty() )
1351 NotifyMacroEventRead();
1352 aINetFormat.SetMacroTable( &aMacroTable );
1355 // set the default attribute
1356 InsertAttr(&m_xAttrTab->pINetFormat, aINetFormat, xCntxt.get());
1358 else if( !aName.isEmpty() )
1360 InsertBookmark( aName );
1363 if( bEnAnchor || bFootnoteAnchor )
1365 InsertFootEndNote( aFootnoteName, bEnAnchor, bFixed );
1366 m_bInFootEndNoteAnchor = m_bCallNextToken = true;
1368 else if( bFootnoteEnSymbol )
1370 m_bInFootEndNoteSymbol = m_bCallNextToken = true;
1373 // save context
1374 PushContext(xCntxt);
1377 void SwHTMLParser::EndAnchor()
1379 if( m_bInFootEndNoteAnchor )
1381 FinishFootEndNote();
1382 m_bInFootEndNoteAnchor = false;
1384 else if( m_bInFootEndNoteSymbol )
1386 m_bInFootEndNoteSymbol = false;
1389 EndTag( HtmlTokenId::ANCHOR_OFF );
1392 /* */
1394 void SwHTMLParser::InsertBookmark( const OUString& rName )
1396 HTMLAttr* pTmp = new HTMLAttr( *m_pPam->GetPoint(),
1397 SfxStringItem(RES_FLTR_BOOKMARK, rName), nullptr, std::shared_ptr<HTMLAttrTable>());
1398 m_aSetAttrTab.push_back( pTmp );
1401 bool SwHTMLParser::HasCurrentParaBookmarks( bool bIgnoreStack ) const
1403 bool bHasMarks = false;
1404 SwNodeOffset nNodeIdx = m_pPam->GetPoint()->GetNodeIndex();
1406 // first step: are there still bookmark in the attribute-stack?
1407 // bookmarks are added to the end of the stack - thus we only have
1408 // to check the last bookmark
1409 if( !bIgnoreStack )
1411 for( auto i = m_aSetAttrTab.size(); i; )
1413 HTMLAttr* pAttr = m_aSetAttrTab[ --i ];
1414 if( RES_FLTR_BOOKMARK == pAttr->m_pItem->Which() )
1416 if( pAttr->GetStartParagraphIdx() == nNodeIdx )
1417 bHasMarks = true;
1418 break;
1423 if( !bHasMarks )
1425 // second step: when we didn't find a bookmark, check if there is one set already
1426 IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
1427 for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
1428 ppMark != pMarkAccess->getAllMarksEnd();
1429 ++ppMark)
1431 const ::sw::mark::IMark* pBookmark = *ppMark;
1433 const SwNodeOffset nBookNdIdx = pBookmark->GetMarkPos().GetNodeIndex();
1434 if( nBookNdIdx==nNodeIdx )
1436 bHasMarks = true;
1437 break;
1439 else if( nBookNdIdx > nNodeIdx )
1440 break;
1444 return bHasMarks;
1447 /* */
1449 void SwHTMLParser::StripTrailingPara()
1451 bool bSetSmallFont = false;
1453 SwContentNode* pCNd = m_pPam->GetPointContentNode();
1454 SwNodeOffset nNodeIdx = m_pPam->GetPoint()->GetNodeIndex();
1455 if( !m_pPam->GetPoint()->GetContentIndex() )
1457 if( pCNd && pCNd->StartOfSectionIndex() + 2 <
1458 pCNd->EndOfSectionIndex() && CanRemoveNode(nNodeIdx))
1461 for(sw::SpzFrameFormat* pSpz: *m_xDoc->GetSpzFrameFormats())
1463 SwFormatAnchor const*const pAnchor = &pSpz->GetAnchor();
1464 SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
1465 if (pAnchorNode &&
1466 ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
1467 (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
1468 pAnchorNode->GetIndex() == nNodeIdx )
1470 return; // we can't delete the node
1473 SetAttr( false ); // the still open attributes must be
1474 // closed before the node is deleted,
1475 // otherwise the last index is dangling
1477 if( pCNd->Len() && pCNd->IsTextNode() )
1479 // fields were inserted into the node, now they have
1480 // to be moved
1481 SwTextNode *pPrvNd = m_xDoc->GetNodes()[nNodeIdx-1]->GetTextNode();
1482 if( pPrvNd )
1484 SwContentIndex aSrc( pCNd, 0 );
1485 pCNd->GetTextNode()->CutText( pPrvNd, aSrc, pCNd->Len() );
1489 // now we have to move maybe existing bookmarks
1490 IDocumentMarkAccess* const pMarkAccess = m_xDoc->getIDocumentMarkAccess();
1491 for(IDocumentMarkAccess::const_iterator_t ppMark = pMarkAccess->getAllMarksBegin();
1492 ppMark != pMarkAccess->getAllMarksEnd();
1493 ++ppMark)
1495 ::sw::mark::IMark* pMark = *ppMark;
1497 SwNodeOffset nBookNdIdx = pMark->GetMarkPos().GetNodeIndex();
1498 if(nBookNdIdx==nNodeIdx)
1500 SwNodeIndex nNewNdIdx(m_pPam->GetPoint()->GetNode());
1501 SwContentNode* pNd = SwNodes::GoPrevious(&nNewNdIdx);
1502 if(!pNd)
1504 OSL_ENSURE(false, "Oops, where is my predecessor node?");
1505 return;
1507 // #i81002# - refactoring
1508 // Do not directly manipulate member of <SwBookmark>
1510 const SwPaM aPaM(*pNd, pNd->Len());
1511 pMarkAccess->repositionMark(*ppMark, aPaM);
1514 else if( nBookNdIdx > nNodeIdx )
1515 break;
1518 SwNode& rDelNode = m_pPam->GetPoint()->GetNode();
1519 m_pPam->Move( fnMoveBackward, GoInNode );
1520 m_pPam->SetMark();
1521 m_pPam->DeleteMark();
1522 m_xDoc->GetNodes().Delete( rDelNode );
1524 else if (pCNd && pCNd->IsTextNode() && m_xTable)
1526 // In empty cells we set a small font, so that the cell doesn't
1527 // get higher than the graphic resp. as low as possible.
1528 bSetSmallFont = true;
1531 else if( pCNd && pCNd->IsTextNode() && m_xTable &&
1532 pCNd->StartOfSectionIndex()+2 ==
1533 pCNd->EndOfSectionIndex() )
1535 // When the cell contains only as-character anchored graphics/frames,
1536 // then we also set a small font.
1537 bSetSmallFont = true;
1538 SwTextNode* pTextNd = pCNd->GetTextNode();
1540 sal_Int32 nPos = m_pPam->GetPoint()->GetContentIndex();
1541 while( bSetSmallFont && nPos>0 )
1543 --nPos;
1544 bSetSmallFont =
1545 (CH_TXTATR_BREAKWORD == pTextNd->GetText()[nPos]) &&
1546 (nullptr != pTextNd->GetTextAttrForCharAt( nPos, RES_TXTATR_FLYCNT ));
1550 if( bSetSmallFont )
1552 // Added default to CJK and CTL
1553 SvxFontHeightItem aFontHeight( 40, 100, RES_CHRATR_FONTSIZE );
1554 pCNd->SetAttr( aFontHeight );
1555 SvxFontHeightItem aFontHeightCJK( 40, 100, RES_CHRATR_CJK_FONTSIZE );
1556 pCNd->SetAttr( aFontHeightCJK );
1557 SvxFontHeightItem aFontHeightCTL( 40, 100, RES_CHRATR_CTL_FONTSIZE );
1558 pCNd->SetAttr( aFontHeightCTL );
1562 void SwHTMLParser::NotifyMacroEventRead()
1564 if (m_bNotifyMacroEventRead)
1565 return;
1566 SwDocShell *pDocSh = m_xDoc->GetDocShell();
1567 if (!pDocSh)
1568 return;
1569 uno::Reference<frame::XModel> const xModel(pDocSh->GetBaseModel());
1570 comphelper::DocumentInfo::notifyMacroEventRead(xModel);
1571 m_bNotifyMacroEventRead = true;
1574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */