crashtesting: assert on reimport of docx export of ooo102874-2.doc
[LibreOffice.git] / sw / source / filter / html / htmlcss1.cxx
blob3b8702641be88373ea868a8a65d48dee0a568ccd
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 <hintids.hxx>
21 #include <svl/itemiter.hxx>
22 #include <svl/urihelper.hxx>
23 #include <i18nlangtag/languagetag.hxx>
24 #include <sfx2/docfile.hxx>
25 #include <editeng/editids.hrc>
26 #include <editeng/fhgtitem.hxx>
27 #include <editeng/brushitem.hxx>
28 #include <editeng/lrspitem.hxx>
29 #include <editeng/ulspitem.hxx>
30 #include <editeng/boxitem.hxx>
31 #include <editeng/flstitem.hxx>
32 #include <editeng/formatbreakitem.hxx>
33 #include <editeng/keepitem.hxx>
34 #include <editeng/fontitem.hxx>
35 #include <editeng/langitem.hxx>
36 #include <editeng/frmdiritem.hxx>
37 #include <o3tl/string_view.hxx>
38 #include <svtools/htmltokn.h>
39 #include <svtools/htmlkywd.hxx>
40 #include <fmtpdsc.hxx>
41 #include <fmtanchr.hxx>
42 #include <fmtornt.hxx>
43 #include <fmtsrnd.hxx>
44 #include <fmtfsize.hxx>
45 #include <frmatr.hxx>
46 #include <charfmt.hxx>
47 #include <docary.hxx>
48 #include <osl/diagnose.h>
50 #include <doc.hxx>
51 #include <IDocumentStylePoolAccess.hxx>
52 #include <pam.hxx>
53 #include <poolfmt.hxx>
54 #include <docsh.hxx>
55 #include <paratr.hxx>
56 #include <pagedesc.hxx>
57 #include "css1kywd.hxx"
58 #include "swcss1.hxx"
59 #include "htmlnum.hxx"
60 #include "swhtml.hxx"
61 #include <numrule.hxx>
62 #include "css1atr.hxx"
64 using namespace ::com::sun::star;
66 // How many rows/characters are allowed for DropCaps?
67 // (Are there maybe somewhere else corresponding values?)
68 #define MAX_DROPCAP_LINES 9
69 #define MAX_DROPCAP_CHARS 9
71 static void lcl_swcss1_setEncoding( SwFormat& rFormat, rtl_TextEncoding eEnc );
73 // Implementation of SwCSS1Parsers (actually swcss1.cxx)
74 const sal_uInt16 aItemIds[] =
76 RES_BREAK,
77 RES_PAGEDESC,
78 RES_KEEP,
81 void SwCSS1Parser::ChgPageDesc( const SwPageDesc *pPageDesc,
82 const SwPageDesc& rNewPageDesc )
84 size_t pos;
85 bool found = m_pDoc->ContainsPageDesc( pPageDesc, &pos );
86 OSL_ENSURE( found, "style not found" );
87 if (found)
88 m_pDoc->ChgPageDesc( pos, rNewPageDesc );
91 SwCSS1Parser::SwCSS1Parser(SwDoc *const pDoc, SwHTMLParser const& rParser,
92 const sal_uInt32 aFHeights[7], const OUString& rBaseURL, bool const bNewDoc)
93 : SvxCSS1Parser(pDoc->GetAttrPool(), rBaseURL,
94 aItemIds, SAL_N_ELEMENTS(aItemIds))
95 , m_pDoc( pDoc )
96 , m_rHTMLParser(rParser)
97 , m_nDropCapCnt( 0 ),
98 m_bIsNewDoc( bNewDoc ),
99 m_bBodyBGColorSet( false ),
100 m_bBodyBackgroundSet( false ),
101 m_bBodyTextSet( false ),
102 m_bBodyLinkSet( false ),
103 m_bBodyVLinkSet( false ),
104 m_bSetFirstPageDesc( false ),
105 m_bSetRightPageDesc( false ),
106 m_bTableHeaderTextCollSet( false ),
107 m_bTableTextCollSet( false ),
108 m_bLinkCharFormatsSet( false )
110 m_aFontHeights[0] = aFHeights[0];
111 m_aFontHeights[1] = aFHeights[1];
112 m_aFontHeights[2] = aFHeights[2];
113 m_aFontHeights[3] = aFHeights[3];
114 m_aFontHeights[4] = aFHeights[4];
115 m_aFontHeights[5] = aFHeights[5];
116 m_aFontHeights[6] = aFHeights[6];
119 SwCSS1Parser::~SwCSS1Parser()
123 // Feature: PrintExt
124 bool SwCSS1Parser::SetFormatBreak( SfxItemSet& rItemSet,
125 const SvxCSS1PropertyInfo& rPropInfo )
127 SvxBreak eBreak = SvxBreak::NONE;
128 bool bKeep = false;
129 bool bSetKeep = false, bSetBreak = false, bSetPageDesc = false;
130 const SwPageDesc *pPageDesc = nullptr;
131 switch( rPropInfo.m_ePageBreakBefore )
133 case SVX_CSS1_PBREAK_ALWAYS:
134 eBreak = SvxBreak::PageBefore;
135 bSetBreak = true;
136 break;
137 case SVX_CSS1_PBREAK_LEFT:
138 pPageDesc = GetLeftPageDesc( true );
139 bSetPageDesc = true;
140 break;
141 case SVX_CSS1_PBREAK_RIGHT:
142 pPageDesc = GetRightPageDesc( true );
143 bSetPageDesc = true;
144 break;
145 case SVX_CSS1_PBREAK_AUTO:
146 bSetBreak = bSetPageDesc = true;
147 break;
148 default:
151 switch( rPropInfo.m_ePageBreakAfter )
153 case SVX_CSS1_PBREAK_ALWAYS:
154 case SVX_CSS1_PBREAK_LEFT:
155 case SVX_CSS1_PBREAK_RIGHT:
156 // LEFT/RIGHT also could be set in the previous paragraph
157 eBreak = SvxBreak::PageAfter;
158 bSetBreak = true;
159 break;
160 case SVX_CSS1_PBREAK_AUTO:
161 bSetBreak = bSetKeep = bSetPageDesc = true;
162 break;
163 case SVX_CSS1_PBREAK_AVOID:
164 bKeep = bSetKeep = true;
165 break;
166 default:
170 if( bSetBreak )
171 rItemSet.Put( SvxFormatBreakItem( eBreak, RES_BREAK ) );
172 if( bSetPageDesc )
173 rItemSet.Put( SwFormatPageDesc( pPageDesc ) );
174 if( bSetKeep )
175 rItemSet.Put( SvxFormatKeepItem( bKeep, RES_KEEP ) );
177 return bSetBreak;
180 static void SetCharFormatAttrs( SwCharFormat *pCharFormat, SfxItemSet& rItemSet )
182 static const TypedWhichId<SvxFontHeightItem> aWhichIds[3] = { RES_CHRATR_FONTSIZE,RES_CHRATR_CJK_FONTSIZE,
183 RES_CHRATR_CTL_FONTSIZE };
184 for(auto const & i : aWhichIds)
186 const SvxFontHeightItem* pItem = rItemSet.GetItemIfSet( i, false );
187 if( pItem && pItem->GetProp() != 100)
189 // percentage values at the FontHeight item aren't supported
190 rItemSet.ClearItem( i );
194 pCharFormat->SetFormatAttr( rItemSet );
196 if( const SvxBrushItem* pItem = rItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
198 // A Brush-Item with RES_BACKGROUND must be converted to one
199 // with RES_CHRATR_BACKGROUND
201 SvxBrushItem aBrushItem( *pItem );
202 aBrushItem.SetWhich( RES_CHRATR_BACKGROUND );
203 pCharFormat->SetFormatAttr( aBrushItem );
206 if( const SvxBoxItem* pItem = rItemSet.GetItemIfSet( RES_BOX, false ) )
208 SvxBoxItem aBoxItem( *pItem );
209 aBoxItem.SetWhich( RES_CHRATR_BOX );
210 pCharFormat->SetFormatAttr( aBoxItem );
214 void SwCSS1Parser::SetLinkCharFormats()
216 OSL_ENSURE( !m_bLinkCharFormatsSet, "Call SetLinkCharFormats unnecessary" );
218 SvxCSS1MapEntry *pStyleEntry =
219 GetTag( u"" OOO_STRING_SVTOOLS_HTML_anchor ""_ustr );
220 SwCharFormat *pUnvisited = nullptr, *pVisited = nullptr;
221 if( pStyleEntry )
223 SfxItemSet& rItemSet = pStyleEntry->GetItemSet();
224 bool bColorSet = (SfxItemState::SET==rItemSet.GetItemState(RES_CHRATR_COLOR,
225 false));
226 pUnvisited = GetCharFormatFromPool( RES_POOLCHR_INET_NORMAL );
227 SetCharFormatAttrs( pUnvisited, rItemSet );
228 m_bBodyLinkSet |= bColorSet;
230 pVisited = GetCharFormatFromPool( RES_POOLCHR_INET_VISIT );
231 SetCharFormatAttrs( pVisited, rItemSet );
232 m_bBodyVLinkSet |= bColorSet;
235 OUString sTmp = u"" OOO_STRING_SVTOOLS_HTML_anchor ":link"_ustr;
237 pStyleEntry = GetTag( sTmp );
238 if( pStyleEntry )
240 SfxItemSet& rItemSet = pStyleEntry->GetItemSet();
241 bool bColorSet = (SfxItemState::SET==rItemSet.GetItemState(RES_CHRATR_COLOR,
242 false));
243 if( !pUnvisited )
244 pUnvisited = GetCharFormatFromPool( RES_POOLCHR_INET_NORMAL );
245 SetCharFormatAttrs( pUnvisited, rItemSet );
246 m_bBodyLinkSet |= bColorSet;
249 sTmp = OOO_STRING_SVTOOLS_HTML_anchor ":visited";
251 pStyleEntry = GetTag( sTmp );
252 if( pStyleEntry )
254 SfxItemSet& rItemSet = pStyleEntry->GetItemSet();
255 bool bColorSet = (SfxItemState::SET==rItemSet.GetItemState(RES_CHRATR_COLOR,
256 false));
257 if( !pVisited )
258 pVisited = GetCharFormatFromPool( RES_POOLCHR_INET_VISIT );
259 SetCharFormatAttrs( pVisited, rItemSet );
260 m_bBodyVLinkSet |= bColorSet;
263 m_bLinkCharFormatsSet = true;
266 static void SetTextCollAttrs( SwTextFormatColl *pColl, SfxItemSet& rItemSet,
267 SvxCSS1PropertyInfo const & rPropInfo,
268 SwCSS1Parser *pCSS1Parser )
270 const SfxItemSet& rCollItemSet = pColl->GetAttrSet();
272 // note: there was some SvxLRSpaceItem code here that was nonobvious
273 // but it looks like the only cases in which it would be required
274 // with split items are if some nProp != 100 or if SetAutoFirst() had
275 // been called (on the pColl items) but it looks like none of these are
276 // possible in HTML import.
278 // top and bottom border
279 const SvxULSpaceItem* pCollULItem;
280 const SvxULSpaceItem* pULItem;
281 if( (rPropInfo.m_bTopMargin || rPropInfo.m_bBottomMargin) &&
282 (!rPropInfo.m_bTopMargin || !rPropInfo.m_bBottomMargin) &&
283 (pCollULItem = rCollItemSet.GetItemIfSet(RES_UL_SPACE)) &&
284 (pULItem = rItemSet.GetItemIfSet(RES_UL_SPACE,false)) )
286 SvxULSpaceItem aULItem( *pCollULItem );
287 if( rPropInfo.m_bTopMargin )
288 aULItem.SetUpper( pULItem->GetUpper() );
289 if( rPropInfo.m_bBottomMargin )
290 aULItem.SetLower( pULItem->GetLower() );
292 rItemSet.Put( aULItem );
295 static const TypedWhichId<SvxFontHeightItem> aWhichIds[3] = { RES_CHRATR_FONTSIZE,RES_CHRATR_CJK_FONTSIZE,
296 RES_CHRATR_CTL_FONTSIZE };
297 for(auto const & i : aWhichIds)
299 const SvxFontHeightItem* pItem = rItemSet.GetItemIfSet( i, false );
300 if( pItem && pItem->GetProp() != 100)
302 // percentage values at the FontHeight item aren't supported
303 rItemSet.ClearItem( i );
307 pCSS1Parser->SetFormatBreak( rItemSet, rPropInfo );
309 pColl->SetFormatAttr( rItemSet );
312 void SwCSS1Parser::SetTableTextColl( bool bHeader )
314 OSL_ENSURE( !(bHeader ? m_bTableHeaderTextCollSet : m_bTableTextCollSet),
315 "Call SetTableTextColl unnecessary" );
317 sal_uInt16 nPoolId;
318 OUString sTag;
319 if( bHeader )
321 nPoolId = RES_POOLCOLL_TABLE_HDLN;
322 sTag = OOO_STRING_SVTOOLS_HTML_tableheader;
324 else
326 nPoolId = RES_POOLCOLL_TABLE;
327 sTag = OOO_STRING_SVTOOLS_HTML_tabledata;
330 SwTextFormatColl *pColl = nullptr;
332 // The following entries will never be used again and may be changed.
333 SvxCSS1MapEntry *pStyleEntry = GetTag( sTag );
334 if( pStyleEntry )
336 pColl = GetTextFormatColl(nPoolId, OUString());
337 SetTextCollAttrs( pColl, pStyleEntry->GetItemSet(),
338 pStyleEntry->GetPropertyInfo(), this );
341 OUString sTmp = sTag + " " OOO_STRING_SVTOOLS_HTML_parabreak;
342 pStyleEntry = GetTag( sTmp );
343 if( pStyleEntry )
345 if( !pColl )
346 pColl = GetTextFormatColl(nPoolId, OUString());
347 SetTextCollAttrs( pColl, pStyleEntry->GetItemSet(),
348 pStyleEntry->GetPropertyInfo(), this );
351 if( bHeader )
352 m_bTableHeaderTextCollSet = true;
353 else
354 m_bTableTextCollSet = true;
357 void SwCSS1Parser::SetPageDescAttrs( const SvxBrushItem *pBrush,
358 SfxItemSet *pItemSet2 )
360 std::shared_ptr<SvxBrushItem> aBrushItem(std::make_shared<SvxBrushItem>(RES_BACKGROUND));
361 std::shared_ptr<SvxBoxItem> aBoxItem(std::make_shared<SvxBoxItem>(RES_BOX));
362 std::shared_ptr<SvxFrameDirectionItem> aFrameDirItem(std::make_shared<SvxFrameDirectionItem>(SvxFrameDirection::Environment, RES_FRAMEDIR));
363 bool bSetBrush = pBrush!=nullptr, bSetBox = false, bSetFrameDir = false;
364 if( pBrush )
365 aBrushItem.reset(pBrush->Clone());
367 if( pItemSet2 )
369 if( const SvxBrushItem* pItem = pItemSet2->GetItemIfSet( RES_BACKGROUND, false ) )
371 // set a background
372 aBrushItem.reset(pItem->Clone());
373 pItemSet2->ClearItem( RES_BACKGROUND );
374 bSetBrush = true;
377 if( const SvxBoxItem* pItem = pItemSet2->GetItemIfSet( RES_BOX, false ) )
379 // set a border
380 aBoxItem.reset(pItem->Clone());
381 pItemSet2->ClearItem( RES_BOX );
382 bSetBox = true;
385 if( const SvxFrameDirectionItem* pItem = pItemSet2->GetItemIfSet( RES_FRAMEDIR, false ) )
387 // set a frame
388 aFrameDirItem.reset(pItem->Clone());
389 pItemSet2->ClearItem( RES_FRAMEDIR );
390 bSetFrameDir = true;
394 if( !(bSetBrush || bSetBox || bSetFrameDir) )
395 return;
397 static sal_uInt16 aPoolIds[] = { RES_POOLPAGE_HTML, RES_POOLPAGE_FIRST,
398 RES_POOLPAGE_LEFT, RES_POOLPAGE_RIGHT };
399 for(sal_uInt16 i : aPoolIds)
401 const SwPageDesc *pPageDesc = GetPageDesc( i, false );
402 if( pPageDesc )
404 SwPageDesc aNewPageDesc( *pPageDesc );
405 SwFrameFormat &rMaster = aNewPageDesc.GetMaster();
406 if( bSetBrush )
407 rMaster.SetFormatAttr( *aBrushItem );
408 if( bSetBox )
409 rMaster.SetFormatAttr( *aBoxItem );
410 if( bSetFrameDir )
411 rMaster.SetFormatAttr( *aFrameDirItem );
413 ChgPageDesc( pPageDesc, aNewPageDesc );
418 // Feature: PrintExt
419 void SwCSS1Parser::SetPageDescAttrs( const SwPageDesc *pPageDesc,
420 SfxItemSet& rItemSet,
421 const SvxCSS1PropertyInfo& rPropInfo )
423 if( !pPageDesc )
424 return;
426 SwPageDesc aNewPageDesc( *pPageDesc );
427 SwFrameFormat &rMaster = aNewPageDesc.GetMaster();
428 const SfxItemSet& rPageItemSet = rMaster.GetAttrSet();
429 bool bChanged = false;
431 // left, right border and first line indentation
432 ::std::optional<SvxLRSpaceItem> oLRSpace;
433 assert(!rItemSet.GetItemIfSet(RES_LR_SPACE,false));
434 if (rPropInfo.m_bLeftMargin)
436 // note: parser never creates SvxLeftMarginItem! must be converted
437 if (SvxTextLeftMarginItem const*const pLeft = rItemSet.GetItemIfSet(RES_MARGIN_TEXTLEFT, false))
439 if (!oLRSpace)
441 if (const SvxLRSpaceItem* pPageItem = rPageItemSet.GetItemIfSet(RES_LR_SPACE))
443 oLRSpace.emplace(*pPageItem);
445 else
447 oLRSpace.emplace(RES_LR_SPACE);
450 oLRSpace->SetLeft(pLeft->GetTextLeft());
453 if (rPropInfo.m_bRightMargin)
455 // note: parser never creates SvxLeftMarginItem! must be converted
456 if (SvxRightMarginItem const*const pRight = rItemSet.GetItemIfSet(RES_MARGIN_RIGHT, false))
458 if (!oLRSpace)
460 if (const SvxLRSpaceItem* pPageItem = rPageItemSet.GetItemIfSet(RES_LR_SPACE))
462 oLRSpace.emplace(*pPageItem);
464 else
466 oLRSpace.emplace(RES_LR_SPACE);
469 oLRSpace->SetRight(pRight->GetRight());
472 if (oLRSpace)
474 rMaster.SetFormatAttr(*oLRSpace);
475 bChanged = true;
478 // top and bottom border
479 const SvxULSpaceItem *pULItem;
480 if( (rPropInfo.m_bTopMargin || rPropInfo.m_bBottomMargin) &&
481 (pULItem = rItemSet.GetItemIfSet(RES_UL_SPACE,false)) )
483 const SvxULSpaceItem* pPageItem;
484 if( (!rPropInfo.m_bTopMargin || !rPropInfo.m_bBottomMargin) &&
485 (pPageItem = rPageItemSet.GetItemIfSet(RES_UL_SPACE) ) )
487 SvxULSpaceItem aULItem( *pPageItem );
488 if( rPropInfo.m_bTopMargin )
489 aULItem.SetUpper( pULItem->GetUpper() );
490 if( rPropInfo.m_bBottomMargin )
491 aULItem.SetLower( pULItem->GetLower() );
493 rMaster.SetFormatAttr( aULItem );
495 else
497 rMaster.SetFormatAttr( *pULItem );
499 bChanged = true;
502 // the size
503 if( rPropInfo.m_eSizeType != SVX_CSS1_STYPE_NONE )
505 if( rPropInfo.m_eSizeType == SVX_CSS1_STYPE_TWIP )
507 rMaster.SetFormatAttr( SwFormatFrameSize( SwFrameSize::Fixed, rPropInfo.m_nWidth,
508 rPropInfo.m_nHeight ) );
509 bChanged = true;
511 else
513 // With "size: auto|portrait|landscape" the current size
514 // of the style remains. If "landscape" and "portrait" then
515 // the landscape flag will be set and maybe the width/height
516 // are swapped.
517 SwFormatFrameSize aFrameSz( rMaster.GetFrameSize() );
518 bool bLandscape = aNewPageDesc.GetLandscape();
519 if( ( bLandscape &&
520 rPropInfo.m_eSizeType == SVX_CSS1_STYPE_PORTRAIT ) ||
521 ( !bLandscape &&
522 rPropInfo.m_eSizeType == SVX_CSS1_STYPE_LANDSCAPE ) )
524 SwTwips nTmp = aFrameSz.GetHeight();
525 aFrameSz.SetHeight( aFrameSz.GetWidth() );
526 aFrameSz.SetWidth( nTmp );
527 rMaster.SetFormatAttr( aFrameSz );
528 aNewPageDesc.SetLandscape( !bLandscape );
529 bChanged = true;
534 // Is that possible?
535 if( const SvxBrushItem* pItem = rItemSet.GetItemIfSet( RES_BACKGROUND, false ) )
537 // set a background
538 rMaster.SetFormatAttr( *pItem );
539 rItemSet.ClearItem( RES_BACKGROUND );
540 bChanged = true;
543 if( bChanged )
544 ChgPageDesc( pPageDesc, aNewPageDesc );
547 std::unique_ptr<SvxBrushItem> SwCSS1Parser::makePageDescBackground() const
549 return m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_HTML, false )
550 ->GetMaster().makeBackgroundBrushItem();
553 Css1ScriptFlags SwCSS1Parser::GetScriptFromClass( OUString& rClass,
554 bool bSubClassOnly )
556 Css1ScriptFlags nScriptFlags = Css1ScriptFlags::AllMask;
557 sal_Int32 nLen = rClass.getLength();
558 sal_Int32 nPos = nLen > 4 ? rClass.lastIndexOf( '-' ) : -1;
560 if( nPos == -1 )
562 if( bSubClassOnly )
563 return nScriptFlags;
564 nPos = 0;
566 else
568 nPos++;
569 nLen = nLen - nPos;
572 switch( nLen )
574 case 3:
575 if( rClass.matchIgnoreAsciiCase( "cjk", nPos ) )
577 nScriptFlags = Css1ScriptFlags::CJK;
579 else if( rClass.matchIgnoreAsciiCase( "ctl", nPos ) )
581 nScriptFlags = Css1ScriptFlags::CTL;
583 break;
584 case 7:
585 if( rClass.matchIgnoreAsciiCase( "western", nPos ) )
587 nScriptFlags = Css1ScriptFlags::Western;
589 break;
591 if( Css1ScriptFlags::AllMask != nScriptFlags )
593 if( nPos )
595 rClass = rClass.copy( 0, nPos-1 );
597 else
599 rClass.clear();
603 return nScriptFlags;
606 static CSS1SelectorType GetTokenAndClass( const CSS1Selector *pSelector,
607 OUString& rToken, OUString& rClass,
608 Css1ScriptFlags& rScriptFlags )
610 rToken = pSelector->GetString();
611 rClass.clear();
612 rScriptFlags = Css1ScriptFlags::AllMask;
614 CSS1SelectorType eType = pSelector->GetType();
615 if( CSS1_SELTYPE_ELEM_CLASS==eType )
617 sal_Int32 nPos = rToken.indexOf( '.' );
618 OSL_ENSURE( nPos >= 0, "No dot in Class-Selector???" );
619 if( nPos >= 0 )
621 rClass = rToken.copy( nPos+1 );
622 rToken = rToken.copy( 0, nPos );
624 rScriptFlags = SwCSS1Parser::GetScriptFromClass( rClass, false );
625 if( rClass.isEmpty() )
626 eType = CSS1_SELTYPE_ELEMENT;
630 rToken = rToken.toAsciiLowerCase();
631 return eType;
634 static void RemoveScriptItems( SfxItemSet& rItemSet, Css1ScriptFlags nScript,
635 const SfxItemSet *pParentItemSet = nullptr )
637 static const sal_uInt16 aWhichIds[3][5] =
639 { RES_CHRATR_FONT, RES_CHRATR_FONTSIZE, RES_CHRATR_LANGUAGE,
640 RES_CHRATR_POSTURE, RES_CHRATR_WEIGHT },
641 { RES_CHRATR_CJK_FONT, RES_CHRATR_CJK_FONTSIZE, RES_CHRATR_CJK_LANGUAGE,
642 RES_CHRATR_CJK_POSTURE, RES_CHRATR_CJK_WEIGHT },
643 { RES_CHRATR_CTL_FONT, RES_CHRATR_CTL_FONTSIZE, RES_CHRATR_CTL_LANGUAGE,
644 RES_CHRATR_CTL_POSTURE, RES_CHRATR_CTL_WEIGHT }
647 bool aClearItems[3] = { false, false, false };
648 switch( nScript )
650 case Css1ScriptFlags::Western:
651 aClearItems[1] = aClearItems[2] = true;
652 break;
653 case Css1ScriptFlags::CJK:
654 aClearItems[0] = aClearItems[2] = true;
655 break;
656 case Css1ScriptFlags::CTL:
657 aClearItems[0] = aClearItems[1] = true;
658 break;
659 case Css1ScriptFlags::AllMask:
660 break;
661 default:
662 OSL_ENSURE( aClearItems[0], "unknown script type" );
663 break;
666 for( size_t j=0; j < SAL_N_ELEMENTS(aWhichIds); ++j )
668 for( size_t i=0; i < SAL_N_ELEMENTS(aWhichIds[0]); ++i )
670 sal_uInt16 nWhich = aWhichIds[j][i];
671 const SfxPoolItem *pItem;
672 if( aClearItems[j] ||
673 (pParentItemSet &&
674 SfxItemState::SET == rItemSet.GetItemState( nWhich, false, &pItem ) &&
675 (0==i ? swhtml_css1atr_equalFontItems( *pItem, pParentItemSet->Get(nWhich ) )
676 : *pItem == pParentItemSet->Get(nWhich ) ) ) )
678 rItemSet.ClearItem( nWhich );
684 void SwCSS1Parser::StyleParsed( const CSS1Selector *pSelector,
685 SfxItemSet& rItemSet,
686 SvxCSS1PropertyInfo& rPropInfo )
688 if( !m_bIsNewDoc )
689 return;
691 CSS1SelectorType eSelType = pSelector->GetType();
692 const CSS1Selector *pNext = pSelector->GetNext();
694 if( CSS1_SELTYPE_ID==eSelType && !pNext )
696 InsertId( pSelector->GetString(), rItemSet, rPropInfo );
698 else if( CSS1_SELTYPE_CLASS==eSelType && !pNext )
700 OUString aClass( pSelector->GetString() );
701 Css1ScriptFlags nScript = GetScriptFromClass( aClass );
702 if( Css1ScriptFlags::AllMask != nScript )
704 SfxItemSet aScriptItemSet( rItemSet );
705 RemoveScriptItems( aScriptItemSet, nScript );
706 InsertClass( aClass, aScriptItemSet, rPropInfo );
708 else
710 InsertClass( aClass, rItemSet, rPropInfo );
713 else if( CSS1_SELTYPE_PAGE==eSelType )
715 if( !pNext ||
716 (CSS1_SELTYPE_PSEUDO == pNext->GetType() &&
717 (pNext->GetString().equalsIgnoreAsciiCase( "left" ) ||
718 pNext->GetString().equalsIgnoreAsciiCase( "right" ) ||
719 pNext->GetString().equalsIgnoreAsciiCase( "first" ) ) ) )
721 OUString aName;
722 if( pNext )
723 aName = pNext->GetString();
724 InsertPage( aName,
725 pNext != nullptr,
726 rItemSet, rPropInfo );
730 if( CSS1_SELTYPE_ELEMENT != eSelType &&
731 CSS1_SELTYPE_ELEM_CLASS != eSelType)
732 return;
734 // get token and class of selector
735 OUString aToken2;
736 OUString aClass;
737 Css1ScriptFlags nScript;
738 eSelType = GetTokenAndClass( pSelector, aToken2, aClass, nScript );
739 HtmlTokenId nToken2 = GetHTMLToken( aToken2 );
741 // and also some information of the next element
742 CSS1SelectorType eNextType = pNext ? pNext->GetType()
743 : CSS1_SELTYPE_ELEMENT;
745 // first some special cases
746 if( CSS1_SELTYPE_ELEMENT==eSelType )
748 switch( nToken2 )
750 case HtmlTokenId::ANCHOR_ON:
751 if( !pNext )
753 InsertTag( aToken2, rItemSet, rPropInfo );
754 return;
756 else if (CSS1_SELTYPE_PSEUDO == eNextType)
758 // maybe A:visited or A:link
760 OUString aPseudo( pNext->GetString() );
761 aPseudo = aPseudo.toAsciiLowerCase();
762 bool bInsert = false;
763 switch( aPseudo[0] )
765 case 'l':
766 if( aPseudo == "link" )
768 bInsert = true;
770 break;
771 case 'v':
772 if( aPseudo == "visited" )
774 bInsert = true;
776 break;
778 if( bInsert )
780 OUString sTmp = aToken2 + ":" + aPseudo;
781 if( Css1ScriptFlags::AllMask != nScript )
783 SfxItemSet aScriptItemSet( rItemSet );
784 RemoveScriptItems( aScriptItemSet, nScript );
785 InsertTag( sTmp, aScriptItemSet, rPropInfo );
787 else
789 InsertTag( sTmp, rItemSet, rPropInfo );
791 return;
794 break;
795 case HtmlTokenId::BODY_ON:
796 if( !pNext )
798 // BODY
800 // We must test the background before setting, because
801 // in SetPageDescAttrs it will be deleted.
802 if( const SvxBrushItem *pBrushItem = rItemSet.GetItemIfSet(RES_BACKGROUND,false) )
804 /// Body has a background color, if it is not "no fill"/"auto fill"
805 if( pBrushItem->GetColor() != COL_TRANSPARENT )
806 m_bBodyBGColorSet = true;
807 if( GPOS_NONE != pBrushItem->GetGraphicPos() )
808 m_bBodyBackgroundSet = true;
811 // Border and Padding
812 rPropInfo.SetBoxItem( rItemSet, MIN_BORDER_DIST );
814 // Some attributes must be set at the style, the ones which
815 // aren't inherited
816 SetPageDescAttrs( nullptr, &rItemSet );
818 // all remaining options can be set at the default style,
819 // then they're the default
820 if( SfxItemState::SET==rItemSet.GetItemState(RES_CHRATR_COLOR,false) )
821 m_bBodyTextSet = true;
822 SetTextCollAttrs(
823 GetTextCollFromPool( RES_POOLCOLL_STANDARD ),
824 rItemSet, rPropInfo, this );
826 return;
828 break;
829 default: break;
832 else if( CSS1_SELTYPE_ELEM_CLASS==eSelType && HtmlTokenId::ANCHOR_ON==nToken2 &&
833 !pNext && aClass.getLength() >= 9 &&
834 ('s' == aClass[0] || 'S' == aClass[0]) )
836 sal_uInt16 nPoolFormatId = 0;
837 if( aClass.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_sdendnote_sym) )
838 nPoolFormatId = RES_POOLCHR_ENDNOTE;
839 else if( aClass.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_sdfootnote_sym) )
840 nPoolFormatId = RES_POOLCHR_FOOTNOTE;
841 if( nPoolFormatId )
843 if( Css1ScriptFlags::AllMask == nScript )
845 SetCharFormatAttrs( GetCharFormatFromPool(nPoolFormatId), rItemSet );
847 else
849 SfxItemSet aScriptItemSet( rItemSet );
850 RemoveScriptItems( aScriptItemSet, nScript );
851 SetCharFormatAttrs( GetCharFormatFromPool(nPoolFormatId),
852 aScriptItemSet);
854 return;
858 // Now the selectors are processed which belong to a paragraph style
859 sal_uInt16 nPoolCollId = 0;
860 switch( nToken2 )
862 case HtmlTokenId::HEAD1_ON:
863 nPoolCollId = RES_POOLCOLL_HEADLINE1;
864 break;
865 case HtmlTokenId::HEAD2_ON:
866 nPoolCollId = RES_POOLCOLL_HEADLINE2;
867 break;
868 case HtmlTokenId::HEAD3_ON:
869 nPoolCollId = RES_POOLCOLL_HEADLINE3;
870 break;
871 case HtmlTokenId::HEAD4_ON:
872 nPoolCollId = RES_POOLCOLL_HEADLINE4;
873 break;
874 case HtmlTokenId::HEAD5_ON:
875 nPoolCollId = RES_POOLCOLL_HEADLINE5;
876 break;
877 case HtmlTokenId::HEAD6_ON:
878 nPoolCollId = RES_POOLCOLL_HEADLINE6;
879 break;
880 case HtmlTokenId::PARABREAK_ON:
881 if( aClass.getLength() >= 9 &&
882 ('s' == aClass[0] || 'S' == aClass[0]) )
884 if( aClass.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_sdendnote) )
885 nPoolCollId = RES_POOLCOLL_ENDNOTE;
886 else if( aClass.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_sdfootnote) )
887 nPoolCollId = RES_POOLCOLL_FOOTNOTE;
889 if( nPoolCollId )
890 aClass.clear();
891 else
892 nPoolCollId = RES_POOLCOLL_TEXT;
894 else
896 nPoolCollId = RES_POOLCOLL_TEXT;
898 break;
899 case HtmlTokenId::ADDRESS_ON:
900 nPoolCollId = RES_POOLCOLL_SEND_ADDRESS;
901 break;
902 case HtmlTokenId::BLOCKQUOTE_ON:
903 nPoolCollId = RES_POOLCOLL_HTML_BLOCKQUOTE;
904 break;
905 case HtmlTokenId::DT_ON:
906 nPoolCollId = RES_POOLCOLL_HTML_DT;
907 break;
908 case HtmlTokenId::DD_ON:
909 nPoolCollId = RES_POOLCOLL_HTML_DD;
910 break;
911 case HtmlTokenId::PREFORMTXT_ON:
912 nPoolCollId = RES_POOLCOLL_HTML_PRE;
913 break;
914 case HtmlTokenId::TABLEHEADER_ON:
915 case HtmlTokenId::TABLEDATA_ON:
916 if( CSS1_SELTYPE_ELEMENT==eSelType && !pNext )
918 InsertTag( aToken2, rItemSet, rPropInfo );
919 return;
921 else if( CSS1_SELTYPE_ELEMENT==eSelType && pNext &&
922 (CSS1_SELTYPE_ELEMENT==eNextType ||
923 CSS1_SELTYPE_ELEM_CLASS==eNextType) )
925 // not TH and TD, but TH P and TD P
926 OUString aSubToken, aSubClass;
927 GetTokenAndClass( pNext, aSubToken, aSubClass, nScript );
928 if( HtmlTokenId::PARABREAK_ON == GetHTMLToken( aSubToken ) )
930 aClass = aSubClass;
931 pNext = pNext->GetNext();
932 eNextType = pNext ? pNext->GetType() : CSS1_SELTYPE_ELEMENT;
934 if( !aClass.isEmpty() || pNext )
936 nPoolCollId = static_cast< sal_uInt16 >(
937 HtmlTokenId::TABLEHEADER_ON == nToken2 ? RES_POOLCOLL_TABLE_HDLN
938 : RES_POOLCOLL_TABLE );
940 else
942 OUString sTmp = aToken2 + " " OOO_STRING_SVTOOLS_HTML_parabreak;
944 if( Css1ScriptFlags::AllMask == nScript )
946 InsertTag( sTmp, rItemSet, rPropInfo );
948 else
950 SfxItemSet aScriptItemSet( rItemSet );
951 RemoveScriptItems( aScriptItemSet, nScript );
952 InsertTag( sTmp, aScriptItemSet, rPropInfo );
955 return;
959 break;
961 default:
965 if( nPoolCollId )
967 if( !pNext ||
968 (CSS1_SELTYPE_PSEUDO==eNextType &&
969 pNext->GetString().equalsIgnoreAsciiCase( "first-letter" ) &&
970 SvxAdjust::Left == rPropInfo.m_eFloat) )
972 // either not a composed selector or a X:first-line { float: left; ... }
974 // search resp. create the style
975 SwTextFormatColl* pColl = GetTextFormatColl(nPoolCollId, OUString());
976 SwTextFormatColl* pParentColl = nullptr;
977 if( !aClass.isEmpty() )
979 OUString aName( pColl->GetName() );
980 AddClassName( aName, aClass );
982 pParentColl = pColl;
983 pColl = m_pDoc->FindTextFormatCollByName( aName );
984 if( !pColl )
985 pColl = m_pDoc->MakeTextFormatColl( aName, pParentColl );
987 if( !pNext )
989 // set only the attributes at the style
990 const SvxBoxItem *pBoxItem =
991 pColl->GetAttrSet().GetItemIfSet(RES_BOX);
992 rPropInfo.SetBoxItem( rItemSet, MIN_BORDER_DIST, pBoxItem );
993 if( Css1ScriptFlags::AllMask == nScript && !pParentColl )
995 SetTextCollAttrs( pColl, rItemSet, rPropInfo, this );
997 else
999 SfxItemSet aScriptItemSet( rItemSet );
1000 RemoveScriptItems( aScriptItemSet, nScript,
1001 pParentColl ? &pParentColl->GetAttrSet() : nullptr );
1002 SetTextCollAttrs( pColl, aScriptItemSet, rPropInfo, this );
1005 else
1007 // create a DropCap attribute
1008 SwFormatDrop aDrop( pColl->GetDrop() );
1009 aDrop.SetChars( 1 );
1011 // set the attributes of the DropCap attribute
1012 if( Css1ScriptFlags::AllMask == nScript )
1014 OUString sName(pColl->GetName());
1015 FillDropCap( aDrop, rItemSet, &sName );
1017 else
1019 SfxItemSet aScriptItemSet( rItemSet );
1020 if( Css1ScriptFlags::Western != nScript )
1022 aScriptItemSet.ClearItem( RES_CHRATR_FONT );
1023 aScriptItemSet.ClearItem( RES_CHRATR_LANGUAGE );
1024 aScriptItemSet.ClearItem( RES_CHRATR_POSTURE );
1025 aScriptItemSet.ClearItem( RES_CHRATR_WEIGHT );
1027 if( Css1ScriptFlags::CJK != nScript )
1029 aScriptItemSet.ClearItem( RES_CHRATR_CJK_FONT );
1030 aScriptItemSet.ClearItem( RES_CHRATR_CJK_LANGUAGE );
1031 aScriptItemSet.ClearItem( RES_CHRATR_CJK_POSTURE );
1032 aScriptItemSet.ClearItem( RES_CHRATR_CJK_WEIGHT );
1034 if( Css1ScriptFlags::CTL != nScript )
1036 aScriptItemSet.ClearItem( RES_CHRATR_CTL_FONT );
1037 aScriptItemSet.ClearItem( RES_CHRATR_CTL_LANGUAGE );
1038 aScriptItemSet.ClearItem( RES_CHRATR_CTL_POSTURE );
1039 aScriptItemSet.ClearItem( RES_CHRATR_CTL_WEIGHT );
1041 OUString sName(pColl->GetName());
1042 FillDropCap( aDrop, aScriptItemSet, &sName );
1045 // Only set the attribute if "float: left" is specified and
1046 // the Initial is over several lines. Otherwise the maybe
1047 // created character style will be later searched and set
1048 // via name.
1049 if( aDrop.GetLines() > 1 &&
1050 (SvxAdjust::Left == rPropInfo.m_eFloat ||
1051 Css1ScriptFlags::AllMask == nScript) )
1053 pColl->SetFormatAttr( aDrop );
1058 return;
1061 // Now the selectors are processed which are belonging to the character
1062 // template. There are no composed ones here.
1063 if( pNext )
1064 return;
1066 SwCharFormat* pCFormat = GetChrFormat(nToken2, OUString());
1067 if( !pCFormat )
1068 return;
1070 SwCharFormat *pParentCFormat = nullptr;
1071 if( !aClass.isEmpty() )
1073 OUString aName( pCFormat->GetName() );
1074 AddClassName( aName, aClass );
1075 pParentCFormat = pCFormat;
1077 pCFormat = m_pDoc->FindCharFormatByName( aName );
1078 if( !pCFormat )
1080 pCFormat = m_pDoc->MakeCharFormat( aName, pParentCFormat );
1081 pCFormat->SetAuto(false);
1085 if( Css1ScriptFlags::AllMask == nScript && !pParentCFormat )
1087 SetCharFormatAttrs( pCFormat, rItemSet );
1089 else
1091 SfxItemSet aScriptItemSet( rItemSet );
1092 RemoveScriptItems( aScriptItemSet, nScript,
1093 pParentCFormat ? &pParentCFormat->GetAttrSet() : nullptr );
1094 SetCharFormatAttrs( pCFormat, aScriptItemSet );
1098 sal_uInt32 SwCSS1Parser::GetFontHeight( sal_uInt16 nSize ) const
1100 return m_aFontHeights[ std::min<sal_uInt16>(nSize,6) ];
1103 const FontList *SwCSS1Parser::GetFontList() const
1105 const FontList *pFList = nullptr;
1106 SwDocShell *pDocSh = m_pDoc->GetDocShell();
1107 if( pDocSh )
1109 const SvxFontListItem *pFListItem =
1110 static_cast<const SvxFontListItem *>(pDocSh->GetItem(SID_ATTR_CHAR_FONTLIST));
1111 if( pFListItem )
1112 pFList = pFListItem->GetFontList();
1115 return pFList;
1118 SwCharFormat* SwCSS1Parser::GetChrFormat( HtmlTokenId nToken2, const OUString& rClass ) const
1120 // search the corresponding style
1121 sal_uInt16 nPoolId = 0;
1122 const char* sName = nullptr;
1123 switch( nToken2 )
1125 case HtmlTokenId::EMPHASIS_ON: nPoolId = RES_POOLCHR_HTML_EMPHASIS; break;
1126 case HtmlTokenId::CITATION_ON: nPoolId = RES_POOLCHR_HTML_CITATION; break;
1127 case HtmlTokenId::STRONG_ON: nPoolId = RES_POOLCHR_HTML_STRONG; break;
1128 case HtmlTokenId::CODE_ON: nPoolId = RES_POOLCHR_HTML_CODE; break;
1129 case HtmlTokenId::SAMPLE_ON: nPoolId = RES_POOLCHR_HTML_SAMPLE; break;
1130 case HtmlTokenId::KEYBOARD_ON: nPoolId = RES_POOLCHR_HTML_KEYBOARD; break;
1131 case HtmlTokenId::VARIABLE_ON: nPoolId = RES_POOLCHR_HTML_VARIABLE; break;
1132 case HtmlTokenId::DEFINSTANCE_ON: nPoolId = RES_POOLCHR_HTML_DEFINSTANCE; break;
1133 case HtmlTokenId::TELETYPE_ON: nPoolId = RES_POOLCHR_HTML_TELETYPE; break;
1135 case HtmlTokenId::SHORTQUOTE_ON: sName = OOO_STRING_SVTOOLS_HTML_shortquote; break;
1136 case HtmlTokenId::LANGUAGE_ON: sName = OOO_STRING_SVTOOLS_HTML_language; break;
1137 case HtmlTokenId::AUTHOR_ON: sName = OOO_STRING_SVTOOLS_HTML_author; break;
1138 case HtmlTokenId::PERSON_ON: sName = OOO_STRING_SVTOOLS_HTML_person; break;
1139 case HtmlTokenId::ACRONYM_ON: sName = OOO_STRING_SVTOOLS_HTML_acronym; break;
1140 case HtmlTokenId::ABBREVIATION_ON: sName = OOO_STRING_SVTOOLS_HTML_abbreviation; break;
1141 case HtmlTokenId::INSERTEDTEXT_ON: sName = OOO_STRING_SVTOOLS_HTML_insertedtext; break;
1142 case HtmlTokenId::DELETEDTEXT_ON: sName = OOO_STRING_SVTOOLS_HTML_deletedtext; break;
1143 default: break;
1146 // search or create the style (only possible with name)
1147 if( !nPoolId && !sName )
1148 return nullptr;
1150 // search or create style (without class)
1151 SwCharFormat *pCFormat = nullptr;
1152 if( nPoolId )
1154 pCFormat = GetCharFormatFromPool( nPoolId );
1156 else
1158 OUString sCName( OUString::createFromAscii(sName) );
1159 pCFormat = m_pDoc->FindCharFormatByName( sCName );
1160 if( !pCFormat )
1162 pCFormat = m_pDoc->MakeCharFormat( sCName, m_pDoc->GetDfltCharFormat() );
1163 pCFormat->SetAuto(false);
1167 assert(pCFormat && "No character style???");
1169 // If a class exists, then search for the class style but don't
1170 // create one.
1171 OUString aClass( rClass );
1172 GetScriptFromClass( aClass, false );
1173 if( !aClass.isEmpty() )
1175 OUString aTmp( pCFormat->GetName() );
1176 AddClassName( aTmp, aClass );
1177 SwCharFormat *pClassCFormat = m_pDoc->FindCharFormatByName( aTmp );
1178 if( pClassCFormat )
1180 pCFormat = pClassCFormat;
1182 else
1184 const SvxCSS1MapEntry *pClass = GetClass( aClass );
1185 if( pClass )
1187 pCFormat = m_pDoc->MakeCharFormat( aTmp, pCFormat );
1188 pCFormat->SetAuto(false);
1189 SfxItemSet aItemSet( pClass->GetItemSet() );
1190 SetCharFormatAttrs( pCFormat, aItemSet );
1195 return pCFormat;
1198 SwTextFormatColl *SwCSS1Parser::GetTextCollFromPool( sal_uInt16 nPoolId ) const
1200 const SwTextFormatColls::size_type nOldArrLen = m_pDoc->GetTextFormatColls()->size();
1202 SwTextFormatColl *pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( nPoolId, false );
1204 if( m_bIsNewDoc )
1206 const SwTextFormatColls::size_type nArrLen = m_pDoc->GetTextFormatColls()->size();
1207 for( SwTextFormatColls::size_type i=nOldArrLen; i<nArrLen; ++i )
1208 lcl_swcss1_setEncoding( *(*m_pDoc->GetTextFormatColls())[i],
1209 GetDfltEncoding() );
1212 return pColl;
1215 SwCharFormat *SwCSS1Parser::GetCharFormatFromPool( sal_uInt16 nPoolId ) const
1217 const SwCharFormats::size_type nOldArrLen = m_pDoc->GetCharFormats()->size();
1219 SwCharFormat *pCharFormat = m_pDoc->getIDocumentStylePoolAccess().GetCharFormatFromPool( nPoolId );
1221 if( m_bIsNewDoc )
1223 const SwCharFormats::size_type nArrLen = m_pDoc->GetCharFormats()->size();
1225 for( SwCharFormats::size_type i=nOldArrLen; i<nArrLen; i++ )
1226 lcl_swcss1_setEncoding( *(*m_pDoc->GetCharFormats())[i],
1227 GetDfltEncoding() );
1230 return pCharFormat;
1233 SwTextFormatColl *SwCSS1Parser::GetTextFormatColl( sal_uInt16 nTextColl,
1234 const OUString& rClass )
1236 SwTextFormatColl* pColl = nullptr;
1238 OUString aClass( rClass );
1239 GetScriptFromClass( aClass, false );
1240 if( RES_POOLCOLL_TEXT == nTextColl && aClass.getLength() >= 9 &&
1241 ('s' == aClass[0] || 'S' == aClass[0] ) )
1243 if( aClass.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_sdendnote) )
1245 nTextColl = RES_POOLCOLL_ENDNOTE;
1246 aClass.clear();
1248 else if( aClass.equalsIgnoreAsciiCase(OOO_STRING_SVTOOLS_HTML_sdfootnote) )
1250 nTextColl = RES_POOLCOLL_FOOTNOTE;
1251 aClass.clear();
1255 if( USER_FMT & nTextColl ) // one created by Reader
1257 OSL_ENSURE( false, "Where does the user style comes from?" );
1258 pColl = GetTextCollFromPool( RES_POOLCOLL_STANDARD );
1260 else
1262 pColl = GetTextCollFromPool( nTextColl );
1265 if( !aClass.isEmpty() )
1267 assert(pColl && "No paragraph style???");
1268 OUString aTmp( pColl->GetName() );
1269 AddClassName( aTmp, aClass );
1270 SwTextFormatColl* pClassColl = m_pDoc->FindTextFormatCollByName( aTmp );
1272 if( !pClassColl &&
1273 (nTextColl==RES_POOLCOLL_TABLE ||
1274 nTextColl==RES_POOLCOLL_TABLE_HDLN) )
1276 // In this case there was a <TD><P CLASS=foo>, but no TD.foo
1277 // style was found. The we must use P.foo, if available.
1278 SwTextFormatColl* pCollText =
1279 GetTextCollFromPool( RES_POOLCOLL_TEXT );
1280 aTmp = pCollText->GetName();
1281 AddClassName( aTmp, aClass );
1282 pClassColl = m_pDoc->FindTextFormatCollByName( aTmp );
1285 if( pClassColl )
1287 pColl = pClassColl;
1289 else
1291 const SvxCSS1MapEntry *pClass = GetClass( aClass );
1292 if( pClass )
1294 pColl = m_pDoc->MakeTextFormatColl( aTmp, pColl );
1295 SfxItemSet aItemSet( pClass->GetItemSet() );
1296 SvxCSS1PropertyInfo aPropInfo( pClass->GetPropertyInfo() );
1297 aPropInfo.SetBoxItem( aItemSet, MIN_BORDER_DIST );
1298 bool bPositioned = MayBePositioned( pClass->GetPropertyInfo() );
1299 if( bPositioned )
1300 aItemSet.ClearItem( RES_BACKGROUND );
1301 SetTextCollAttrs( pColl, aItemSet, aPropInfo,
1302 this );
1308 if( pColl )
1309 lcl_swcss1_setEncoding( *pColl, GetDfltEncoding() );
1311 return pColl;
1314 SwPageDesc *SwCSS1Parser::GetMasterPageDesc()
1316 return m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_HTML, false );
1319 static SwPageDesc *FindPageDesc(SwDoc *pDoc, sal_uInt16 nPoolId)
1321 size_t nPageDescs = pDoc->GetPageDescCnt();
1322 size_t nPage;
1323 for (nPage=0; nPage < nPageDescs &&
1324 pDoc->GetPageDesc(nPage).GetPoolFormatId() != nPoolId; ++nPage)
1327 return nPage < nPageDescs ? &pDoc->GetPageDesc(nPage) : nullptr;
1330 const SwPageDesc *SwCSS1Parser::GetPageDesc( sal_uInt16 nPoolId, bool bCreate )
1332 if( RES_POOLPAGE_HTML == nPoolId )
1333 return m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_HTML, false );
1335 const SwPageDesc *pPageDesc = FindPageDesc(m_pDoc, nPoolId);
1336 if( !pPageDesc && bCreate )
1338 if (m_rHTMLParser.IsReadingHeaderOrFooter())
1339 { // (there should be only one definition of header/footer in HTML)
1340 SAL_WARN("sw.html", "no creating PageDesc while reading header/footer");
1341 return nullptr;
1344 // The first page is created from the right page, if there is one.
1345 SwPageDesc *pMasterPageDesc = nullptr;
1346 if( RES_POOLPAGE_FIRST == nPoolId )
1347 pMasterPageDesc = FindPageDesc(m_pDoc, RES_POOLPAGE_RIGHT);
1348 if( !pMasterPageDesc )
1349 pMasterPageDesc = m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_HTML, false );
1351 // The new page style is created by copying from master
1352 SwPageDesc *pNewPageDesc = m_pDoc->
1353 getIDocumentStylePoolAccess().GetPageDescFromPool( nPoolId, false );
1355 // therefore we also need the number of the new style
1356 OSL_ENSURE(pNewPageDesc == FindPageDesc(m_pDoc, nPoolId), "page style not found");
1358 m_pDoc->CopyPageDesc( *pMasterPageDesc, *pNewPageDesc, false );
1360 // Modify the styles for their new purpose.
1361 const SwPageDesc *pFollow = nullptr;
1362 bool bSetFollowFollow = false;
1363 switch( nPoolId )
1365 case RES_POOLPAGE_FIRST:
1366 // If there is already a left page, then is it the follow-up
1367 // style, else it is the HTML style.
1368 pFollow = GetLeftPageDesc();
1369 if( !pFollow )
1370 pFollow = pMasterPageDesc;
1371 break;
1373 case RES_POOLPAGE_RIGHT:
1374 // If the left style is already created, nothing will happen here.
1375 // Otherwise the left style is created and ensures the link with
1376 // the right style.
1377 GetLeftPageDesc( true );
1378 break;
1380 case RES_POOLPAGE_LEFT:
1381 // The right style is created if none exists. No links are created.
1382 // If there is already a first page style, then the left style becomes
1383 // follow-up style of the first page.
1384 pFollow = GetRightPageDesc( true );
1385 bSetFollowFollow = true;
1387 const SwPageDesc *pFirstPageDesc = GetFirstPageDesc();
1388 if( pFirstPageDesc )
1390 SwPageDesc aNewFirstPageDesc( *pFirstPageDesc );
1391 aNewFirstPageDesc.SetFollow( pNewPageDesc );
1392 ChgPageDesc( pFirstPageDesc, aNewFirstPageDesc );
1395 break;
1398 if( pFollow )
1400 SwPageDesc aNewPageDesc( *pNewPageDesc );
1401 aNewPageDesc.SetFollow( pFollow );
1402 ChgPageDesc( pNewPageDesc, aNewPageDesc );
1404 if( bSetFollowFollow )
1406 SwPageDesc aNewFollowPageDesc( *pFollow );
1407 aNewFollowPageDesc.SetFollow( pNewPageDesc );
1408 ChgPageDesc( pFollow, aNewFollowPageDesc );
1411 pPageDesc = pNewPageDesc;
1414 return pPageDesc;
1417 bool SwCSS1Parser::MayBePositioned( const SvxCSS1PropertyInfo& rPropInfo,
1418 bool bAutoWidth )
1420 if (!rPropInfo.m_bVisible)
1422 // Don't create a textframe for this div if it's hidden.
1423 return false;
1426 // abs-pos
1427 // left/top none auto twip perc
1429 // none Z Z - -
1430 // auto Z Z - -
1431 // twip Z Z S/R -
1432 // perc - - - -
1434 // - the tag will be positioned absolutely and left/top are both
1435 // present and don't contain a percentage value, or
1436 // - the tag should flow, and
1437 // - a width was specified (needed in both cases)
1438 return ( ( SVX_CSS1_POS_ABSOLUTE == rPropInfo.m_ePosition &&
1439 SVX_CSS1_LTYPE_PERCENTAGE != rPropInfo.m_eLeftType &&
1440 SVX_CSS1_LTYPE_PERCENTAGE != rPropInfo.m_eTopType &&
1441 (SVX_CSS1_LTYPE_TWIP == rPropInfo.m_eLeftType ||
1442 SVX_CSS1_LTYPE_TWIP != rPropInfo.m_eTopType) ) ||
1443 ( SvxAdjust::End != rPropInfo.m_eFloat ) ) &&
1444 ( bAutoWidth ||
1445 SVX_CSS1_LTYPE_TWIP == rPropInfo.m_eWidthType ||
1446 SVX_CSS1_LTYPE_PERCENTAGE == rPropInfo.m_eWidthType );
1449 void SwCSS1Parser::AddClassName( OUString& rFormatName, std::u16string_view rClass )
1451 OSL_ENSURE( !rClass.empty(), "Style class without length?" );
1453 rFormatName += OUString::Concat(".") + rClass;
1456 void SwCSS1Parser::FillDropCap( SwFormatDrop& rDrop,
1457 SfxItemSet& rItemSet,
1458 const OUString *pName )
1460 // the number of lines matches somehow a percentage value
1461 // for the height (what happens with absolute heights???)
1462 sal_uInt8 nLines = rDrop.GetLines();
1463 if( const SvxFontHeightItem* pFontHeightItem = rItemSet.GetItemIfSet( RES_CHRATR_FONTSIZE, false ) )
1465 sal_uInt16 nProp = pFontHeightItem->GetProp();
1466 nLines = static_cast<sal_uInt8>((nProp + 50) / 100);
1467 if( nLines < 1 )
1468 nLines = 1;
1469 else if( nLines > MAX_DROPCAP_LINES )
1470 nLines = MAX_DROPCAP_LINES;
1472 // Only when nLines>1, then the attribute also is set. Then
1473 // we don't need the font height in the character style.
1474 if( nLines > 1 )
1476 rItemSet.ClearItem( RES_CHRATR_FONTSIZE );
1477 rItemSet.ClearItem( RES_CHRATR_CJK_FONTSIZE );
1478 rItemSet.ClearItem( RES_CHRATR_CTL_FONTSIZE );
1482 // In case of hard attribution (pName==0) we can stop, if the Initial is
1483 // only one line.
1484 if( nLines<=1 )
1485 return;
1487 rDrop.SetLines(nLines);
1489 // a right border becomes the spacing to text!
1490 if (const SvxRightMarginItem *const pRightMargin = rItemSet.GetItemIfSet(RES_MARGIN_RIGHT, false))
1492 rDrop.SetDistance(static_cast<sal_uInt16>(pRightMargin->ResolveRight({})));
1493 rItemSet.ClearItem(RES_MARGIN_RIGHT);
1495 rItemSet.ClearItem(RES_MARGIN_FIRSTLINE);
1496 rItemSet.ClearItem(RES_MARGIN_TEXTLEFT);
1498 // for every other attribute create a character style
1499 if( !rItemSet.Count() )
1500 return;
1502 SwCharFormat *pCFormat = nullptr;
1503 OUString aName;
1504 if( pName )
1506 aName = *pName + ".FL"; // first letter
1507 pCFormat = m_pDoc->FindCharFormatByName( aName );
1509 else
1513 aName = "first-letter " + OUString::number( static_cast<sal_Int32>(++m_nDropCapCnt) );
1515 while( m_pDoc->FindCharFormatByName(aName) );
1518 if( !pCFormat )
1520 pCFormat = m_pDoc->MakeCharFormat( aName, m_pDoc->GetDfltCharFormat() );
1521 pCFormat->SetAuto(false);
1523 SetCharFormatAttrs( pCFormat, rItemSet );
1525 // The character style needs only be set in the attribute, when
1526 // the attribute also is set.
1527 if( nLines > 1 )
1528 rDrop.SetCharFormat( pCFormat );
1531 // specific CSS1 of SwHTMLParsers
1533 HTMLAttr **SwHTMLParser::GetAttrTabEntry( sal_uInt16 nWhich )
1535 // find the table entry of the item ...
1536 HTMLAttr **ppAttr = nullptr;
1537 switch( nWhich )
1539 case RES_CHRATR_BLINK:
1540 ppAttr = &m_xAttrTab->pBlink;
1541 break;
1542 case RES_CHRATR_CASEMAP:
1543 ppAttr = &m_xAttrTab->pCaseMap;
1544 break;
1545 case RES_CHRATR_COLOR:
1546 ppAttr = &m_xAttrTab->pFontColor;
1547 break;
1548 case RES_CHRATR_CROSSEDOUT:
1549 ppAttr = &m_xAttrTab->pStrike;
1550 break;
1551 case RES_CHRATR_ESCAPEMENT:
1552 ppAttr = &m_xAttrTab->pEscapement;
1553 break;
1554 case RES_CHRATR_FONT:
1555 ppAttr = &m_xAttrTab->pFont;
1556 break;
1557 case RES_CHRATR_CJK_FONT:
1558 ppAttr = &m_xAttrTab->pFontCJK;
1559 break;
1560 case RES_CHRATR_CTL_FONT:
1561 ppAttr = &m_xAttrTab->pFontCTL;
1562 break;
1563 case RES_CHRATR_FONTSIZE:
1564 ppAttr = &m_xAttrTab->pFontHeight;
1565 break;
1566 case RES_CHRATR_CJK_FONTSIZE:
1567 ppAttr = &m_xAttrTab->pFontHeightCJK;
1568 break;
1569 case RES_CHRATR_CTL_FONTSIZE:
1570 ppAttr = &m_xAttrTab->pFontHeightCTL;
1571 break;
1572 case RES_CHRATR_KERNING:
1573 ppAttr = &m_xAttrTab->pKerning;
1574 break;
1575 case RES_CHRATR_POSTURE:
1576 ppAttr = &m_xAttrTab->pItalic;
1577 break;
1578 case RES_CHRATR_CJK_POSTURE:
1579 ppAttr = &m_xAttrTab->pItalicCJK;
1580 break;
1581 case RES_CHRATR_CTL_POSTURE:
1582 ppAttr = &m_xAttrTab->pItalicCTL;
1583 break;
1584 case RES_CHRATR_UNDERLINE:
1585 ppAttr = &m_xAttrTab->pUnderline;
1586 break;
1587 case RES_CHRATR_WEIGHT:
1588 ppAttr = &m_xAttrTab->pBold;
1589 break;
1590 case RES_CHRATR_CJK_WEIGHT:
1591 ppAttr = &m_xAttrTab->pBoldCJK;
1592 break;
1593 case RES_CHRATR_CTL_WEIGHT:
1594 ppAttr = &m_xAttrTab->pBoldCTL;
1595 break;
1596 case RES_CHRATR_BACKGROUND:
1597 ppAttr = &m_xAttrTab->pCharBrush;
1598 break;
1599 case RES_CHRATR_BOX:
1600 ppAttr = &m_xAttrTab->pCharBox;
1601 break;
1603 case RES_PARATR_LINESPACING:
1604 ppAttr = &m_xAttrTab->pLineSpacing;
1605 break;
1606 case RES_PARATR_ADJUST:
1607 ppAttr = &m_xAttrTab->pAdjust;
1608 break;
1610 case RES_MARGIN_FIRSTLINE:
1611 ppAttr = &m_xAttrTab->pFirstLineIndent;
1612 break;
1613 case RES_MARGIN_TEXTLEFT:
1614 ppAttr = &m_xAttrTab->pTextLeftMargin;
1615 break;
1616 case RES_MARGIN_RIGHT:
1617 ppAttr = &m_xAttrTab->pRightMargin;
1618 break;
1619 case RES_UL_SPACE:
1620 ppAttr = &m_xAttrTab->pULSpace;
1621 break;
1622 case RES_BOX:
1623 ppAttr = &m_xAttrTab->pBox;
1624 break;
1625 case RES_BACKGROUND:
1626 ppAttr = &m_xAttrTab->pBrush;
1627 break;
1628 case RES_BREAK:
1629 ppAttr = &m_xAttrTab->pBreak;
1630 break;
1631 case RES_PAGEDESC:
1632 ppAttr = &m_xAttrTab->pPageDesc;
1633 break;
1634 case RES_PARATR_SPLIT:
1635 ppAttr = &m_xAttrTab->pSplit;
1636 break;
1637 case RES_PARATR_WIDOWS:
1638 ppAttr = &m_xAttrTab->pWidows;
1639 break;
1640 case RES_PARATR_ORPHANS:
1641 ppAttr = &m_xAttrTab->pOrphans;
1642 break;
1643 case RES_KEEP:
1644 ppAttr = &m_xAttrTab->pKeep;
1645 break;
1647 case RES_CHRATR_LANGUAGE:
1648 ppAttr = &m_xAttrTab->pLanguage;
1649 break;
1650 case RES_CHRATR_CJK_LANGUAGE:
1651 ppAttr = &m_xAttrTab->pLanguageCJK;
1652 break;
1653 case RES_CHRATR_CTL_LANGUAGE:
1654 ppAttr = &m_xAttrTab->pLanguageCTL;
1655 break;
1657 case RES_FRAMEDIR:
1658 ppAttr = &m_xAttrTab->pDirection;
1659 break;
1662 return ppAttr;
1665 void SwHTMLParser::NewStyle()
1667 OUString sType;
1669 const HTMLOptions& rOptions2 = GetOptions();
1670 for (size_t i = rOptions2.size(); i; )
1672 const HTMLOption& rOption = rOptions2[--i];
1673 if( HtmlOptionId::TYPE == rOption.GetToken() )
1674 sType = rOption.GetString();
1677 m_bIgnoreRawData = sType.getLength() && o3tl::getToken(sType, 0,';') != sCSS_mimetype;
1680 void SwHTMLParser::EndStyle()
1682 m_bIgnoreRawData = false;
1684 if( !m_aStyleSource.isEmpty() )
1686 m_pCSS1Parser->ParseStyleSheet( m_aStyleSource );
1687 m_aStyleSource.clear();
1691 bool SwHTMLParser::FileDownload( const OUString& rURL,
1692 OUString& rStr )
1694 // depose view (because of reschedule)
1695 SwViewShell *pOldVSh = CallEndAction();
1697 SfxMedium aDLMedium( rURL, StreamMode::READ | StreamMode::SHARE_DENYWRITE );
1699 SvStream* pStream = aDLMedium.GetInStream();
1700 if( pStream )
1702 SvMemoryStream aStream;
1703 aStream.WriteStream( *pStream );
1705 rStr = OUString(static_cast<const char *>(aStream.GetData()), aStream.TellEnd(),
1706 GetSrcEncoding());
1709 // was aborted?
1710 SwDocShell* pShell = m_xDoc->GetDocShell();
1711 if( ( pShell && pShell->IsAbortingImport() )
1712 || 1 == m_xDoc->getReferenceCount() )
1714 // was the import aborted from SFX?
1715 eState = SvParserState::Error;
1716 pStream = nullptr;
1719 // recreate View
1720 SwViewShell *const pVSh = CallStartAction( pOldVSh );
1721 OSL_ENSURE( pOldVSh == pVSh, "FileDownload: SwViewShell changed on us" );
1723 return pStream!=nullptr;
1726 void SwHTMLParser::InsertLink()
1728 bool bFinishDownload = false;
1729 if( !m_vPendingStack.empty() )
1731 OSL_ENSURE( ShouldFinishFileDownload(),
1732 "Pending-Stack without File-Download?" );
1734 m_vPendingStack.pop_back();
1735 assert( m_vPendingStack.empty() && "Where does the Pending-Stack come from?" );
1737 bFinishDownload = true;
1739 else
1741 OUString sRel, sHRef, sType;
1743 const HTMLOptions& rOptions2 = GetOptions();
1744 for (size_t i = rOptions2.size(); i; )
1746 const HTMLOption& rOption = rOptions2[--i];
1747 switch( rOption.GetToken() )
1749 case HtmlOptionId::REL:
1750 sRel = rOption.GetString();
1751 break;
1752 case HtmlOptionId::HREF:
1753 sHRef = URIHelper::SmartRel2Abs( INetURLObject( m_sBaseURL ), rOption.GetString(), Link<OUString *, bool>(), false );
1754 break;
1755 case HtmlOptionId::TYPE:
1756 sType = rOption.GetString();
1757 break;
1758 default: break;
1762 if( !sHRef.isEmpty() && sRel.equalsIgnoreAsciiCase( "STYLESHEET" ) &&
1763 ( sType.isEmpty() || o3tl::getToken(sType, 0,';') == sCSS_mimetype ) )
1765 if( GetMedium() )
1767 // start download of style source
1768 StartFileDownload(sHRef);
1769 if( IsParserWorking() )
1771 // The style was loaded synchronously and we can call it directly.
1772 bFinishDownload = true;
1774 else
1776 // The style was load asynchronously and is only available
1777 // on the next continue call. Therefore we must create a
1778 // Pending stack, so that we will return to here.
1779 m_vPendingStack.emplace_back( HtmlTokenId::LINK );
1782 else
1784 // load file synchronous
1785 OUString sSource;
1786 if( FileDownload( sHRef, sSource ) )
1787 m_pCSS1Parser->ParseStyleSheet( sSource );
1792 if( bFinishDownload )
1794 OUString sSource;
1795 if( FinishFileDownload( sSource ) && !sSource.isEmpty() )
1796 m_pCSS1Parser->ParseStyleSheet( sSource );
1800 bool SwCSS1Parser::ParseStyleSheet( const OUString& rIn )
1802 if( !SvxCSS1Parser::ParseStyleSheet( rIn ) )
1803 return false;
1805 SwPageDesc *pMasterPageDesc =
1806 m_pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_HTML, false );
1808 SvxCSS1MapEntry* pPageEntry = GetPage(OUString(), false);
1809 if( pPageEntry )
1811 // @page (affects all already existing pages)
1813 SetPageDescAttrs( pMasterPageDesc, pPageEntry->GetItemSet(),
1814 pPageEntry->GetPropertyInfo() );
1816 // For all other already existing page styles the attributes
1817 // must also be set
1819 SetPageDescAttrs( GetFirstPageDesc(), pPageEntry->GetItemSet(),
1820 pPageEntry->GetPropertyInfo() );
1821 SetPageDescAttrs( GetLeftPageDesc(), pPageEntry->GetItemSet(),
1822 pPageEntry->GetPropertyInfo() );
1823 SetPageDescAttrs( GetRightPageDesc(), pPageEntry->GetItemSet(),
1824 pPageEntry->GetPropertyInfo() );
1828 pPageEntry = GetPage( u"first"_ustr, true );
1829 if( pPageEntry )
1831 SetPageDescAttrs( GetFirstPageDesc(true), pPageEntry->GetItemSet(),
1832 pPageEntry->GetPropertyInfo() );
1833 m_bSetFirstPageDesc = true;
1836 pPageEntry = GetPage( u"right"_ustr, true );
1837 if( pPageEntry )
1839 SetPageDescAttrs( GetRightPageDesc(true), pPageEntry->GetItemSet(),
1840 pPageEntry->GetPropertyInfo() );
1841 m_bSetRightPageDesc = true;
1844 pPageEntry = GetPage( u"left"_ustr, true );
1845 if( pPageEntry )
1846 SetPageDescAttrs( GetLeftPageDesc(true), pPageEntry->GetItemSet(),
1847 pPageEntry->GetPropertyInfo() );
1849 return true;
1852 bool SwHTMLParser::ParseStyleOptions( const OUString &rStyle,
1853 const OUString &rId,
1854 const OUString &rClass,
1855 SfxItemSet &rItemSet,
1856 SvxCSS1PropertyInfo &rPropInfo,
1857 const OUString *pLang,
1858 const OUString *pDir )
1860 bool bRet = false;
1862 if( !rClass.isEmpty() )
1864 OUString aClass( rClass );
1865 SwCSS1Parser::GetScriptFromClass( aClass );
1866 const SvxCSS1MapEntry *pClass = m_pCSS1Parser->GetClass( aClass );
1867 if( pClass )
1869 SvxCSS1Parser::MergeStyles( pClass->GetItemSet(),
1870 pClass->GetPropertyInfo(),
1871 rItemSet, rPropInfo, false );
1872 bRet = true;
1876 if( !rId.isEmpty() )
1878 const SvxCSS1MapEntry *pId = m_pCSS1Parser->GetId( rId );
1879 if( pId )
1880 SvxCSS1Parser::MergeStyles( pId->GetItemSet(),
1881 pId->GetPropertyInfo(),
1882 rItemSet, rPropInfo, !rClass.isEmpty() );
1883 rPropInfo.m_aId = rId;
1884 bRet = true;
1887 if( !rStyle.isEmpty() )
1889 m_pCSS1Parser->ParseStyleOption( rStyle, rItemSet, rPropInfo );
1890 bRet = true;
1893 if( bRet )
1894 rPropInfo.SetBoxItem( rItemSet, MIN_BORDER_DIST );
1896 if( pLang && !pLang->isEmpty() )
1898 LanguageType eLang = LanguageTag::convertToLanguageTypeWithFallback( *pLang );
1899 if( LANGUAGE_DONTKNOW != eLang )
1901 SvxLanguageItem aLang( eLang, RES_CHRATR_LANGUAGE );
1902 rItemSet.Put( aLang );
1903 aLang.SetWhich( RES_CHRATR_CJK_LANGUAGE );
1904 rItemSet.Put( aLang );
1905 aLang.SetWhich( RES_CHRATR_CTL_LANGUAGE );
1906 rItemSet.Put( aLang );
1908 bRet = true;
1911 if( pDir && !pDir->isEmpty() )
1913 OUString aValue( *pDir );
1914 SvxFrameDirection eDir = SvxFrameDirection::Environment;
1915 if (aValue.equalsIgnoreAsciiCase("LTR"))
1916 eDir = SvxFrameDirection::Horizontal_LR_TB;
1917 else if (aValue.equalsIgnoreAsciiCase("RTL"))
1918 eDir = SvxFrameDirection::Horizontal_RL_TB;
1920 if( SvxFrameDirection::Environment != eDir )
1922 SvxFrameDirectionItem aDir( eDir, RES_FRAMEDIR );
1923 rItemSet.Put( aDir );
1925 bRet = true;
1929 return bRet;
1932 void SwHTMLParser::SetAnchorAndAdjustment( const SvxCSS1PropertyInfo &rPropInfo,
1933 SfxItemSet &rFrameItemSet )
1935 SwFormatAnchor aAnchor;
1937 sal_Int16 eHoriOri = text::HoriOrientation::NONE;
1938 sal_Int16 eVertOri = text::VertOrientation::NONE;
1939 sal_Int16 eHoriRel = text::RelOrientation::FRAME;
1940 sal_Int16 eVertRel = text::RelOrientation::FRAME;
1941 SwTwips nHoriPos = 0, nVertPos = 0;
1942 css::text::WrapTextMode eSurround = css::text::WrapTextMode_THROUGH;
1943 if( SVX_CSS1_POS_ABSOLUTE == rPropInfo.m_ePosition )
1945 if( SVX_CSS1_LTYPE_TWIP == rPropInfo.m_eLeftType &&
1946 SVX_CSS1_LTYPE_TWIP == rPropInfo.m_eTopType )
1948 // Absolute positioned objects are page-bound, when they
1949 // aren't in a frame and otherwise frame-bound.
1950 const SwStartNode *pFlySttNd =
1951 m_pPam->GetPoint()->GetNode().FindFlyStartNode();
1952 if( pFlySttNd )
1954 aAnchor.SetType( RndStdIds::FLY_AT_FLY );
1955 SwPosition aPos( *pFlySttNd );
1956 aAnchor.SetAnchor( &aPos );
1958 else
1960 aAnchor.SetType( RndStdIds::FLY_AT_PAGE );
1961 aAnchor.SetPageNum( 1 );
1963 nHoriPos = rPropInfo.m_nLeft;
1964 nVertPos = rPropInfo.m_nTop;
1966 else
1968 aAnchor.SetType( RndStdIds::FLY_AT_PARA );
1969 aAnchor.SetAnchor( m_pPam->GetPoint() );
1970 eVertOri = text::VertOrientation::TOP;
1971 eVertRel = text::RelOrientation::CHAR;
1972 if( SVX_CSS1_LTYPE_TWIP == rPropInfo.m_eLeftType )
1974 eHoriOri = text::HoriOrientation::NONE;
1975 eHoriRel = text::RelOrientation::PAGE_FRAME;
1976 nHoriPos = rPropInfo.m_nLeft;
1978 else
1980 eHoriOri = text::HoriOrientation::LEFT;
1981 eHoriRel = text::RelOrientation::FRAME; // to be changed later
1985 else
1987 // Flowing object are inserted as paragraph-bound, when the paragraph is
1988 // still empty and otherwise auto-bound.
1989 // Auto-bound frames for the time being inserted at the previous position
1990 // and later moved.
1991 const sal_Int32 nContent = m_pPam->GetPoint()->GetContentIndex();
1992 if( nContent )
1994 aAnchor.SetType( RndStdIds::FLY_AT_CHAR );
1995 m_pPam->Move( fnMoveBackward );
1996 eVertOri = text::VertOrientation::CHAR_BOTTOM;
1997 eVertRel = text::RelOrientation::CHAR;
1999 else
2001 aAnchor.SetType( RndStdIds::FLY_AT_PARA );
2002 eVertOri = text::VertOrientation::TOP;
2003 eVertRel = text::RelOrientation::PRINT_AREA;
2006 aAnchor.SetAnchor( m_pPam->GetPoint() );
2008 if( nContent )
2009 m_pPam->Move( fnMoveForward );
2011 sal_uInt16 nLeftSpace = 0, nRightSpace = 0;
2012 short nIndent = 0;
2013 GetMarginsFromContextWithNumberBullet( nLeftSpace, nRightSpace, nIndent );
2015 if( SvxAdjust::Right==rPropInfo.m_eFloat )
2017 eHoriOri = text::HoriOrientation::RIGHT;
2018 eHoriRel = nRightSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
2019 eSurround = css::text::WrapTextMode_LEFT;
2021 else
2023 eHoriOri = text::HoriOrientation::LEFT;
2024 eHoriRel = nLeftSpace ? text::RelOrientation::PRINT_AREA : text::RelOrientation::FRAME;
2025 eSurround = css::text::WrapTextMode_RIGHT;
2028 rFrameItemSet.Put( aAnchor );
2030 // positioned absolutely with wrap
2031 rFrameItemSet.Put( SwFormatHoriOrient( nHoriPos, eHoriOri, eHoriRel ) );
2032 rFrameItemSet.Put( SwFormatVertOrient( nVertPos, eVertOri, eVertRel ) );
2033 rFrameItemSet.Put( SwFormatSurround( eSurround ) );
2036 void SwHTMLParser::SetVarSize( SvxCSS1PropertyInfo const &rPropInfo,
2037 SfxItemSet &rFrameItemSet,
2038 SwTwips nDfltWidth, sal_uInt8 nDfltPrcWidth )
2040 SwTwips nWidth = nDfltWidth, nHeight = MINFLY;
2041 sal_uInt8 nPercentWidth = nDfltPrcWidth, nPercentHeight = 0;
2042 switch( rPropInfo.m_eWidthType )
2044 case SVX_CSS1_LTYPE_PERCENTAGE:
2045 nPercentWidth = rPropInfo.m_nWidth > 0 ? static_cast<sal_uInt8>(rPropInfo.m_nWidth) : 1;
2046 nWidth = MINFLY;
2047 break;
2048 case SVX_CSS1_LTYPE_TWIP:
2049 nWidth = std::max<tools::Long>(rPropInfo.m_nWidth, MINFLY);
2050 nPercentWidth = 0;
2051 break;
2052 default:
2055 switch( rPropInfo.m_eHeightType )
2057 case SVX_CSS1_LTYPE_PERCENTAGE:
2058 nPercentHeight = rPropInfo.m_nHeight > 0 ? static_cast<sal_uInt8>(rPropInfo.m_nHeight) : 1;
2059 break;
2060 case SVX_CSS1_LTYPE_TWIP:
2061 // Netscape and MS-IE interpreting the height incorrectly as minimum height,
2062 // therefore we are doing the same.
2063 nHeight = std::max<tools::Long>(rPropInfo.m_nHeight, MINFLY);
2064 break;
2065 default:
2069 SwFormatFrameSize aFrameSize( SwFrameSize::Minimum, nWidth, nHeight );
2070 aFrameSize.SetWidthPercent( nPercentWidth );
2071 aFrameSize.SetHeightPercent( nPercentHeight );
2072 rFrameItemSet.Put( aFrameSize );
2075 void SwHTMLParser::SetFrameFormatAttrs( SfxItemSet &rItemSet,
2076 HtmlFrameFormatFlags nFlags,
2077 SfxItemSet &rFrameItemSet )
2079 const SvxBoxItem *pBoxItem;
2080 if( (nFlags & HtmlFrameFormatFlags::Box) &&
2081 (pBoxItem = rItemSet.GetItemIfSet( RES_BOX )) )
2083 if( nFlags & HtmlFrameFormatFlags::Padding )
2085 SvxBoxItem aBoxItem( *pBoxItem );
2086 // reset all 4 sides to 0
2087 aBoxItem.SetAllDistances(0);
2088 rFrameItemSet.Put( aBoxItem );
2090 else
2092 rFrameItemSet.Put( *pBoxItem );
2094 rItemSet.ClearItem( RES_BOX );
2097 const SvxBrushItem* pBrushItem;
2098 if( (nFlags & HtmlFrameFormatFlags::Background) &&
2099 (pBrushItem = rItemSet.GetItemIfSet( RES_BACKGROUND )) )
2101 rFrameItemSet.Put( *pBrushItem );
2102 rItemSet.ClearItem( RES_BACKGROUND );
2105 const SvxFrameDirectionItem* pFrameDirectionItem;
2106 if( (nFlags & HtmlFrameFormatFlags::Direction) &&
2107 (pFrameDirectionItem = rItemSet.GetItemIfSet( RES_FRAMEDIR )) )
2109 rFrameItemSet.Put( *pFrameDirectionItem );
2110 rItemSet.ClearItem( RES_FRAMEDIR );
2114 std::unique_ptr<HTMLAttrContext> SwHTMLParser::PopContext( HtmlTokenId nToken )
2116 std::unique_ptr<HTMLAttrContext> xCntxt;
2118 HTMLAttrContexts::size_type nPos = m_aContexts.size();
2119 if( nPos <= m_nContextStMin )
2120 return nullptr;
2122 bool bFound = HtmlTokenId::NONE == nToken;
2123 if( nToken != HtmlTokenId::NONE )
2125 // search for stack entry of token ...
2126 while( nPos > m_nContextStMin )
2128 HtmlTokenId nCntxtToken = m_aContexts[--nPos]->GetToken();
2129 if( nCntxtToken == nToken )
2131 bFound = true;
2132 break;
2134 else if( nCntxtToken == HtmlTokenId::NONE ) // zero as token doesn't occur
2136 break;
2140 else
2142 nPos--;
2145 if( bFound )
2147 xCntxt = std::move(m_aContexts[nPos]);
2148 m_aContexts.erase( m_aContexts.begin() + nPos );
2151 return xCntxt;
2154 void SwHTMLParser::GetMarginsFromContext( sal_uInt16& nLeft,
2155 sal_uInt16& nRight,
2156 short& nIndent,
2157 bool bIgnoreTopContext ) const
2159 HTMLAttrContexts::size_type nPos = m_aContexts.size();
2160 if( bIgnoreTopContext )
2162 if( !nPos )
2163 return;
2164 else
2165 nPos--;
2168 while( nPos > m_nContextStAttrMin )
2170 const HTMLAttrContext *pCntxt = m_aContexts[--nPos].get();
2171 if( pCntxt->IsLRSpaceChanged() )
2173 pCntxt->GetMargins( nLeft, nRight, nIndent );
2174 return;
2179 void SwHTMLParser::GetMarginsFromContextWithNumberBullet( sal_uInt16& nLeft,
2180 sal_uInt16& nRight,
2181 short& nIndent ) const
2183 GetMarginsFromContext( nLeft, nRight, nIndent );
2184 const SwHTMLNumRuleInfo& rInfo = const_cast<SwHTMLParser*>(this)->GetNumInfo();
2185 if( rInfo.GetDepth() )
2187 sal_uInt8 nLevel = static_cast<sal_uInt8>( (rInfo.GetDepth() <= MAXLEVEL ? rInfo.GetDepth()
2188 : MAXLEVEL) - 1 );
2189 const SwNumFormat& rNumFormat = rInfo.GetNumRule()->Get(nLevel);
2190 nLeft = nLeft + rNumFormat.GetAbsLSpace(); //TODO: overflow
2191 nIndent = rNumFormat.GetFirstLineOffset(); //TODO: overflow
2195 void SwHTMLParser::GetULSpaceFromContext( sal_uInt16& nUpper,
2196 sal_uInt16& nLower ) const
2198 sal_uInt16 nDefaultColl = 0;
2199 OUString aDefaultClass;
2201 HTMLAttrContexts::size_type nPos = m_aContexts.size();
2202 while( nPos > m_nContextStAttrMin )
2204 const HTMLAttrContext *pCntxt = m_aContexts[--nPos].get();
2205 if( pCntxt->IsULSpaceChanged() )
2207 pCntxt->GetULSpace( nUpper, nLower );
2208 return;
2210 else if (!nDefaultColl)
2212 nDefaultColl = pCntxt->GetDefaultTextFormatColl();
2213 if (nDefaultColl)
2214 aDefaultClass = pCntxt->GetClass();
2218 if (!nDefaultColl)
2219 nDefaultColl = RES_POOLCOLL_TEXT;
2221 const SwTextFormatColl *pColl =
2222 m_pCSS1Parser->GetTextFormatColl(nDefaultColl, aDefaultClass);
2223 const SvxULSpaceItem& rULSpace = pColl->GetULSpace();
2224 nUpper = rULSpace.GetUpper();
2225 nLower = rULSpace.GetLower();
2228 void SwHTMLParser::EndContextAttrs( HTMLAttrContext *pContext )
2230 HTMLAttrs &rAttrs = pContext->GetAttrs();
2231 for( auto pAttr : rAttrs )
2233 if( RES_PARATR_DROP==pAttr->GetItem().Which() )
2235 // Set the number of characters for DropCaps. If it's zero at the
2236 // end, the attribute is set to invalid and then isn't set from SetAttr.
2237 sal_Int32 nChars = m_pPam->GetPoint()->GetContentIndex();
2238 if( nChars < 1 )
2239 pAttr->Invalidate();
2240 else if( nChars > MAX_DROPCAP_CHARS )
2241 nChars = MAX_DROPCAP_CHARS;
2242 static_cast<SwFormatDrop&>(pAttr->GetItem()).SetChars(static_cast<sal_uInt8>(nChars));
2245 EndAttr( pAttr );
2249 void SwHTMLParser::InsertParaAttrs( const SfxItemSet& rItemSet )
2251 SfxItemIter aIter( rItemSet );
2253 for (const SfxPoolItem* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
2255 // search for the table entry of the item...
2256 sal_uInt16 nWhich = pItem->Which();
2257 HTMLAttr **ppAttr = GetAttrTabEntry( nWhich );
2259 if( ppAttr )
2261 NewAttr(m_xAttrTab, ppAttr, *pItem);
2262 if( RES_PARATR_BEGIN > nWhich )
2263 (*ppAttr)->SetLikePara();
2264 m_aParaAttrs.push_back( *ppAttr );
2265 bool bSuccess = EndAttr( *ppAttr, false );
2266 if (!bSuccess)
2267 m_aParaAttrs.pop_back();
2272 static void lcl_swcss1_setEncoding( SwFormat& rFormat, rtl_TextEncoding eEnc )
2274 if( RTL_TEXTENCODING_DONTKNOW == eEnc )
2275 return;
2277 const SfxItemSet& rItemSet = rFormat.GetAttrSet();
2278 static const TypedWhichId<SvxFontItem> aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT,
2279 RES_CHRATR_CTL_FONT };
2280 for (auto const & i : aWhichIds)
2282 const SvxFontItem *pFontItem = rItemSet.GetItemIfSet(i, false);
2283 if (!pFontItem)
2284 continue;
2285 if (RTL_TEXTENCODING_SYMBOL == pFontItem->GetCharSet())
2286 continue;
2287 if (eEnc == pFontItem->GetCharSet())
2288 continue;
2289 SvxFontItem aFont(pFontItem->GetFamily(), pFontItem->GetFamilyName(),
2290 pFontItem->GetStyleName(), pFontItem->GetPitch(),
2291 eEnc, i);
2292 rFormat.SetFormatAttr(aFont);
2296 void SwCSS1Parser::SetDfltEncoding( rtl_TextEncoding eEnc )
2298 if( eEnc == GetDfltEncoding() )
2299 return;
2301 if( m_bIsNewDoc )
2303 // Set new encoding as pool default
2304 static const sal_uInt16 aWhichIds[3] = { RES_CHRATR_FONT, RES_CHRATR_CJK_FONT,
2305 RES_CHRATR_CTL_FONT };
2306 for(sal_uInt16 i : aWhichIds)
2308 const SvxFontItem& rDfltFont =
2309 static_cast<const SvxFontItem&>(m_pDoc->GetDefault( i));
2310 SvxFontItem aFont( rDfltFont.GetFamily(),
2311 rDfltFont.GetFamilyName(),
2312 rDfltFont.GetStyleName(),
2313 rDfltFont.GetPitch(),
2314 eEnc, i );
2315 m_pDoc->SetDefault( aFont );
2318 // Change all paragraph styles that do specify a font.
2319 for( auto pTextFormatColl : *m_pDoc->GetTextFormatColls() )
2320 lcl_swcss1_setEncoding( *pTextFormatColl, eEnc );
2322 // Change all character styles that do specify a font.
2323 for( auto pCharFormat : *m_pDoc->GetCharFormats() )
2324 lcl_swcss1_setEncoding( *pCharFormat, eEnc );
2327 SvxCSS1Parser::SetDfltEncoding( eEnc );
2330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */