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