crashtesting: assert on reimport of docx export of ooo102874-2.doc
[LibreOffice.git] / sw / source / filter / html / svxcss1.cxx
blob7b18efd302d7ac3cc90d0b9d6b563ad37a8f835a
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 <sal/config.h>
22 #include <algorithm>
23 #include <cmath>
24 #include <limits>
25 #include <memory>
26 #include <stdlib.h>
28 #include <svx/svxids.hrc>
29 #include <i18nlangtag/languagetag.hxx>
30 #include <svtools/ctrltool.hxx>
31 #include <svl/urihelper.hxx>
32 #include <editeng/udlnitem.hxx>
33 #include <editeng/adjustitem.hxx>
34 #include <editeng/blinkitem.hxx>
35 #include <editeng/crossedoutitem.hxx>
36 #include <editeng/kernitem.hxx>
37 #include <editeng/lspcitem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/postitem.hxx>
40 #include <editeng/colritem.hxx>
41 #include <editeng/cmapitem.hxx>
42 #include <editeng/brushitem.hxx>
43 #include <editeng/wghtitem.hxx>
44 #include <editeng/fhgtitem.hxx>
45 #include <editeng/borderline.hxx>
46 #include <editeng/boxitem.hxx>
47 #include <editeng/ulspitem.hxx>
48 #include <editeng/lrspitem.hxx>
49 #include <editeng/langitem.hxx>
50 #include <svl/itempool.hxx>
51 #include <editeng/spltitem.hxx>
52 #include <editeng/widwitem.hxx>
53 #include <editeng/frmdiritem.hxx>
54 #include <editeng/orphitem.hxx>
55 #include <utility>
56 #include <vcl/svapp.hxx>
57 #include <sal/log.hxx>
58 #include <osl/diagnose.h>
59 #include <o3tl/string_view.hxx>
61 #include <hintids.hxx>
63 #include "css1kywd.hxx"
64 #include "svxcss1.hxx"
65 #include "htmlnum.hxx"
67 using namespace ::com::sun::star;
69 /// type of functions to parse CSS1 properties
70 typedef void (*FnParseCSS1Prop)( const CSS1Expression *pExpr,
71 SfxItemSet& rItemSet,
72 SvxCSS1PropertyInfo& rPropInfo,
73 const SvxCSS1Parser& rParser );
75 CSS1PropertyEnum const aFontSizeTable[] =
77 { "xx-small", 0 },
78 { "x-small", 1 },
79 { "small", 2 },
80 { "medium", 3 },
81 { "large", 4 },
82 { "x-large", 5 },
83 { "xx-large", 6 },
84 { nullptr, 0 }
87 CSS1PropertyEnum const aFontWeightTable[] =
89 { "extra-light", WEIGHT_NORMAL }, // WEIGHT_ULTRALIGHT (OBS)
90 { "light", WEIGHT_NORMAL }, // WEIGHT_LIGHT (OBSOLETE)
91 { "demi-light", WEIGHT_NORMAL }, // WEIGHT_SEMILIGHT (OBS)
92 { "medium", WEIGHT_NORMAL }, // WEIGHT_MEDIUM (OBS)
93 { "normal", WEIGHT_NORMAL }, // WEIGHT_MEDIUM
94 { "demi-bold", WEIGHT_NORMAL }, // WEIGHT_SEMIBOLD (OBS)
95 { "bold", WEIGHT_BOLD }, // WEIGHT_BOLD (OBSOLETE)
96 { "extra-bold", WEIGHT_BOLD }, // WEIGHT_ULTRABOLD (OBS)
97 { "bolder", WEIGHT_BOLD },
98 { "lighter", WEIGHT_NORMAL },
99 { nullptr, 0 }
102 CSS1PropertyEnum const aFontStyleTable[] =
104 { "normal", ITALIC_NONE },
105 { "italic", ITALIC_NORMAL },
106 { "oblique", ITALIC_NORMAL },
107 { nullptr, 0 }
110 CSS1PropertyEnum const aFontVariantTable[] =
112 { "normal", sal_uInt16(SvxCaseMap::NotMapped) },
113 { "small-caps", sal_uInt16(SvxCaseMap::SmallCaps) },
114 { nullptr, 0 }
117 CSS1PropertyEnum const aTextTransformTable[] =
119 { "uppercase", sal_uInt16(SvxCaseMap::Uppercase) },
120 { "lowercase", sal_uInt16(SvxCaseMap::Lowercase) },
121 { "capitalize", sal_uInt16(SvxCaseMap::Capitalize) },
122 { nullptr, 0 }
125 CSS1PropertyEnum const aDirectionTable[] =
127 { "ltr", sal_uInt16(SvxFrameDirection::Horizontal_LR_TB) },
128 { "rtl", sal_uInt16(SvxFrameDirection::Horizontal_RL_TB) },
129 { "inherit", sal_uInt16(SvxFrameDirection::Environment) },
130 { nullptr, 0 }
133 CSS1PropertyEnum const aBGRepeatTable[] =
135 { "repeat", GPOS_TILED },
136 { "repeat-x", GPOS_TILED },
137 { "repeat-y", GPOS_TILED },
138 { "no-repeat", GPOS_NONE },
139 { nullptr, 0 }
142 CSS1PropertyEnum const aBGHoriPosTable[] =
144 { "left", GPOS_LT },
145 { "center", GPOS_MT },
146 { "right", GPOS_RT },
147 { nullptr, 0 }
150 CSS1PropertyEnum const aBGVertPosTable[] =
152 { "top", GPOS_LT },
153 { "middle", GPOS_LM },
154 { "bottom", GPOS_LB },
155 { nullptr, 0 }
158 CSS1PropertyEnum const aTextAlignTable[] =
160 { "left", sal_uInt16(SvxAdjust::Left) },
161 { "center", sal_uInt16(SvxAdjust::Center) },
162 { "right", sal_uInt16(SvxAdjust::Right) },
163 { "justify", sal_uInt16(SvxAdjust::Block) },
164 { nullptr, 0 }
167 CSS1PropertyEnum const aBorderWidthTable[] =
169 { "thin", 0 }, // DEF_LINE_WIDTH_0 / DEF_DOUBLE_LINE0
170 { "medium", 1 }, // DEF_LINE_WIDTH_1 / DEF_DOUBLE_LINE1
171 { "thick", 2 }, // DEF_LINE_WIDTH_2 / DEF_DOUBLE_LINE2
172 { nullptr, 0 }
175 namespace {
177 enum CSS1BorderStyle { CSS1_BS_NONE, CSS1_BS_SINGLE, CSS1_BS_DOUBLE, CSS1_BS_DOTTED, CSS1_BS_DASHED, CSS1_BS_GROOVE, CSS1_BS_RIDGE, CSS1_BS_INSET, CSS1_BS_OUTSET };
181 CSS1PropertyEnum const aBorderStyleTable[] =
183 { "none", CSS1_BS_NONE },
184 { "dotted", CSS1_BS_DOTTED },
185 { "dashed", CSS1_BS_DASHED },
186 { "solid", CSS1_BS_SINGLE },
187 { "double", CSS1_BS_DOUBLE },
188 { "groove", CSS1_BS_GROOVE },
189 { "ridge", CSS1_BS_RIDGE },
190 { "inset", CSS1_BS_INSET },
191 { "outset", CSS1_BS_OUTSET },
192 { nullptr, 0 }
195 CSS1PropertyEnum const aFloatTable[] =
197 { "left", sal_uInt16(SvxAdjust::Left) },
198 { "right", sal_uInt16(SvxAdjust::Right) },
199 { "none", sal_uInt16(SvxAdjust::End) },
200 { nullptr, 0 }
203 CSS1PropertyEnum const aPositionTable[] =
205 { "absolute", SVX_CSS1_POS_ABSOLUTE },
206 { "relative", SVX_CSS1_POS_RELATIVE },
207 { "static", SVX_CSS1_POS_STATIC },
208 { nullptr, 0 }
211 // Feature: PrintExt
212 CSS1PropertyEnum const aSizeTable[] =
214 { "auto", SVX_CSS1_STYPE_AUTO },
215 { "landscape", SVX_CSS1_STYPE_LANDSCAPE },
216 { "portrait", SVX_CSS1_STYPE_PORTRAIT },
217 { nullptr, 0 }
220 CSS1PropertyEnum const aPageBreakTable[] =
222 { "auto", SVX_CSS1_PBREAK_AUTO },
223 { "always", SVX_CSS1_PBREAK_ALWAYS },
224 { "avoid", SVX_CSS1_PBREAK_AVOID },
225 { "left", SVX_CSS1_PBREAK_LEFT },
226 { "right", SVX_CSS1_PBREAK_RIGHT },
227 { nullptr, 0 }
230 CSS1PropertyEnum const aNumberStyleTable[] =
232 { "decimal", SVX_NUM_ARABIC },
233 { "lower-alpha", SVX_NUM_CHARS_LOWER_LETTER },
234 { "lower-latin", SVX_NUM_CHARS_LOWER_LETTER },
235 { "lower-roman", SVX_NUM_ROMAN_LOWER },
236 { "upper-alpha", SVX_NUM_CHARS_UPPER_LETTER },
237 { "upper-latin", SVX_NUM_CHARS_UPPER_LETTER },
238 { "upper-roman", SVX_NUM_ROMAN_UPPER },
239 { nullptr, 0 }
242 CSS1PropertyEnum const aBulletStyleTable[] =
244 { "circle", HTML_BULLETCHAR_CIRCLE },
245 { "disc", HTML_BULLETCHAR_DISC },
246 { "square", HTML_BULLETCHAR_SQUARE },
247 { nullptr, 0 }
250 sal_uInt16 const aBorderWidths[] =
252 SvxBorderLineWidth::Hairline,
253 SvxBorderLineWidth::VeryThin,
254 SvxBorderLineWidth::Thin
257 #undef SBORDER_ENTRY
258 #undef DBORDER_ENTRY
260 namespace {
262 struct SvxCSS1ItemIds
264 sal_uInt16 nFont;
265 sal_uInt16 nFontCJK;
266 sal_uInt16 nFontCTL;
267 sal_uInt16 nPosture;
268 sal_uInt16 nPostureCJK;
269 sal_uInt16 nPostureCTL;
270 sal_uInt16 nWeight;
271 sal_uInt16 nWeightCJK;
272 sal_uInt16 nWeightCTL;
273 sal_uInt16 nFontHeight;
274 sal_uInt16 nFontHeightCJK;
275 sal_uInt16 nFontHeightCTL;
276 sal_uInt16 nUnderline;
277 sal_uInt16 nOverline;
278 sal_uInt16 nCrossedOut;
279 sal_uInt16 nColor;
280 sal_uInt16 nKerning;
281 sal_uInt16 nCaseMap;
282 sal_uInt16 nBlink;
284 sal_uInt16 nLineSpacing;
285 sal_uInt16 nAdjust;
286 sal_uInt16 nWidows;
287 sal_uInt16 nOrphans;
288 sal_uInt16 nFormatSplit;
290 // this looks a bit superfluous? TypedWhichId<SvxLRSpaceItem> nLRSpace{0};
291 TypedWhichId<SvxULSpaceItem> nULSpace{0};
292 sal_uInt16 nBox;
293 sal_uInt16 nBrush;
295 sal_uInt16 nLanguage;
296 sal_uInt16 nLanguageCJK;
297 sal_uInt16 nLanguageCTL;
298 sal_uInt16 nDirection;
303 static SvxCSS1ItemIds aItemIds;
305 struct SvxCSS1BorderInfo
307 Color aColor;
308 sal_uInt16 nAbsWidth;
309 sal_uInt16 nNamedWidth;
310 CSS1BorderStyle eStyle;
312 SvxCSS1BorderInfo() :
313 aColor( COL_BLACK ), nAbsWidth( USHRT_MAX ),
314 nNamedWidth( USHRT_MAX ), eStyle( CSS1_BS_NONE )
317 void SetBorderLine( SvxBoxItemLine nLine, SvxBoxItem &rBoxItem ) const;
320 void SvxCSS1BorderInfo::SetBorderLine( SvxBoxItemLine nLine, SvxBoxItem &rBoxItem ) const
322 if( CSS1_BS_NONE==eStyle || nAbsWidth==0 ||
323 (nAbsWidth==USHRT_MAX && nNamedWidth==USHRT_MAX) )
325 rBoxItem.SetLine( nullptr, nLine );
326 return;
329 ::editeng::SvxBorderLine aBorderLine( &aColor );
331 // Line style double or single?
332 switch ( eStyle )
334 case CSS1_BS_SINGLE:
335 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::SOLID);
336 break;
337 case CSS1_BS_DOUBLE:
338 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
339 break;
340 case CSS1_BS_DOTTED:
341 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOTTED);
342 break;
343 case CSS1_BS_DASHED:
344 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DASHED);
345 break;
346 case CSS1_BS_GROOVE:
347 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::ENGRAVED);
348 break;
349 case CSS1_BS_RIDGE:
350 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::EMBOSSED);
351 break;
352 case CSS1_BS_INSET:
353 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::INSET);
354 break;
355 case CSS1_BS_OUTSET:
356 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::OUTSET);
357 break;
358 default:
359 aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::NONE);
360 break;
363 // convert named width, if no absolute is given
364 if( nAbsWidth==USHRT_MAX )
365 aBorderLine.SetWidth( aBorderWidths[ nNamedWidth ] );
366 else
367 aBorderLine.SetWidth( nAbsWidth );
369 rBoxItem.SetLine( &aBorderLine, nLine );
372 SvxCSS1PropertyInfo::SvxCSS1PropertyInfo()
374 Clear();
377 SvxCSS1PropertyInfo::SvxCSS1PropertyInfo( const SvxCSS1PropertyInfo& rProp ) :
378 m_aId( rProp.m_aId ),
379 m_bTopMargin( rProp.m_bTopMargin ),
380 m_bBottomMargin( rProp.m_bBottomMargin ),
381 m_bLeftMargin( rProp.m_bLeftMargin ),
382 m_bRightMargin( rProp.m_bRightMargin ),
383 m_bTextIndent( rProp.m_bTextIndent ),
384 m_bNumbering ( rProp.m_bNumbering ),
385 m_bBullet ( rProp.m_bBullet ),
386 m_eFloat( rProp.m_eFloat ),
387 m_ePosition( rProp.m_ePosition ),
388 m_nTopBorderDistance( rProp.m_nTopBorderDistance ),
389 m_nBottomBorderDistance( rProp.m_nBottomBorderDistance ),
390 m_nLeftBorderDistance( rProp.m_nLeftBorderDistance ),
391 m_nRightBorderDistance( rProp.m_nRightBorderDistance ),
392 m_nNumberingType ( rProp.m_nNumberingType ),
393 m_cBulletChar( rProp.m_cBulletChar ),
394 m_nColumnCount( rProp.m_nColumnCount ),
395 m_nLeft( rProp.m_nLeft ),
396 m_nTop( rProp.m_nTop ),
397 m_nWidth( rProp.m_nWidth ),
398 m_nHeight( rProp.m_nHeight ),
399 m_nLeftMargin( rProp.m_nLeftMargin ),
400 m_nRightMargin( rProp.m_nRightMargin ),
401 m_eLeftType( rProp.m_eLeftType ),
402 m_eTopType( rProp.m_eTopType ),
403 m_eWidthType( rProp.m_eWidthType ),
404 m_eHeightType( rProp.m_eHeightType ),
405 m_eLeftMarginType( rProp.m_eLeftMarginType ),
406 m_eRightMarginType( rProp.m_eRightMarginType ),
407 m_eSizeType( rProp.m_eSizeType ),
408 m_ePageBreakBefore( rProp.m_ePageBreakBefore ),
409 m_ePageBreakAfter( rProp.m_ePageBreakAfter )
411 for( size_t i=0; i<m_aBorderInfos.size(); ++i )
412 if (rProp.m_aBorderInfos[i])
413 m_aBorderInfos[i].reset( new SvxCSS1BorderInfo( *rProp.m_aBorderInfos[i] ) );
416 SvxCSS1PropertyInfo::~SvxCSS1PropertyInfo()
420 void SvxCSS1PropertyInfo::DestroyBorderInfos()
422 for(auto & rp : m_aBorderInfos)
423 rp.reset();
426 void SvxCSS1PropertyInfo::Clear()
428 m_aId.clear();
429 m_bTopMargin = m_bBottomMargin = false;
430 m_bLeftMargin = m_bRightMargin = m_bTextIndent = false;
431 m_bNumbering = m_bBullet = false;
432 m_nLeftMargin = m_nRightMargin = 0;
433 m_eFloat = SvxAdjust::End;
435 m_ePosition = SVX_CSS1_POS_NONE;
436 m_nTopBorderDistance = m_nBottomBorderDistance =
437 m_nLeftBorderDistance = m_nRightBorderDistance = UNSET_BORDER_DISTANCE;
439 m_nNumberingType = SVX_NUM_CHARS_UPPER_LETTER;
440 m_cBulletChar = ' ';
442 m_nColumnCount = 0;
444 m_nLeft = m_nTop = m_nWidth = m_nHeight = 0;
445 m_eLeftType = m_eTopType = m_eWidthType = m_eHeightType = SVX_CSS1_LTYPE_NONE;
446 m_eLeftMarginType = SVX_CSS1_LTYPE_NONE;
447 m_eRightMarginType = SVX_CSS1_LTYPE_NONE;
449 // Feature: PrintExt
450 m_eSizeType = SVX_CSS1_STYPE_NONE;
451 m_ePageBreakBefore = SVX_CSS1_PBREAK_NONE;
452 m_ePageBreakAfter = SVX_CSS1_PBREAK_NONE;
454 DestroyBorderInfos();
457 void SvxCSS1PropertyInfo::Merge( const SvxCSS1PropertyInfo& rProp )
459 if( rProp.m_bTopMargin )
460 m_bTopMargin = true;
461 if( rProp.m_bBottomMargin )
462 m_bBottomMargin = true;
464 if( rProp.m_bLeftMargin )
466 m_bLeftMargin = true;
467 m_nLeftMargin = rProp.m_nLeftMargin;
469 if( rProp.m_bRightMargin )
471 m_bRightMargin = true;
472 m_nRightMargin = rProp.m_nRightMargin;
474 if( rProp.m_bTextIndent )
475 m_bTextIndent = true;
477 for( size_t i=0; i<m_aBorderInfos.size(); ++i )
479 if( rProp.m_aBorderInfos[i] )
480 m_aBorderInfos[i].reset( new SvxCSS1BorderInfo( *rProp.m_aBorderInfos[i] ) );
483 if( UNSET_BORDER_DISTANCE != rProp.m_nTopBorderDistance )
484 m_nTopBorderDistance = rProp.m_nTopBorderDistance;
485 if( UNSET_BORDER_DISTANCE != rProp.m_nBottomBorderDistance )
486 m_nBottomBorderDistance = rProp.m_nBottomBorderDistance;
487 if( UNSET_BORDER_DISTANCE != rProp.m_nLeftBorderDistance )
488 m_nLeftBorderDistance = rProp.m_nLeftBorderDistance;
489 if( UNSET_BORDER_DISTANCE != rProp.m_nRightBorderDistance )
490 m_nRightBorderDistance = rProp.m_nRightBorderDistance;
492 m_nColumnCount = rProp.m_nColumnCount;
494 if( rProp.m_eFloat != SvxAdjust::End )
495 m_eFloat = rProp.m_eFloat;
497 if( rProp.m_ePosition != SVX_CSS1_POS_NONE )
498 m_ePosition = rProp.m_ePosition;
500 // Feature: PrintExt
501 if( rProp.m_eSizeType != SVX_CSS1_STYPE_NONE )
503 m_eSizeType = rProp.m_eSizeType;
504 m_nWidth = rProp.m_nWidth;
505 m_nHeight = rProp.m_nHeight;
508 if( rProp.m_ePageBreakBefore != SVX_CSS1_PBREAK_NONE )
509 m_ePageBreakBefore = rProp.m_ePageBreakBefore;
511 if( rProp.m_ePageBreakAfter != SVX_CSS1_PBREAK_NONE )
512 m_ePageBreakAfter = rProp.m_ePageBreakAfter;
514 if( rProp.m_eLeftType != SVX_CSS1_LTYPE_NONE )
516 m_eLeftType = rProp.m_eLeftType;
517 m_nLeft = rProp.m_nLeft;
520 if( rProp.m_eTopType != SVX_CSS1_LTYPE_NONE )
522 m_eTopType = rProp.m_eTopType;
523 m_nTop = rProp.m_nTop;
526 if( rProp.m_eWidthType != SVX_CSS1_LTYPE_NONE )
528 m_eWidthType = rProp.m_eWidthType;
529 m_nWidth = rProp.m_nWidth;
532 if( rProp.m_eHeightType != SVX_CSS1_LTYPE_NONE )
534 m_eHeightType = rProp.m_eHeightType;
535 m_nHeight = rProp.m_nHeight;
539 SvxCSS1BorderInfo *SvxCSS1PropertyInfo::GetBorderInfo( SvxBoxItemLine nLine, bool bCreate )
541 sal_uInt16 nPos = 0;
542 switch( nLine )
544 case SvxBoxItemLine::TOP: nPos = 0; break;
545 case SvxBoxItemLine::BOTTOM: nPos = 1; break;
546 case SvxBoxItemLine::LEFT: nPos = 2; break;
547 case SvxBoxItemLine::RIGHT: nPos = 3; break;
550 if( !m_aBorderInfos[nPos] && bCreate )
551 m_aBorderInfos[nPos].reset( new SvxCSS1BorderInfo );
553 return m_aBorderInfos[nPos].get();
556 void SvxCSS1PropertyInfo::CopyBorderInfo( SvxBoxItemLine nSrcLine, SvxBoxItemLine nDstLine,
557 sal_uInt16 nWhat )
559 SvxCSS1BorderInfo *pSrcInfo = GetBorderInfo( nSrcLine, false );
560 if( !pSrcInfo )
561 return;
563 SvxCSS1BorderInfo *pDstInfo = GetBorderInfo( nDstLine );
564 if( (nWhat & SVX_CSS1_BORDERINFO_WIDTH) != 0 )
566 pDstInfo->nAbsWidth = pSrcInfo->nAbsWidth;
567 pDstInfo->nNamedWidth = pSrcInfo->nNamedWidth;
570 if( (nWhat & SVX_CSS1_BORDERINFO_COLOR) != 0 )
571 pDstInfo->aColor = pSrcInfo->aColor;
573 if( (nWhat & SVX_CSS1_BORDERINFO_STYLE) != 0 )
574 pDstInfo->eStyle = pSrcInfo->eStyle;
577 void SvxCSS1PropertyInfo::CopyBorderInfo( sal_uInt16 nCount, sal_uInt16 nWhat )
579 if( nCount==0 )
581 CopyBorderInfo( SvxBoxItemLine::BOTTOM, SvxBoxItemLine::TOP, nWhat );
582 CopyBorderInfo( SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT, nWhat );
584 if( nCount<=1 )
586 CopyBorderInfo( SvxBoxItemLine::LEFT, SvxBoxItemLine::RIGHT, nWhat );
590 void SvxCSS1PropertyInfo::SetBoxItem( SfxItemSet& rItemSet,
591 sal_uInt16 nMinBorderDist,
592 const SvxBoxItem *pDfltItem )
594 bool bChg = m_nTopBorderDistance != UNSET_BORDER_DISTANCE ||
595 m_nBottomBorderDistance != UNSET_BORDER_DISTANCE ||
596 m_nLeftBorderDistance != UNSET_BORDER_DISTANCE ||
597 m_nRightBorderDistance != UNSET_BORDER_DISTANCE;
599 for( size_t i=0; !bChg && i<m_aBorderInfos.size(); ++i )
600 bChg = m_aBorderInfos[i]!=nullptr;
602 if( !bChg )
603 return;
605 std::shared_ptr<SvxBoxItem> aBoxItem(std::make_shared<SvxBoxItem>(aItemIds.nBox));
606 if( pDfltItem )
607 aBoxItem.reset(pDfltItem->Clone());
609 SvxCSS1BorderInfo *pInfo = GetBorderInfo( SvxBoxItemLine::TOP, false );
610 if( pInfo )
611 pInfo->SetBorderLine( SvxBoxItemLine::TOP, *aBoxItem );
613 pInfo = GetBorderInfo( SvxBoxItemLine::BOTTOM, false );
614 if( pInfo )
615 pInfo->SetBorderLine( SvxBoxItemLine::BOTTOM, *aBoxItem );
617 pInfo = GetBorderInfo( SvxBoxItemLine::LEFT, false );
618 if( pInfo )
619 pInfo->SetBorderLine( SvxBoxItemLine::LEFT, *aBoxItem );
621 pInfo = GetBorderInfo( SvxBoxItemLine::RIGHT, false );
622 if( pInfo )
623 pInfo->SetBorderLine( SvxBoxItemLine::RIGHT, *aBoxItem );
625 for( size_t i=0; i<m_aBorderInfos.size(); ++i )
627 SvxBoxItemLine nLine = SvxBoxItemLine::TOP;
628 sal_uInt16 nDist = 0;
629 switch( i )
631 case 0: nLine = SvxBoxItemLine::TOP;
632 nDist = m_nTopBorderDistance;
633 m_nTopBorderDistance = UNSET_BORDER_DISTANCE;
634 break;
635 case 1: nLine = SvxBoxItemLine::BOTTOM;
636 nDist = m_nBottomBorderDistance;
637 m_nBottomBorderDistance = UNSET_BORDER_DISTANCE;
638 break;
639 case 2: nLine = SvxBoxItemLine::LEFT;
640 nDist = m_nLeftBorderDistance;
641 m_nLeftBorderDistance = UNSET_BORDER_DISTANCE;
642 break;
643 case 3: nLine = SvxBoxItemLine::RIGHT;
644 nDist = m_nRightBorderDistance;
645 m_nRightBorderDistance = UNSET_BORDER_DISTANCE;
646 break;
649 if( aBoxItem->GetLine( nLine ) )
651 if( UNSET_BORDER_DISTANCE == nDist )
652 nDist = aBoxItem->GetDistance( nLine );
654 if( nDist < nMinBorderDist )
655 nDist = nMinBorderDist;
657 else
659 nDist = 0U;
662 aBoxItem->SetDistance( nDist, nLine );
665 rItemSet.Put( *aBoxItem );
667 DestroyBorderInfos();
670 SvxCSS1MapEntry::SvxCSS1MapEntry( SfxItemSet aItemSet,
671 const SvxCSS1PropertyInfo& rProp ) :
672 m_aItemSet(std::move( aItemSet )),
673 m_aPropInfo( rProp )
676 void SvxCSS1Parser::StyleParsed( const CSS1Selector * /*pSelector*/,
677 SfxItemSet& /*rItemSet*/,
678 SvxCSS1PropertyInfo& /*rPropInfo*/ )
680 // you see nothing is happening here
683 void SvxCSS1Parser::SelectorParsed( std::unique_ptr<CSS1Selector> pSelector, bool bFirst )
685 if( bFirst )
687 OSL_ENSURE( m_pSheetItemSet, "Where is the Item-Set for Style-Sheets?" );
689 for (const std::unique_ptr<CSS1Selector> & rpSelection : m_Selectors)
691 StyleParsed(rpSelection.get(), *m_pSheetItemSet, *m_pSheetPropInfo);
693 m_pSheetItemSet->ClearItem();
694 m_pSheetPropInfo->Clear();
696 // prepare the next rule
697 m_Selectors.clear();
700 m_Selectors.push_back(std::move(pSelector));
703 SvxCSS1Parser::SvxCSS1Parser( SfxItemPool& rPool, OUString aBaseURL,
704 sal_uInt16 const *pWhichIds, sal_uInt16 nWhichIds ) :
705 m_sBaseURL(std::move( aBaseURL )),
706 m_pItemSet(nullptr),
707 m_pPropInfo( nullptr ),
708 m_eDefaultEnc( RTL_TEXTENCODING_DONTKNOW ),
709 m_bIgnoreFontFamily( false )
711 // also initialize item IDs
712 auto initTrueWhich = [&rPool, this](sal_uInt16 rWid)
714 rWid = rPool.GetTrueWhichIDFromSlotID(rWid, false);
715 m_aWhichMap = m_aWhichMap.MergeRange(rWid, rWid);
716 return rWid;
719 aItemIds.nFont = initTrueWhich( SID_ATTR_CHAR_FONT );
720 aItemIds.nFontCJK = initTrueWhich( SID_ATTR_CHAR_CJK_FONT );
721 aItemIds.nFontCTL = initTrueWhich( SID_ATTR_CHAR_CTL_FONT );
722 aItemIds.nPosture = initTrueWhich( SID_ATTR_CHAR_POSTURE );
723 aItemIds.nPostureCJK = initTrueWhich( SID_ATTR_CHAR_CJK_POSTURE );
724 aItemIds.nPostureCTL = initTrueWhich( SID_ATTR_CHAR_CTL_POSTURE );
725 aItemIds.nWeight = initTrueWhich( SID_ATTR_CHAR_WEIGHT );
726 aItemIds.nWeightCJK = initTrueWhich( SID_ATTR_CHAR_CJK_WEIGHT );
727 aItemIds.nWeightCTL = initTrueWhich( SID_ATTR_CHAR_CTL_WEIGHT );
728 aItemIds.nFontHeight = initTrueWhich( SID_ATTR_CHAR_FONTHEIGHT );
729 aItemIds.nFontHeightCJK = initTrueWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT );
730 aItemIds.nFontHeightCTL = initTrueWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT );
731 aItemIds.nUnderline = initTrueWhich( SID_ATTR_CHAR_UNDERLINE );
732 aItemIds.nOverline = initTrueWhich( SID_ATTR_CHAR_OVERLINE );
733 aItemIds.nCrossedOut = initTrueWhich( SID_ATTR_CHAR_STRIKEOUT );
734 aItemIds.nColor = initTrueWhich( SID_ATTR_CHAR_COLOR );
735 aItemIds.nKerning = initTrueWhich( SID_ATTR_CHAR_KERNING );
736 aItemIds.nCaseMap = initTrueWhich( SID_ATTR_CHAR_CASEMAP );
737 aItemIds.nBlink = initTrueWhich( SID_ATTR_FLASH );
739 aItemIds.nLineSpacing = initTrueWhich( SID_ATTR_PARA_LINESPACE );
740 aItemIds.nAdjust = initTrueWhich( SID_ATTR_PARA_ADJUST );
741 aItemIds.nWidows = initTrueWhich( SID_ATTR_PARA_WIDOWS );
742 aItemIds.nOrphans = initTrueWhich( SID_ATTR_PARA_ORPHANS );
743 aItemIds.nFormatSplit = initTrueWhich( SID_ATTR_PARA_SPLIT );
745 // every id that is used must be added
746 m_aWhichMap = m_aWhichMap.MergeRange(RES_MARGIN_FIRSTLINE, RES_MARGIN_FIRSTLINE);
747 m_aWhichMap = m_aWhichMap.MergeRange(RES_MARGIN_TEXTLEFT, RES_MARGIN_TEXTLEFT);
748 m_aWhichMap = m_aWhichMap.MergeRange(RES_MARGIN_RIGHT, RES_MARGIN_RIGHT);
749 aItemIds.nULSpace = TypedWhichId<SvxULSpaceItem>(initTrueWhich( SID_ATTR_ULSPACE ));
750 aItemIds.nBox = initTrueWhich( SID_ATTR_BORDER_OUTER );
751 aItemIds.nBrush = initTrueWhich( SID_ATTR_BRUSH );
753 aItemIds.nLanguage = initTrueWhich( SID_ATTR_CHAR_LANGUAGE );
754 aItemIds.nLanguageCJK = initTrueWhich( SID_ATTR_CHAR_CJK_LANGUAGE );
755 aItemIds.nLanguageCTL = initTrueWhich( SID_ATTR_CHAR_CTL_LANGUAGE );
756 aItemIds.nDirection = initTrueWhich( SID_ATTR_FRAMEDIRECTION );
758 if( pWhichIds && nWhichIds )
759 for (sal_uInt16 i = 0; i < nWhichIds; ++i)
760 m_aWhichMap = m_aWhichMap.MergeRange(pWhichIds[i], pWhichIds[i]);
762 m_pSheetItemSet.reset( new SfxItemSet( rPool, m_aWhichMap ) );
763 m_pSheetPropInfo.reset( new SvxCSS1PropertyInfo );
766 SvxCSS1Parser::~SvxCSS1Parser()
768 m_pSheetItemSet.reset();
769 m_pSheetPropInfo.reset();
772 void SvxCSS1Parser::InsertId( const OUString& rId,
773 const SfxItemSet& rItemSet,
774 const SvxCSS1PropertyInfo& rProp )
776 InsertMapEntry( rId, rItemSet, rProp, m_Ids );
779 const SvxCSS1MapEntry* SvxCSS1Parser::GetId( const OUString& rId ) const
781 CSS1Map::const_iterator itr = m_Ids.find(rId);
782 return itr == m_Ids.end() ? nullptr : itr->second.get();
785 void SvxCSS1Parser::InsertClass( const OUString& rClass,
786 const SfxItemSet& rItemSet,
787 const SvxCSS1PropertyInfo& rProp )
789 InsertMapEntry( rClass, rItemSet, rProp, m_Classes );
792 const SvxCSS1MapEntry* SvxCSS1Parser::GetClass( const OUString& rClass ) const
794 CSS1Map::const_iterator itr = m_Classes.find(rClass);
795 return itr == m_Classes.end() ? nullptr : itr->second.get();
798 void SvxCSS1Parser::InsertPage( const OUString& rPage,
799 bool bPseudo,
800 const SfxItemSet& rItemSet,
801 const SvxCSS1PropertyInfo& rProp )
803 OUString aKey( rPage );
804 if( bPseudo )
805 aKey = ":" + aKey;
806 InsertMapEntry( aKey, rItemSet, rProp, m_Pages );
809 SvxCSS1MapEntry* SvxCSS1Parser::GetPage( const OUString& rPage, bool bPseudo )
811 OUString aKey( rPage );
812 if( bPseudo )
813 aKey = ":" + aKey;
815 CSS1Map::iterator itr = m_Pages.find(aKey);
816 return itr == m_Pages.end() ? nullptr : itr->second.get();
819 void SvxCSS1Parser::InsertTag( const OUString& rTag,
820 const SfxItemSet& rItemSet,
821 const SvxCSS1PropertyInfo& rProp )
823 InsertMapEntry( rTag, rItemSet, rProp, m_Tags );
826 SvxCSS1MapEntry* SvxCSS1Parser::GetTag( const OUString& rTag )
828 CSS1Map::iterator itr = m_Tags.find(rTag);
829 return itr == m_Tags.end() ? nullptr : itr->second.get();
832 bool SvxCSS1Parser::ParseStyleSheet( const OUString& rIn )
834 m_pItemSet = m_pSheetItemSet.get();
835 m_pPropInfo = m_pSheetPropInfo.get();
837 CSS1Parser::ParseStyleSheet( rIn );
839 for (const std::unique_ptr<CSS1Selector> & rpSelector : m_Selectors)
841 StyleParsed(rpSelector.get(), *m_pSheetItemSet, *m_pSheetPropInfo);
844 // and clean up a little bit
845 m_Selectors.clear();
846 m_pSheetItemSet->ClearItem();
847 m_pSheetPropInfo->Clear();
849 m_pItemSet = nullptr;
850 m_pPropInfo = nullptr;
852 return true;
855 void SvxCSS1Parser::ParseStyleOption( const OUString& rIn,
856 SfxItemSet& rItemSet,
857 SvxCSS1PropertyInfo& rPropInfo )
859 m_pItemSet = &rItemSet;
860 m_pPropInfo = &rPropInfo;
862 CSS1Parser::ParseStyleOption( rIn );
863 rItemSet.ClearItem( aItemIds.nDirection );
865 m_pItemSet = nullptr;
866 m_pPropInfo = nullptr;
869 bool SvxCSS1Parser::GetEnum( const CSS1PropertyEnum *pPropTable,
870 std::u16string_view rValue, sal_uInt16& rEnum )
872 while( pPropTable->pName )
874 if( !o3tl::equalsIgnoreAsciiCase( rValue, pPropTable->pName ) )
875 pPropTable++;
876 else
877 break;
880 if( pPropTable->pName )
881 rEnum = pPropTable->nEnum;
883 return (pPropTable->pName != nullptr);
886 void SvxCSS1Parser::PixelToTwip( tools::Long &rWidth, tools::Long &rHeight )
888 rWidth = o3tl::convert(rWidth, o3tl::Length::px, o3tl::Length::twip);
889 rHeight = o3tl::convert(rHeight, o3tl::Length::px, o3tl::Length::twip);
892 sal_uInt32 SvxCSS1Parser::GetFontHeight( sal_uInt16 nSize ) const
894 sal_uInt16 nHeight;
896 switch( nSize )
898 case 0: nHeight = 8*20; break;
899 case 1: nHeight = 10*20; break;
900 case 2: nHeight = 11*20; break;
901 case 3: nHeight = 12*20; break;
902 case 4: nHeight = 17*20; break;
903 case 5: nHeight = 20*20; break;
904 case 6:
905 default: nHeight = 32*20; break;
908 return nHeight;
911 const FontList *SvxCSS1Parser::GetFontList() const
913 return nullptr;
916 void SvxCSS1Parser::InsertMapEntry( const OUString& rKey,
917 const SfxItemSet& rItemSet,
918 const SvxCSS1PropertyInfo& rProp,
919 CSS1Map& rMap )
921 auto [itr,inserted] = rMap.insert(std::make_pair(rKey, nullptr));
922 if (inserted)
923 itr->second = std::make_unique<SvxCSS1MapEntry>(rItemSet, rProp);
924 else
926 SvxCSS1MapEntry *const p = itr->second.get();
927 MergeStyles( rItemSet, rProp,
928 p->GetItemSet(), p->GetPropertyInfo(), true );
932 void SvxCSS1Parser::MergeStyles( const SfxItemSet& rSrcSet,
933 const SvxCSS1PropertyInfo& rSrcInfo,
934 SfxItemSet& rTargetSet,
935 SvxCSS1PropertyInfo& rTargetInfo,
936 bool bSmart )
938 if( !bSmart )
940 rTargetSet.Put( rSrcSet );
942 else
944 // not sure if this is really necessary?
945 SfxItemSet copy(rSrcSet);
946 if (!rSrcInfo.m_bTextIndent)
948 copy.ClearItem(RES_MARGIN_FIRSTLINE);
950 if (!rSrcInfo.m_bLeftMargin)
952 copy.ClearItem(RES_MARGIN_TEXTLEFT);
954 if (!rSrcInfo.m_bRightMargin)
956 copy.ClearItem(RES_MARGIN_RIGHT);
959 SvxULSpaceItem aULSpace( rTargetSet.Get(aItemIds.nULSpace) );
961 rTargetSet.Put(copy);
963 if( rSrcInfo.m_bTopMargin || rSrcInfo.m_bBottomMargin )
965 const SvxULSpaceItem& rNewULSpace = rSrcSet.Get( aItemIds.nULSpace );
967 if( rSrcInfo.m_bTopMargin )
968 aULSpace.SetUpper( rNewULSpace.GetUpper() );
969 if( rSrcInfo.m_bBottomMargin )
970 aULSpace.SetLower( rNewULSpace.GetLower() );
972 rTargetSet.Put( aULSpace );
976 rTargetInfo.Merge( rSrcInfo );
979 void SvxCSS1Parser::SetDfltEncoding( rtl_TextEncoding eEnc )
981 m_eDefaultEnc = eEnc;
984 static void ParseCSS1_font_size( const CSS1Expression *pExpr,
985 SfxItemSet &rItemSet,
986 SvxCSS1PropertyInfo& /*rPropInfo*/,
987 const SvxCSS1Parser& rParser )
989 assert(pExpr && "no expression");
991 sal_uLong nHeight = 0;
992 sal_uInt16 nPropHeight = 100;
994 switch( pExpr->GetType() )
996 case CSS1_LENGTH:
997 nHeight = pExpr->GetULength();
998 break;
999 case CSS1_PIXLENGTH:
1001 double fHeight = pExpr->GetNumber();
1002 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
1004 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
1005 tools::Long nPWidth = 0;
1006 SvxCSS1Parser::PixelToTwip(nPWidth, nPHeight);
1007 nHeight = static_cast<sal_uLong>(nPHeight);
1009 else
1011 SAL_WARN("sw.html", "out-of-size pxlength: " << fHeight);
1014 break;
1015 case CSS1_PERCENTAGE:
1016 // only for drop caps!
1017 nPropHeight = o3tl::narrowing<sal_uInt16>(pExpr->GetNumber());
1018 break;
1019 case CSS1_IDENT:
1021 sal_uInt16 nSize;
1023 if( SvxCSS1Parser::GetEnum( aFontSizeTable, pExpr->GetString(),
1024 nSize ) )
1026 nHeight = rParser.GetFontHeight( nSize );
1029 break;
1031 default:
1035 if( nHeight || nPropHeight!=100 )
1037 SvxFontHeightItem aFontHeight( nHeight, nPropHeight,
1038 aItemIds.nFontHeight );
1039 rItemSet.Put( aFontHeight );
1040 aFontHeight.SetWhich( aItemIds.nFontHeightCJK );
1041 rItemSet.Put( aFontHeight );
1042 aFontHeight.SetWhich( aItemIds.nFontHeightCTL );
1043 rItemSet.Put( aFontHeight );
1047 static void ParseCSS1_font_family( const CSS1Expression *pExpr,
1048 SfxItemSet &rItemSet,
1049 SvxCSS1PropertyInfo& /*rPropInfo*/,
1050 const SvxCSS1Parser& rParser )
1052 OSL_ENSURE( pExpr, "no expression" );
1054 OUStringBuffer aName;
1055 rtl_TextEncoding eEnc = rParser.GetDfltEncoding();
1056 const FontList *pFList = rParser.GetFontList();
1057 bool bFirst = true;
1058 bool bFound = false;
1059 while( pExpr && (bFirst || ','==pExpr->GetOp() || !pExpr->GetOp()) )
1061 CSS1Token eType = pExpr->GetType();
1062 if( CSS1_IDENT==eType || CSS1_STRING==eType )
1064 OUString aIdent( pExpr->GetString() );
1066 if( CSS1_IDENT==eType )
1068 // Collect all following IDs and append them with a space
1069 const CSS1Expression *pNext = pExpr->GetNext();
1070 while( pNext && !pNext->GetOp() &&
1071 CSS1_IDENT==pNext->GetType() )
1073 aIdent += " " + pNext->GetString();
1074 pExpr = pNext;
1075 pNext = pExpr->GetNext();
1078 if( !aIdent.isEmpty() )
1080 if( !bFound && pFList )
1082 sal_Handle hFont = pFList->GetFirstFontMetric( aIdent );
1083 if( nullptr != hFont )
1085 const FontMetric& rFMetric = FontList::GetFontMetric( hFont );
1086 if( RTL_TEXTENCODING_DONTKNOW != rFMetric.GetCharSet() )
1088 bFound = true;
1089 if( RTL_TEXTENCODING_SYMBOL == rFMetric.GetCharSet() )
1090 eEnc = RTL_TEXTENCODING_SYMBOL;
1094 if( !bFirst )
1095 aName.append(";");
1096 aName.append(aIdent);
1100 pExpr = pExpr->GetNext();
1101 bFirst = false;
1104 if( !aName.isEmpty() && !rParser.IsIgnoreFontFamily() )
1106 SvxFontItem aFont( FAMILY_DONTKNOW, aName.makeStringAndClear(), OUString(), PITCH_DONTKNOW,
1107 eEnc, aItemIds.nFont );
1108 rItemSet.Put( aFont );
1109 aFont.SetWhich( aItemIds.nFontCJK );
1110 rItemSet.Put( aFont );
1111 aFont.SetWhich( aItemIds.nFontCTL );
1112 rItemSet.Put( aFont );
1116 static void ParseCSS1_font_weight( const CSS1Expression *pExpr,
1117 SfxItemSet &rItemSet,
1118 SvxCSS1PropertyInfo& /*rPropInfo*/,
1119 const SvxCSS1Parser& /*rParser*/ )
1121 assert(pExpr && "no expression");
1123 switch( pExpr->GetType() )
1125 case CSS1_IDENT:
1126 case CSS1_STRING: // MS-IE, what else
1128 sal_uInt16 nWeight;
1129 if( SvxCSS1Parser::GetEnum( aFontWeightTable, pExpr->GetString(),
1130 nWeight ) )
1132 SvxWeightItem aWeight( static_cast<FontWeight>(nWeight), aItemIds.nWeight );
1133 rItemSet.Put( aWeight );
1134 aWeight.SetWhich( aItemIds.nWeightCJK );
1135 rItemSet.Put( aWeight );
1136 aWeight.SetWhich( aItemIds.nWeightCTL );
1137 rItemSet.Put( aWeight );
1140 break;
1141 case CSS1_NUMBER:
1143 sal_uInt16 nWeight = o3tl::narrowing<sal_uInt16>(pExpr->GetNumber());
1144 SvxWeightItem aWeight( nWeight>400 ? WEIGHT_BOLD : WEIGHT_NORMAL,
1145 aItemIds.nWeight );
1146 rItemSet.Put( aWeight );
1147 aWeight.SetWhich( aItemIds.nWeightCJK );
1148 rItemSet.Put( aWeight );
1149 aWeight.SetWhich( aItemIds.nWeightCTL );
1150 rItemSet.Put( aWeight );
1152 break;
1154 default:
1159 static void ParseCSS1_font_style( const CSS1Expression *pExpr,
1160 SfxItemSet &rItemSet,
1161 SvxCSS1PropertyInfo& /*rPropInfo*/,
1162 const SvxCSS1Parser& /*rParser*/ )
1164 OSL_ENSURE( pExpr, "no expression" );
1166 bool bPosture = false;
1167 bool bCaseMap = false;
1168 FontItalic eItalic = ITALIC_NONE;
1169 SvxCaseMap eCaseMap = SvxCaseMap::NotMapped;
1171 // normal | italic || small-caps | oblique || small-caps | small-caps
1172 // (only normal, italic and oblique are valid)
1174 // the value can have two values!
1175 for( int i=0; pExpr && i<2; ++i )
1177 // also here MS-IE parser leaves traces
1178 if( (CSS1_IDENT==pExpr->GetType() || CSS1_STRING==pExpr->GetType()) &&
1179 !pExpr->GetOp() )
1181 const OUString& rValue = pExpr->GetString();
1182 // first check if the value is italic or 'normal'
1183 sal_uInt16 nItalic;
1184 if( SvxCSS1Parser::GetEnum( aFontStyleTable, rValue, nItalic ) )
1186 eItalic = static_cast<FontItalic>(nItalic);
1187 if( !bCaseMap && ITALIC_NONE==eItalic )
1189 // for 'normal' we must also exclude case-map
1190 eCaseMap = SvxCaseMap::NotMapped;
1191 bCaseMap = true;
1193 bPosture = true;
1195 else if( !bCaseMap &&
1196 rValue.equalsIgnoreAsciiCase( "small-caps" ) )
1198 eCaseMap = SvxCaseMap::SmallCaps;
1199 bCaseMap = true;
1203 // fetch next expression
1204 pExpr = pExpr->GetNext();
1207 if( bPosture )
1209 SvxPostureItem aPosture( eItalic, aItemIds.nPosture );
1210 rItemSet.Put( aPosture );
1211 aPosture.SetWhich( aItemIds.nPostureCJK );
1212 rItemSet.Put( aPosture );
1213 aPosture.SetWhich( aItemIds.nPostureCTL );
1214 rItemSet.Put( aPosture );
1217 if( bCaseMap )
1218 rItemSet.Put( SvxCaseMapItem( eCaseMap, aItemIds.nCaseMap ) );
1221 static void ParseCSS1_font_variant( const CSS1Expression *pExpr,
1222 SfxItemSet &rItemSet,
1223 SvxCSS1PropertyInfo& /*rPropInfo*/,
1224 const SvxCSS1Parser& /*rParser*/ )
1226 assert(pExpr && "no expression");
1228 // normal | small-caps
1229 switch( pExpr->GetType() )
1231 case CSS1_IDENT:
1233 sal_uInt16 nCaseMap;
1234 if( SvxCSS1Parser::GetEnum( aFontVariantTable, pExpr->GetString(),
1235 nCaseMap ) )
1237 rItemSet.Put( SvxCaseMapItem( static_cast<SvxCaseMap>(nCaseMap),
1238 aItemIds.nCaseMap ) );
1240 break;
1242 default:
1243 break;
1247 static void ParseCSS1_text_transform( const CSS1Expression *pExpr,
1248 SfxItemSet &rItemSet,
1249 SvxCSS1PropertyInfo& /*rPropInfo*/,
1250 const SvxCSS1Parser& /*rParser*/ )
1252 assert(pExpr && "no expression");
1254 // none | capitalize | uppercase | lowercase
1256 switch( pExpr->GetType() )
1258 case CSS1_IDENT:
1260 sal_uInt16 nCaseMap;
1261 if( SvxCSS1Parser::GetEnum( aTextTransformTable, pExpr->GetString(),
1262 nCaseMap ) )
1264 rItemSet.Put( SvxCaseMapItem( static_cast<SvxCaseMap>(nCaseMap),
1265 aItemIds.nCaseMap ) );
1267 break;
1269 default:
1270 break;
1274 static void ParseCSS1_color( const CSS1Expression *pExpr,
1275 SfxItemSet &rItemSet,
1276 SvxCSS1PropertyInfo& /*rPropInfo*/,
1277 const SvxCSS1Parser& /*rParser*/ )
1279 assert(pExpr && "no expression");
1281 switch( pExpr->GetType() )
1283 case CSS1_IDENT:
1284 case CSS1_RGB:
1285 case CSS1_HEXCOLOR:
1286 case CSS1_STRING: // because MS-IE
1288 Color aColor;
1289 if( pExpr->GetColor( aColor ) )
1290 rItemSet.Put( SvxColorItem( aColor, aItemIds.nColor ) );
1292 break;
1293 default:
1298 static void ParseCSS1_column_count( const CSS1Expression *pExpr,
1299 SfxItemSet& /*rItemSet*/,
1300 SvxCSS1PropertyInfo &rPropInfo,
1301 const SvxCSS1Parser& /*rParser*/ )
1303 assert(pExpr && "no expression");
1305 if ( pExpr->GetType() == CSS1_NUMBER )
1307 double columnCount = pExpr->GetNumber();
1308 if ( columnCount >= 2 )
1310 rPropInfo.m_nColumnCount = columnCount;
1315 static void ParseCSS1_direction( const CSS1Expression *pExpr,
1316 SfxItemSet &rItemSet,
1317 SvxCSS1PropertyInfo& /*rPropInfo*/,
1318 const SvxCSS1Parser& /*rParser*/ )
1320 assert(pExpr && "no expression");
1322 sal_uInt16 nDir;
1323 switch( pExpr->GetType() )
1325 case CSS1_IDENT:
1326 case CSS1_STRING:
1327 if( SvxCSS1Parser::GetEnum( aDirectionTable, pExpr->GetString(),
1328 nDir ) )
1330 rItemSet.Put( SvxFrameDirectionItem(
1331 static_cast < SvxFrameDirection >( nDir ),
1332 aItemIds.nDirection ) );
1334 break;
1335 default:
1340 static void MergeHori( SvxGraphicPosition& ePos, SvxGraphicPosition eHori )
1342 OSL_ENSURE( GPOS_LT==eHori || GPOS_MT==eHori || GPOS_RT==eHori,
1343 "vertical position not at the top" );
1345 switch( ePos )
1347 case GPOS_LT:
1348 case GPOS_MT:
1349 case GPOS_RT:
1350 ePos = eHori;
1351 break;
1353 case GPOS_LM:
1354 case GPOS_MM:
1355 case GPOS_RM:
1356 ePos = GPOS_LT==eHori ? GPOS_LM : (GPOS_MT==eHori ? GPOS_MM : GPOS_RM);
1357 break;
1359 case GPOS_LB:
1360 case GPOS_MB:
1361 case GPOS_RB:
1362 ePos = GPOS_LT==eHori ? GPOS_LB : (GPOS_MT==eHori ? GPOS_MB : GPOS_RB);
1363 break;
1365 default:
1370 static void MergeVert( SvxGraphicPosition& ePos, SvxGraphicPosition eVert )
1372 OSL_ENSURE( GPOS_LT==eVert || GPOS_LM==eVert || GPOS_LB==eVert,
1373 "horizontal position not on the left side" );
1375 switch( ePos )
1377 case GPOS_LT:
1378 case GPOS_LM:
1379 case GPOS_LB:
1380 ePos = eVert;
1381 break;
1383 case GPOS_MT:
1384 case GPOS_MM:
1385 case GPOS_MB:
1386 ePos = GPOS_LT==eVert ? GPOS_MT : (GPOS_LM==eVert ? GPOS_MM : GPOS_MB);
1387 break;
1389 case GPOS_RT:
1390 case GPOS_RM:
1391 case GPOS_RB:
1392 ePos = GPOS_LT==eVert ? GPOS_RT : (GPOS_LM==eVert ? GPOS_RM : GPOS_RB);
1393 break;
1395 default:
1400 static void ParseCSS1_background( const CSS1Expression *pExpr,
1401 SfxItemSet &rItemSet,
1402 SvxCSS1PropertyInfo& /*rPropInfo*/,
1403 const SvxCSS1Parser& rParser )
1405 OSL_ENSURE( pExpr, "no expression" );
1407 Color aColor;
1408 OUString aURL;
1410 bool bColor = false, bTransparent = false;
1411 SvxGraphicPosition eRepeat = GPOS_TILED;
1412 SvxGraphicPosition ePos = GPOS_LT;
1413 bool bHori = false, bVert = false;
1415 while( pExpr && !pExpr->GetOp() )
1417 switch( pExpr->GetType() )
1419 case CSS1_URL:
1420 pExpr->GetURL( aURL );
1421 break;
1423 case CSS1_RGB:
1424 bColor = pExpr->GetColor( aColor );
1425 break;
1427 case CSS1_LENGTH:
1428 case CSS1_PIXLENGTH:
1430 // since we don't know any absolute position, we
1431 // only distinguish between 0 and !0. Therefore pixel
1432 // can be handled like all other units.
1434 bool nonZero = std::trunc(pExpr->GetNumber()) != 0.0;
1435 if( !bHori )
1437 ePos = nonZero ? GPOS_MM : GPOS_LT;
1438 bHori = true;
1440 else if( !bVert )
1442 MergeVert( ePos, (nonZero ? GPOS_LM : GPOS_LT) );
1443 bVert = true;
1446 break;
1448 case CSS1_PERCENTAGE:
1450 // the percentage is converted to an enum
1452 sal_uInt16 nPerc = o3tl::narrowing<sal_uInt16>(pExpr->GetNumber());
1453 if( !bHori )
1455 ePos = nPerc < 25 ? GPOS_LT
1456 : (nPerc < 75 ? GPOS_MM
1457 : GPOS_RB);
1459 else if( !bVert )
1461 SvxGraphicPosition eVert =
1462 nPerc < 25 ? GPOS_LT: (nPerc < 75 ? GPOS_LM
1463 : GPOS_LB);
1464 MergeVert( ePos, eVert );
1467 break;
1469 case CSS1_IDENT:
1470 case CSS1_HEXCOLOR:
1471 case CSS1_STRING: // because of MS-IE
1473 sal_uInt16 nEnum;
1474 const OUString &rValue = pExpr->GetString();
1475 if( rValue.equalsIgnoreAsciiCase( "transparent" ) )
1477 bTransparent = true;
1479 if( SvxCSS1Parser::GetEnum( aBGRepeatTable, rValue, nEnum ) )
1481 eRepeat = static_cast<SvxGraphicPosition>(nEnum);
1483 else if( SvxCSS1Parser::GetEnum( aBGHoriPosTable, rValue, nEnum ) )
1485 // <position>, horizontal
1486 MergeHori( ePos, static_cast<SvxGraphicPosition>(nEnum) );
1488 else if( SvxCSS1Parser::GetEnum( aBGVertPosTable, rValue, nEnum ) )
1490 // <position>, vertical
1491 MergeVert( ePos, static_cast<SvxGraphicPosition>(nEnum) );
1493 else if( !bColor )
1495 // <color>
1496 bColor = pExpr->GetColor( aColor );
1498 // <scroll> we don't know
1500 break;
1502 default:
1506 pExpr = pExpr->GetNext();
1509 // transparent beats everything
1510 if( bTransparent )
1512 bColor = false;
1513 aURL.clear();
1516 // repeat has priority over a position
1517 if( GPOS_NONE == eRepeat )
1518 eRepeat = ePos;
1520 if( !bTransparent && !bColor && aURL.isEmpty() )
1521 return;
1523 SvxBrushItem aBrushItem( aItemIds.nBrush );
1525 if( bTransparent )
1526 aBrushItem.SetColor( COL_TRANSPARENT);
1527 else if( bColor )
1528 aBrushItem.SetColor( aColor );
1530 if( !aURL.isEmpty() )
1532 aBrushItem.SetGraphicLink( URIHelper::SmartRel2Abs( INetURLObject( rParser.GetBaseURL()), aURL, Link<OUString *, bool>(), false ) );
1533 aBrushItem.SetGraphicPos( eRepeat );
1536 rItemSet.Put( aBrushItem );
1539 static void ParseCSS1_background_color( const CSS1Expression *pExpr,
1540 SfxItemSet &rItemSet,
1541 SvxCSS1PropertyInfo& /*rPropInfo*/,
1542 const SvxCSS1Parser& /*rParser*/ )
1544 assert(pExpr && "no expression");
1546 Color aColor;
1548 bool bColor = false, bTransparent = false;
1550 switch( pExpr->GetType() )
1552 case CSS1_RGB:
1553 bColor = pExpr->GetColor( aColor );
1554 break;
1555 case CSS1_IDENT:
1556 case CSS1_HEXCOLOR:
1557 case CSS1_STRING: // because of MS-IE
1558 if( pExpr->GetString().equalsIgnoreAsciiCase( "transparent" ) )
1560 bTransparent = true;
1562 else
1564 // <color>
1565 bColor = pExpr->GetColor( aColor );
1567 break;
1568 default:
1572 if( bTransparent || bColor )
1574 SvxBrushItem aBrushItem( aItemIds.nBrush );
1576 if( bTransparent )
1577 aBrushItem.SetColor( COL_TRANSPARENT );
1578 else if( bColor )
1579 aBrushItem.SetColor( aColor);
1581 rItemSet.Put( aBrushItem );
1585 static void ParseCSS1_line_height( const CSS1Expression *pExpr,
1586 SfxItemSet &rItemSet,
1587 SvxCSS1PropertyInfo& /*rPropInfo*/,
1588 const SvxCSS1Parser& )
1590 assert(pExpr && "no expression");
1592 sal_uInt16 nHeight = 0;
1593 sal_uInt16 nPropHeight = 0;
1595 switch( pExpr->GetType() )
1597 case CSS1_LENGTH:
1598 nHeight = o3tl::narrowing<sal_uInt16>(pExpr->GetULength());
1599 break;
1600 case CSS1_PIXLENGTH:
1602 double fHeight = pExpr->GetNumber();
1603 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
1605 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
1606 tools::Long nPWidth = 0;
1607 SvxCSS1Parser::PixelToTwip(nPWidth, nPHeight);
1608 nHeight = o3tl::narrowing<sal_uInt16>(nPHeight);
1611 break;
1612 case CSS1_PERCENTAGE:
1614 nPropHeight = o3tl::narrowing<sal_uInt16>(pExpr->GetNumber());
1616 break;
1617 case CSS1_NUMBER:
1619 nPropHeight = o3tl::narrowing<sal_uInt16>(pExpr->GetNumber() * 100);
1621 break;
1622 default:
1626 if( nHeight )
1628 if( nHeight < SvxCSS1Parser::GetMinFixLineSpace() )
1629 nHeight = SvxCSS1Parser::GetMinFixLineSpace();
1630 SvxLineSpacingItem aLSItem( nHeight, aItemIds.nLineSpacing );
1631 aLSItem.SetLineHeight( nHeight );
1632 // interpret <line-height> attribute as minimum line height
1633 aLSItem.SetLineSpaceRule( SvxLineSpaceRule::Min );
1634 aLSItem.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
1635 rItemSet.Put( aLSItem );
1637 else if( nPropHeight )
1639 SvxLineSpacingItem aLSItem( nPropHeight, aItemIds.nLineSpacing );
1640 aLSItem.SetLineSpaceRule( SvxLineSpaceRule::Auto );
1641 if( 100 == nPropHeight )
1642 aLSItem.SetInterLineSpaceRule( SvxInterLineSpaceRule::Off );
1643 else
1644 aLSItem.SetPropLineSpace( nPropHeight );
1645 rItemSet.Put( aLSItem );
1650 static void ParseCSS1_list_style_type( const CSS1Expression *pExpr,
1651 SfxItemSet & /*rItemSet*/,
1652 SvxCSS1PropertyInfo& rPropInfo,
1653 const SvxCSS1Parser& /*rParser*/ )
1655 assert(pExpr && "no expression");
1657 if( pExpr->GetType() != CSS1_IDENT )
1658 return;
1660 const OUString& rValue = pExpr->GetString();
1662 // values are context-dependent, so fill both
1663 sal_uInt16 nEnum;
1664 if( SvxCSS1Parser::GetEnum( aNumberStyleTable, rValue, nEnum ) )
1666 rPropInfo.m_bNumbering = true;
1667 rPropInfo.m_nNumberingType = static_cast<SvxNumType>(nEnum);
1669 if( SvxCSS1Parser::GetEnum( aBulletStyleTable, rValue, nEnum ) )
1671 rPropInfo.m_bBullet = true;
1672 rPropInfo.m_cBulletChar = nEnum;
1676 static void ParseCSS1_font( const CSS1Expression *pExpr,
1677 SfxItemSet &rItemSet,
1678 SvxCSS1PropertyInfo& rPropInfo,
1679 const SvxCSS1Parser& rParser )
1681 OSL_ENSURE( pExpr, "no expression" );
1683 FontItalic eItalic = ITALIC_NONE;
1684 SvxCaseMap eCaseMap = SvxCaseMap::NotMapped;
1685 FontWeight eWeight = WEIGHT_NORMAL;
1687 // [ <font-style> || <font-variant> || <font-weight> ] ?
1688 while( pExpr && !pExpr->GetOp() &&
1689 (CSS1_IDENT==pExpr->GetType() ||
1690 CSS1_STRING==pExpr->GetType() ||
1691 CSS1_NUMBER==pExpr->GetType()) )
1693 if( CSS1_IDENT==pExpr->GetType() ||
1694 CSS1_STRING==pExpr->GetType() )
1696 const OUString& rValue = pExpr->GetString();
1698 sal_uInt16 nEnum;
1700 if( SvxCSS1Parser::GetEnum( aFontStyleTable, rValue, nEnum ) )
1702 eItalic = static_cast<FontItalic>(nEnum);
1704 else if( SvxCSS1Parser::GetEnum( aFontVariantTable, rValue, nEnum ) )
1706 eCaseMap = static_cast<SvxCaseMap>(nEnum);
1708 else if( SvxCSS1Parser::GetEnum( aFontWeightTable, rValue, nEnum ) )
1710 eWeight = static_cast<FontWeight>(nEnum);
1713 else
1715 eWeight = o3tl::narrowing<sal_uInt16>(pExpr->GetNumber()) > 400 ? WEIGHT_BOLD
1716 : WEIGHT_NORMAL;
1719 pExpr = pExpr->GetNext();
1722 if( !pExpr || pExpr->GetOp() )
1723 return;
1725 // Since "font" resets all values for which nothing is specified,
1726 // we do it here.
1727 SvxPostureItem aPosture( eItalic, aItemIds.nPosture );
1728 rItemSet.Put( aPosture );
1729 aPosture.SetWhich( aItemIds.nPostureCJK );
1730 rItemSet.Put( aPosture );
1731 aPosture.SetWhich( aItemIds.nPostureCTL );
1732 rItemSet.Put( aPosture );
1734 rItemSet.Put( SvxCaseMapItem( eCaseMap, aItemIds.nCaseMap ) );
1736 SvxWeightItem aWeight( eWeight, aItemIds.nWeight );
1737 rItemSet.Put( aWeight );
1738 aWeight.SetWhich( aItemIds.nWeightCJK );
1739 rItemSet.Put( aWeight );
1740 aWeight.SetWhich( aItemIds.nWeightCTL );
1741 rItemSet.Put( aWeight );
1743 // font-size
1744 CSS1Expression aExpr( pExpr->GetType(), pExpr->GetString(),
1745 pExpr->GetNumber() );
1746 ParseCSS1_font_size( &aExpr, rItemSet, rPropInfo, rParser );
1747 pExpr = pExpr->GetNext();
1749 if( !pExpr )
1750 return;
1752 // [ '/' line-height ]?
1753 if( '/' == pExpr->GetOp() )
1755 // '/' line-height
1756 aExpr.Set( pExpr->GetType(), pExpr->GetString(), pExpr->GetNumber() );
1757 ParseCSS1_line_height( &aExpr, rItemSet, rPropInfo, rParser );
1759 pExpr = pExpr->GetNext();
1762 if( !pExpr || pExpr->GetOp() )
1763 return;
1765 // font-family
1766 ParseCSS1_font_family( pExpr, rItemSet, rPropInfo, rParser );
1769 static void ParseCSS1_letter_spacing( const CSS1Expression *pExpr,
1770 SfxItemSet &rItemSet,
1771 SvxCSS1PropertyInfo& /*rPropInfo*/,
1772 const SvxCSS1Parser& /*rParser*/ )
1774 assert(pExpr && "no expression");
1776 switch( pExpr->GetType() )
1778 case CSS1_LENGTH:
1779 rItemSet.Put( SvxKerningItem( static_cast<short>(pExpr->GetSLength()),
1780 aItemIds.nKerning ) );
1781 break;
1783 case CSS1_PIXLENGTH:
1785 double fHeight = pExpr->GetNumber();
1786 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
1788 tools::Long nPWidth = static_cast<tools::Long>(fHeight);
1789 tools::Long nPHeight = 0;
1790 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1791 rItemSet.Put( SvxKerningItem( static_cast<short>(nPWidth), aItemIds.nKerning ) );
1794 break;
1796 case CSS1_NUMBER:
1797 if( pExpr->GetNumber() == 0 )
1799 // normally unnecessary, but we are tolerant
1800 rItemSet.Put( SvxKerningItem( short(0), aItemIds.nKerning ) );
1802 break;
1804 case CSS1_IDENT:
1805 case CSS1_STRING: // As a precaution also MS-IE
1806 if( pExpr->GetString().equalsIgnoreAsciiCase( "normal" ) )
1808 rItemSet.Put( SvxKerningItem( short(0), aItemIds.nKerning ) );
1810 break;
1811 default:
1816 static void ParseCSS1_text_decoration( const CSS1Expression *pExpr,
1817 SfxItemSet &rItemSet,
1818 SvxCSS1PropertyInfo& /*rPropInfo*/,
1819 const SvxCSS1Parser& /*rParser*/ )
1821 OSL_ENSURE( pExpr, "no expression" );
1823 bool bUnderline = false;
1824 bool bOverline = false;
1825 bool bCrossedOut = false;
1826 bool bBlink = false;
1827 bool bBlinkOn = false;
1828 FontLineStyle eUnderline = LINESTYLE_NONE;
1829 FontLineStyle eOverline = LINESTYLE_NONE;
1830 FontStrikeout eCrossedOut = STRIKEOUT_NONE;
1832 // the value can contain two values! And MS-IE also strings
1833 while( pExpr && (pExpr->GetType() == CSS1_IDENT ||
1834 pExpr->GetType() == CSS1_STRING) && !pExpr->GetOp() )
1836 OUString aValue = pExpr->GetString().toAsciiLowerCase();
1837 bool bKnown = false;
1839 switch( aValue[0] )
1841 case 'n':
1842 if( aValue == "none" )
1844 bUnderline = true;
1845 eUnderline = LINESTYLE_NONE;
1847 bOverline = true;
1848 eOverline = LINESTYLE_NONE;
1850 bCrossedOut = true;
1851 eCrossedOut = STRIKEOUT_NONE;
1853 bBlink = true;
1854 bBlinkOn = false;
1856 bKnown = true;
1858 break;
1860 case 'u':
1861 if( aValue == "underline" )
1863 bUnderline = true;
1864 eUnderline = LINESTYLE_SINGLE;
1866 bKnown = true;
1868 break;
1870 case 'o':
1871 if( aValue == "overline" )
1873 bOverline = true;
1874 eOverline = LINESTYLE_SINGLE;
1876 bKnown = true;
1878 break;
1880 case 'l':
1881 if( aValue == "line-through" )
1883 bCrossedOut = true;
1884 eCrossedOut = STRIKEOUT_SINGLE;
1886 bKnown = true;
1888 break;
1890 case 'b':
1891 if( aValue == "blink" )
1893 bBlink = true;
1894 bBlinkOn = true;
1896 bKnown = true;
1898 break;
1901 if( !bKnown )
1903 bUnderline = true;
1904 eUnderline = LINESTYLE_SINGLE;
1907 pExpr = pExpr->GetNext();
1910 if( bUnderline )
1911 rItemSet.Put( SvxUnderlineItem( eUnderline, aItemIds.nUnderline ) );
1913 if( bOverline )
1914 rItemSet.Put( SvxOverlineItem( eOverline, aItemIds.nOverline ) );
1916 if( bCrossedOut )
1917 rItemSet.Put( SvxCrossedOutItem( eCrossedOut, aItemIds.nCrossedOut ) );
1919 if( bBlink )
1920 rItemSet.Put( SvxBlinkItem( bBlinkOn, aItemIds.nBlink ) );
1923 static void ParseCSS1_text_align( const CSS1Expression *pExpr,
1924 SfxItemSet &rItemSet,
1925 SvxCSS1PropertyInfo& /*rPropInfo*/,
1926 const SvxCSS1Parser& /*rParser*/ )
1928 assert(pExpr && "no expression");
1930 if( CSS1_IDENT==pExpr->GetType() ||
1931 CSS1_STRING==pExpr->GetType() ) // MS-IE, again
1933 sal_uInt16 nAdjust;
1934 if( SvxCSS1Parser::GetEnum( aTextAlignTable, pExpr->GetString(),
1935 nAdjust ) )
1937 rItemSet.Put( SvxAdjustItem( static_cast<SvxAdjust>(nAdjust),
1938 aItemIds.nAdjust ) );
1943 static void ParseCSS1_text_indent( const CSS1Expression *pExpr,
1944 SfxItemSet &rItemSet,
1945 SvxCSS1PropertyInfo& rPropInfo,
1946 const SvxCSS1Parser& /*rParser*/ )
1948 assert(pExpr && "no expression");
1950 short nIndent = 0;
1951 bool bSet = false;
1952 switch( pExpr->GetType() )
1954 case CSS1_LENGTH:
1956 double n = std::round(pExpr->GetNumber());
1957 SAL_WARN_IF(
1958 n < std::numeric_limits<short>::min() || n > std::numeric_limits<short>::max(),
1959 "sw.html", "clamping length " << n << " to short range");
1960 nIndent = static_cast<short>(
1961 std::clamp(
1962 n, double(std::numeric_limits<short>::min()),
1963 double(std::numeric_limits<short>::max())));
1964 bSet = true;
1966 break;
1967 case CSS1_PIXLENGTH:
1969 double fWidth = pExpr->GetNumber();
1970 if (fWidth < SAL_MAX_INT32/2.0 && fWidth > SAL_MIN_INT32/2.0)
1972 tools::Long nPWidth = static_cast<tools::Long>(fWidth);
1973 tools::Long nPHeight = 0;
1974 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
1975 nIndent = static_cast<short>(nPWidth);
1976 bSet = true;
1979 break;
1980 case CSS1_PERCENTAGE:
1981 // we aren't able
1982 break;
1983 default:
1987 if( !bSet )
1988 return;
1990 SvxFirstLineIndentItem const firstLine(SvxIndentValue::twips(nIndent), RES_MARGIN_FIRSTLINE);
1991 rItemSet.Put(firstLine);
1992 rPropInfo.m_bTextIndent = true;
1995 static void ParseCSS1_margin_left( const CSS1Expression *pExpr,
1996 SfxItemSet &rItemSet,
1997 SvxCSS1PropertyInfo& rPropInfo,
1998 const SvxCSS1Parser& /*rParser*/ )
2000 assert(pExpr && "no expression");
2002 tools::Long nLeft = 0;
2003 bool bSet = false;
2004 switch( pExpr->GetType() )
2006 case CSS1_LENGTH:
2008 nLeft = pExpr->GetSLength();
2009 bSet = true;
2011 break;
2012 case CSS1_PIXLENGTH:
2014 double fLeft = pExpr->GetNumber();
2015 if (fLeft < SAL_MAX_INT32/2.0 && fLeft > SAL_MIN_INT32/2.0)
2017 nLeft = static_cast<tools::Long>(fLeft);
2018 tools::Long nPHeight = 0;
2019 SvxCSS1Parser::PixelToTwip( nLeft, nPHeight );
2020 bSet = true;
2022 else
2024 SAL_WARN("sw.html", "out-of-size pxlength: " << fLeft);
2027 break;
2028 case CSS1_PERCENTAGE:
2029 // we aren't able
2030 break;
2031 default:
2035 if (pExpr->GetString() == "auto")
2037 rPropInfo.m_bLeftMargin = true;
2038 rPropInfo.m_eLeftMarginType = SVX_CSS1_LTYPE_AUTO;
2041 if( !bSet )
2042 return;
2044 rPropInfo.m_nLeftMargin = nLeft;
2045 if( nLeft < 0 )
2046 nLeft = 0;
2048 // TODO: other things may need a SvxLeftMarginItem ? but they currently convert it anyway so they can convert that too.
2049 SvxTextLeftMarginItem const leftMargin(
2050 SvxIndentValue::twips(o3tl::narrowing<sal_uInt16>(nLeft)), RES_MARGIN_TEXTLEFT);
2051 rItemSet.Put(leftMargin);
2052 rPropInfo.m_bLeftMargin = true;
2055 static void ParseCSS1_margin_right( const CSS1Expression *pExpr,
2056 SfxItemSet &rItemSet,
2057 SvxCSS1PropertyInfo& rPropInfo,
2058 const SvxCSS1Parser& /*rParser*/ )
2060 assert(pExpr && "no expression");
2062 tools::Long nRight = 0;
2063 bool bSet = false;
2064 switch( pExpr->GetType() )
2066 case CSS1_LENGTH:
2068 nRight = pExpr->GetSLength();
2069 bSet = true;
2071 break;
2072 case CSS1_PIXLENGTH:
2074 double fRight = pExpr->GetNumber();
2075 if (fRight < SAL_MAX_INT32/2.0 && fRight > SAL_MIN_INT32/2.0)
2077 nRight = static_cast<tools::Long>(fRight);
2078 tools::Long nPHeight = 0;
2079 SvxCSS1Parser::PixelToTwip( nRight, nPHeight );
2080 bSet = true;
2083 break;
2084 case CSS1_PERCENTAGE:
2085 // we aren't able
2086 break;
2087 default:
2091 if (pExpr->GetString() == "auto")
2093 rPropInfo.m_bRightMargin = true;
2094 rPropInfo.m_eRightMarginType = SVX_CSS1_LTYPE_AUTO;
2097 if( !bSet )
2098 return;
2100 rPropInfo.m_nRightMargin = nRight;
2101 if( nRight < 0 )
2102 nRight = 0;
2104 SvxRightMarginItem rightMargin(SvxIndentValue::twips(o3tl::narrowing<sal_uInt16>(nRight)),
2105 RES_MARGIN_RIGHT);
2106 rItemSet.Put(rightMargin);
2107 rPropInfo.m_bRightMargin = true;
2110 static void ParseCSS1_margin_top( const CSS1Expression *pExpr,
2111 SfxItemSet &rItemSet,
2112 SvxCSS1PropertyInfo& rPropInfo,
2113 const SvxCSS1Parser& /*rParser*/ )
2115 assert(pExpr && "no expression");
2117 sal_uInt16 nUpper = 0;
2118 bool bSet = false;
2119 switch( pExpr->GetType() )
2121 case CSS1_LENGTH:
2123 tools::Long nTmp = pExpr->GetSLength();
2124 if( nTmp < 0 )
2125 nTmp = 0;
2126 nUpper = o3tl::narrowing<sal_uInt16>(nTmp);
2127 bSet = true;
2129 break;
2130 case CSS1_PIXLENGTH:
2132 double fHeight = pExpr->GetNumber();
2133 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
2135 tools::Long nPWidth = 0;
2136 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
2137 if( nPHeight < 0 )
2138 nPHeight = 0;
2139 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2140 nUpper = o3tl::narrowing<sal_uInt16>(nPHeight);
2141 bSet = true;
2144 break;
2145 case CSS1_PERCENTAGE:
2146 // we aren't able
2147 break;
2148 default:
2152 if( !bSet )
2153 return;
2155 if( const SvxULSpaceItem* pItem = rItemSet.GetItemIfSet( aItemIds.nULSpace, false ) )
2157 SvxULSpaceItem aULItem( *pItem );
2158 aULItem.SetUpper( nUpper );
2159 rItemSet.Put( aULItem );
2161 else
2163 SvxULSpaceItem aULItem( aItemIds.nULSpace );
2164 aULItem.SetUpper( nUpper );
2165 rItemSet.Put( aULItem );
2167 rPropInfo.m_bTopMargin = true;
2170 static void ParseCSS1_margin_bottom( const CSS1Expression *pExpr,
2171 SfxItemSet &rItemSet,
2172 SvxCSS1PropertyInfo& rPropInfo,
2173 const SvxCSS1Parser& /*rParser*/ )
2175 assert(pExpr && "no expression");
2177 sal_uInt16 nLower = 0;
2178 bool bSet = false;
2179 switch( pExpr->GetType() )
2181 case CSS1_LENGTH:
2183 tools::Long nTmp = pExpr->GetSLength();
2184 if( nTmp < 0 )
2185 nTmp = 0;
2186 nLower = o3tl::narrowing<sal_uInt16>(nTmp);
2187 bSet = true;
2189 break;
2190 case CSS1_PIXLENGTH:
2192 double fHeight = pExpr->GetNumber();
2193 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
2195 tools::Long nPWidth = 0;
2196 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
2197 if( nPHeight < 0 )
2198 nPHeight = 0;
2199 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2200 nLower = o3tl::narrowing<sal_uInt16>(nPHeight);
2201 bSet = true;
2204 break;
2205 case CSS1_PERCENTAGE:
2206 // we aren't able
2207 break;
2208 default:
2212 if( !bSet )
2213 return;
2215 if( const SvxULSpaceItem* pItem = rItemSet.GetItemIfSet( aItemIds.nULSpace, false ) )
2217 SvxULSpaceItem aULItem( *pItem );
2218 aULItem.SetLower( nLower );
2219 rItemSet.Put( aULItem );
2221 else
2223 SvxULSpaceItem aULItem( aItemIds.nULSpace );
2224 aULItem.SetLower( nLower );
2225 rItemSet.Put( aULItem );
2227 rPropInfo.m_bBottomMargin = true;
2230 static void ParseCSS1_margin( const CSS1Expression *pExpr,
2231 SfxItemSet &rItemSet,
2232 SvxCSS1PropertyInfo& rPropInfo,
2233 const SvxCSS1Parser& /*rParser*/ )
2235 OSL_ENSURE( pExpr, "no expression" );
2237 tools::Long nMargins[4] = { 0, 0, 0, 0 };
2238 bool bSetMargins[4] = { false, false, false, false };
2240 for( int i=0; pExpr && i<4 && !pExpr->GetOp(); ++i )
2242 bool bSetThis = false;
2243 tools::Long nMargin = 0;
2245 switch( pExpr->GetType() )
2247 case CSS1_LENGTH:
2249 nMargin = pExpr->GetSLength();
2250 bSetThis = true;
2252 break;
2253 case CSS1_PIXLENGTH:
2255 double fMargin = pExpr->GetNumber();
2256 if (fMargin < SAL_MAX_INT32/2.0 && fMargin > SAL_MIN_INT32/2.0)
2258 nMargin = static_cast<tools::Long>(fMargin);
2259 tools::Long nPWidth = 0;
2260 SvxCSS1Parser::PixelToTwip( nPWidth, nMargin );
2261 bSetThis = true;
2263 else
2265 SAL_WARN("sw.html", "out-of-size pxlength: " << fMargin);
2268 break;
2269 case CSS1_PERCENTAGE:
2270 // we aren't able
2271 break;
2272 default:
2276 if( bSetThis )
2278 // 0 = top
2279 // 1 = right
2280 // 2 = bottom
2281 // 3 = left
2282 switch( i )
2284 case 0:
2285 nMargins[0] = nMargins[1] =nMargins[2] = nMargins[3] = nMargin;
2286 bSetMargins[0] = bSetMargins[1] =
2287 bSetMargins[2] = bSetMargins[3] = true;
2288 break;
2289 case 1:
2290 nMargins[1] = nMargins[3] = nMargin; // right + left
2291 bSetMargins[1] = bSetMargins[3] = true;
2292 break;
2293 case 2:
2294 nMargins[2] = nMargin; // bottom
2295 bSetMargins[2] = true;
2296 break;
2297 case 3:
2298 nMargins[3] = nMargin; // left
2299 bSetMargins[3] = true;
2300 break;
2303 pExpr = pExpr->GetNext();
2306 if( bSetMargins[3] || bSetMargins[1] )
2308 if( bSetMargins[3] )
2310 rPropInfo.m_bLeftMargin = true;
2311 rPropInfo.m_nLeftMargin = nMargins[3];
2312 if( nMargins[3] < 0 )
2313 nMargins[3] = 0;
2315 if( bSetMargins[1] )
2317 rPropInfo.m_bRightMargin = true;
2318 rPropInfo.m_nRightMargin = nMargins[1];
2319 if( nMargins[1] < 0 )
2320 nMargins[1] = 0;
2323 if (bSetMargins[3])
2325 SvxTextLeftMarginItem const leftMargin(
2326 SvxIndentValue::twips(o3tl::narrowing<sal_uInt16>(nMargins[3])),
2327 RES_MARGIN_TEXTLEFT);
2328 rItemSet.Put(leftMargin);
2330 if (bSetMargins[1])
2332 SvxRightMarginItem const rightMargin(
2333 SvxIndentValue::twips(o3tl::narrowing<sal_uInt16>(nMargins[1])), RES_MARGIN_RIGHT);
2334 rItemSet.Put(rightMargin);
2338 if( !(bSetMargins[0] || bSetMargins[2]) )
2339 return;
2341 if( nMargins[0] < 0 )
2342 nMargins[0] = 0;
2343 if( nMargins[2] < 0 )
2344 nMargins[2] = 0;
2346 if( const SvxULSpaceItem* pItem = rItemSet.GetItemIfSet( aItemIds.nULSpace, false ) )
2348 SvxULSpaceItem aULItem( *pItem );
2349 if( bSetMargins[0] )
2350 aULItem.SetUpper( o3tl::narrowing<sal_uInt16>(nMargins[0]) );
2351 if( bSetMargins[2] )
2352 aULItem.SetLower( o3tl::narrowing<sal_uInt16>(nMargins[2]) );
2353 rItemSet.Put( aULItem );
2355 else
2357 SvxULSpaceItem aULItem( aItemIds.nULSpace );
2358 if( bSetMargins[0] )
2359 aULItem.SetUpper( o3tl::narrowing<sal_uInt16>(nMargins[0]) );
2360 if( bSetMargins[2] )
2361 aULItem.SetLower( o3tl::narrowing<sal_uInt16>(nMargins[2]) );
2362 rItemSet.Put( aULItem );
2365 rPropInfo.m_bTopMargin |= bSetMargins[0];
2366 rPropInfo.m_bBottomMargin |= bSetMargins[2];
2369 static bool ParseCSS1_padding_xxx( const CSS1Expression *pExpr,
2370 SvxCSS1PropertyInfo& rPropInfo,
2371 SvxBoxItemLine nWhichLine )
2373 assert(pExpr && "no expression");
2375 bool bSet = false;
2376 sal_uInt16 nDist = 0;
2378 switch( pExpr->GetType() )
2380 case CSS1_LENGTH:
2382 tools::Long nTmp = pExpr->GetSLength();
2383 if( nTmp < 0 )
2384 nTmp = 0;
2385 else if( nTmp > SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1 )
2386 nTmp = SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1;
2387 nDist = o3tl::narrowing<sal_uInt16>(nTmp);
2388 bSet = true;
2390 break;
2391 case CSS1_PIXLENGTH:
2393 double fWidth = pExpr->GetNumber();
2394 if (fWidth < SAL_MAX_INT32/2.0 && fWidth > SAL_MIN_INT32/2.0)
2396 tools::Long nPWidth = static_cast<tools::Long>(fWidth);
2397 tools::Long nPHeight = 0;
2398 if( nPWidth < 0 )
2399 nPWidth = 0;
2400 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2401 if( nPWidth > SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1 )
2402 nPWidth = SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1;
2403 nDist = o3tl::narrowing<sal_uInt16>(nPWidth);
2404 bSet = true;
2407 break;
2408 case CSS1_PERCENTAGE:
2409 // we aren't able
2410 break;
2411 default:
2415 if( bSet )
2417 switch( nWhichLine )
2419 case SvxBoxItemLine::TOP: rPropInfo.m_nTopBorderDistance = nDist; break;
2420 case SvxBoxItemLine::BOTTOM: rPropInfo.m_nBottomBorderDistance = nDist;break;
2421 case SvxBoxItemLine::LEFT: rPropInfo.m_nLeftBorderDistance = nDist; break;
2422 case SvxBoxItemLine::RIGHT: rPropInfo.m_nRightBorderDistance = nDist; break;
2426 return bSet;
2429 static void ParseCSS1_padding_top( const CSS1Expression *pExpr,
2430 SfxItemSet & /*rItemSet*/,
2431 SvxCSS1PropertyInfo& rPropInfo,
2432 const SvxCSS1Parser& /*rParser*/ )
2434 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::TOP );
2437 static void ParseCSS1_padding_bottom( const CSS1Expression *pExpr,
2438 SfxItemSet & /*rItemSet*/,
2439 SvxCSS1PropertyInfo& rPropInfo,
2440 const SvxCSS1Parser& /*rParser*/ )
2442 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::BOTTOM );
2445 static void ParseCSS1_padding_left( const CSS1Expression *pExpr,
2446 SfxItemSet & /*rItemSet*/,
2447 SvxCSS1PropertyInfo& rPropInfo,
2448 const SvxCSS1Parser& /*rParser*/ )
2450 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::LEFT );
2453 static void ParseCSS1_padding_right( const CSS1Expression *pExpr,
2454 SfxItemSet & /*rItemSet*/,
2455 SvxCSS1PropertyInfo& rPropInfo,
2456 const SvxCSS1Parser& /*rParser*/ )
2458 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::RIGHT );
2461 static void ParseCSS1_padding( const CSS1Expression *pExpr,
2462 SfxItemSet & /*rItemSet*/,
2463 SvxCSS1PropertyInfo& rPropInfo,
2464 const SvxCSS1Parser& /*rParser*/ )
2466 int n=0;
2467 while( n<4 && pExpr && !pExpr->GetOp() )
2469 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2470 if( ParseCSS1_padding_xxx( pExpr, rPropInfo, nLine ) )
2472 if( n==0 )
2474 rPropInfo.m_nTopBorderDistance = rPropInfo.m_nBottomBorderDistance;
2475 rPropInfo.m_nLeftBorderDistance = rPropInfo.m_nTopBorderDistance;
2477 if( n <= 1 )
2478 rPropInfo.m_nRightBorderDistance = rPropInfo.m_nLeftBorderDistance;
2481 pExpr = pExpr->GetNext();
2482 n++;
2486 static void ParseCSS1_border_xxx( const CSS1Expression *pExpr,
2487 SfxItemSet & /*rItemSet*/,
2488 SvxCSS1PropertyInfo& rPropInfo,
2489 const SvxCSS1Parser& /*rParser*/,
2490 SvxBoxItemLine nWhichLine, bool bAll )
2492 assert(pExpr && "no expression");
2494 sal_uInt16 nWidth = USHRT_MAX; // line thickness
2495 sal_uInt16 nNWidth = 1; // named line thickness (and default)
2496 CSS1BorderStyle eStyle = CSS1_BS_NONE; // line style
2497 Color aColor;
2498 bool bColor = false;
2500 while( pExpr && !pExpr->GetOp() )
2502 switch( pExpr->GetType() )
2504 case CSS1_RGB:
2505 case CSS1_HEXCOLOR:
2506 if( pExpr->GetColor( aColor ) )
2507 bColor = true;
2508 break;
2510 case CSS1_IDENT:
2512 const OUString& rValue = pExpr->GetString();
2513 sal_uInt16 nValue;
2514 if( SvxCSS1Parser::GetEnum( aBorderWidthTable, rValue, nValue ) )
2516 nNWidth = nValue;
2518 else if( SvxCSS1Parser::GetEnum( aBorderStyleTable, rValue, nValue ) )
2520 eStyle = static_cast<CSS1BorderStyle>(nValue);
2522 else if( pExpr->GetColor( aColor ) )
2524 bColor = true;
2527 break;
2529 case CSS1_LENGTH:
2530 nWidth = o3tl::narrowing<sal_uInt16>(pExpr->GetULength());
2531 break;
2533 case CSS1_PIXLENGTH:
2535 // One Pixel becomes a hairline (is prettier)
2536 double fWidth = pExpr->GetNumber();
2537 if (fWidth > 1.0 && fWidth < SAL_MAX_INT32/2.0)
2539 bool bHori = nWhichLine == SvxBoxItemLine::TOP ||
2540 nWhichLine == SvxBoxItemLine::BOTTOM;
2542 tools::Long nPWidth = bHori ? 0 : fWidth;
2543 tools::Long nPHeight = bHori ? fWidth : 0;
2544 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2545 nWidth = o3tl::narrowing<sal_uInt16>(bHori ? nPHeight : nPWidth);
2547 else
2548 nWidth = 1;
2550 break;
2552 default:
2556 pExpr = pExpr->GetNext();
2559 for( int i=0; i<4; ++i )
2561 SvxBoxItemLine nLine = SvxBoxItemLine::TOP;
2562 switch( i )
2564 case 0: nLine = SvxBoxItemLine::TOP; break;
2565 case 1: nLine = SvxBoxItemLine::BOTTOM; break;
2566 case 2: nLine = SvxBoxItemLine::LEFT; break;
2567 case 3: nLine = SvxBoxItemLine::RIGHT; break;
2570 if( bAll || nLine == nWhichLine )
2572 SvxCSS1BorderInfo *pInfo = rPropInfo.GetBorderInfo( nLine );
2573 pInfo->eStyle = eStyle;
2574 pInfo->nAbsWidth = nWidth;
2575 pInfo->nNamedWidth = nNWidth;
2576 if( bColor )
2577 pInfo->aColor = aColor;
2582 static void ParseCSS1_border_xxx_width( const CSS1Expression *pExpr,
2583 SfxItemSet & /*rItemSet*/,
2584 SvxCSS1PropertyInfo& rPropInfo,
2585 const SvxCSS1Parser& /*rParser*/,
2586 SvxBoxItemLine nWhichLine )
2588 assert(pExpr && "no expression");
2590 sal_uInt16 nWidth = USHRT_MAX; // line thickness
2591 sal_uInt16 nNWidth = 1; // named line thickness (and default)
2593 switch( pExpr->GetType() )
2595 case CSS1_IDENT:
2597 sal_uInt16 nValue;
2598 if( SvxCSS1Parser::GetEnum( aBorderWidthTable, pExpr->GetString(), nValue ) )
2600 nNWidth = nValue;
2603 break;
2605 case CSS1_LENGTH:
2606 nWidth = o3tl::narrowing<sal_uInt16>(pExpr->GetULength());
2607 break;
2609 case CSS1_PIXLENGTH:
2611 double fLength = pExpr->GetNumber();
2612 if (fLength < SAL_MAX_INT32/2.0 && fLength > SAL_MIN_INT32/2.0)
2614 tools::Long nWidthL = static_cast<tools::Long>(fLength);
2616 bool bHori = nWhichLine == SvxBoxItemLine::TOP ||
2617 nWhichLine == SvxBoxItemLine::BOTTOM;
2619 tools::Long nPWidth = bHori ? 0 : nWidthL;
2620 tools::Long nPHeight = bHori ? nWidthL : 0;
2621 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2622 nWidth = o3tl::narrowing<sal_uInt16>(bHori ? nPHeight : nPWidth);
2625 break;
2627 default:
2631 SvxCSS1BorderInfo *pInfo = rPropInfo.GetBorderInfo( nWhichLine );
2632 pInfo->nAbsWidth = nWidth;
2633 pInfo->nNamedWidth = nNWidth;
2636 static void ParseCSS1_border_top_width( const CSS1Expression *pExpr,
2637 SfxItemSet &rItemSet,
2638 SvxCSS1PropertyInfo& rPropInfo,
2639 const SvxCSS1Parser& rParser )
2641 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::TOP );
2644 static void ParseCSS1_border_right_width( const CSS1Expression *pExpr,
2645 SfxItemSet &rItemSet,
2646 SvxCSS1PropertyInfo& rPropInfo,
2647 const SvxCSS1Parser& rParser )
2649 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::RIGHT );
2652 static void ParseCSS1_border_bottom_width( const CSS1Expression *pExpr,
2653 SfxItemSet &rItemSet,
2654 SvxCSS1PropertyInfo& rPropInfo,
2655 const SvxCSS1Parser& rParser )
2657 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::BOTTOM );
2660 static void ParseCSS1_border_left_width( const CSS1Expression *pExpr,
2661 SfxItemSet &rItemSet,
2662 SvxCSS1PropertyInfo& rPropInfo,
2663 const SvxCSS1Parser& rParser )
2665 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::LEFT );
2668 static void ParseCSS1_border_width( const CSS1Expression *pExpr,
2669 SfxItemSet &rItemSet,
2670 SvxCSS1PropertyInfo& rPropInfo,
2671 const SvxCSS1Parser& rParser )
2673 sal_uInt16 n=0;
2674 while( n<4 && pExpr && !pExpr->GetOp() )
2676 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2677 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, nLine );
2678 rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_WIDTH );
2680 pExpr = pExpr->GetNext();
2681 n++;
2685 static void ParseCSS1_border_color( const CSS1Expression *pExpr,
2686 SfxItemSet & /*rItemSet*/,
2687 SvxCSS1PropertyInfo& rPropInfo,
2688 const SvxCSS1Parser& /*rParser*/ )
2690 sal_uInt16 n=0;
2691 while( n<4 && pExpr && !pExpr->GetOp() )
2693 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2694 Color aColor;
2695 switch( pExpr->GetType() )
2697 case CSS1_RGB:
2698 case CSS1_HEXCOLOR:
2699 case CSS1_IDENT:
2700 if( pExpr->GetColor( aColor ) )
2701 rPropInfo.GetBorderInfo( nLine )->aColor = aColor;
2702 break;
2703 default:
2706 rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_COLOR );
2708 pExpr = pExpr->GetNext();
2709 n++;
2713 static void ParseCSS1_border_style( const CSS1Expression *pExpr,
2714 SfxItemSet & /*rItemSet*/,
2715 SvxCSS1PropertyInfo& rPropInfo,
2716 const SvxCSS1Parser& /*rParser*/ )
2718 sal_uInt16 n=0;
2719 while( n<4 && pExpr && !pExpr->GetOp() )
2721 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2722 sal_uInt16 nValue = 0;
2723 if( CSS1_IDENT==pExpr->GetType() &&
2724 SvxCSS1Parser::GetEnum( aBorderStyleTable, pExpr->GetString(),
2725 nValue ) )
2727 rPropInfo.GetBorderInfo( nLine )->eStyle = static_cast<CSS1BorderStyle>(nValue);
2729 rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_STYLE );
2731 pExpr = pExpr->GetNext();
2732 n++;
2736 static void ParseCSS1_border_top( const CSS1Expression *pExpr,
2737 SfxItemSet &rItemSet,
2738 SvxCSS1PropertyInfo& rPropInfo,
2739 const SvxCSS1Parser& rParser )
2741 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::TOP, false );
2744 static void ParseCSS1_border_right( const CSS1Expression *pExpr,
2745 SfxItemSet &rItemSet,
2746 SvxCSS1PropertyInfo& rPropInfo,
2747 const SvxCSS1Parser& rParser )
2749 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::RIGHT, false );
2752 static void ParseCSS1_border_bottom( const CSS1Expression *pExpr,
2753 SfxItemSet &rItemSet,
2754 SvxCSS1PropertyInfo& rPropInfo,
2755 const SvxCSS1Parser& rParser )
2757 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::BOTTOM, false );
2760 static void ParseCSS1_border_left( const CSS1Expression *pExpr,
2761 SfxItemSet &rItemSet,
2762 SvxCSS1PropertyInfo& rPropInfo,
2763 const SvxCSS1Parser& rParser )
2765 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::LEFT, false );
2768 static void ParseCSS1_border( const CSS1Expression *pExpr,
2769 SfxItemSet &rItemSet,
2770 SvxCSS1PropertyInfo& rPropInfo,
2771 const SvxCSS1Parser& rParser )
2773 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::TOP, true );
2776 static void ParseCSS1_float( const CSS1Expression *pExpr,
2777 SfxItemSet & /*rItemSet*/,
2778 SvxCSS1PropertyInfo& rPropInfo,
2779 const SvxCSS1Parser& /*rParser*/ )
2781 assert(pExpr && "no expression");
2783 if( CSS1_IDENT==pExpr->GetType() )
2785 sal_uInt16 nFloat;
2786 if( SvxCSS1Parser::GetEnum( aFloatTable, pExpr->GetString(), nFloat ) )
2787 rPropInfo.m_eFloat = static_cast<SvxAdjust>(nFloat);
2791 static void ParseCSS1_position( const CSS1Expression *pExpr,
2792 SfxItemSet & /*rItemSet*/,
2793 SvxCSS1PropertyInfo& rPropInfo,
2794 const SvxCSS1Parser& /*rParser*/ )
2796 assert(pExpr && "no expression");
2798 if( CSS1_IDENT==pExpr->GetType() )
2800 sal_uInt16 nPos;
2801 if( SvxCSS1Parser::GetEnum( aPositionTable, pExpr->GetString(), nPos ) )
2802 rPropInfo.m_ePosition = static_cast<SvxCSS1Position>(nPos);
2806 static void ParseCSS1_length( const CSS1Expression *pExpr,
2807 tools::Long& rLength,
2808 SvxCSS1LengthType& rLengthType,
2809 bool bHori )
2811 switch( pExpr->GetType() )
2813 case CSS1_IDENT:
2814 if( pExpr->GetString().equalsIgnoreAsciiCase( "auto" ) )
2816 rLength = 0;
2817 rLengthType = SVX_CSS1_LTYPE_AUTO;
2819 break;
2821 case CSS1_LENGTH:
2822 rLength = pExpr->GetSLength();
2823 rLengthType = SVX_CSS1_LTYPE_TWIP;
2824 break;
2826 case CSS1_PIXLENGTH:
2827 case CSS1_NUMBER: // because of Netscape and IE
2829 double fLength = pExpr->GetNumber();
2830 if (fLength < SAL_MAX_INT32/2.0 && fLength > SAL_MIN_INT32/2.0)
2832 tools::Long nWidthL = static_cast<tools::Long>(fLength);
2833 tools::Long nPWidth = bHori ? 0 : nWidthL;
2834 tools::Long nPHeight = bHori ? nWidthL : 0;
2835 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2836 rLength = (bHori ? nPHeight : nPWidth);
2837 rLengthType = SVX_CSS1_LTYPE_TWIP;
2840 break;
2842 case CSS1_PERCENTAGE:
2843 rLength = static_cast<tools::Long>(std::min(pExpr->GetNumber(), 100.0));
2844 rLengthType = SVX_CSS1_LTYPE_PERCENTAGE;
2845 break;
2847 default:
2852 static void ParseCSS1_width( const CSS1Expression *pExpr,
2853 SfxItemSet & /*rItemSet*/,
2854 SvxCSS1PropertyInfo& rPropInfo,
2855 const SvxCSS1Parser& /*rParser*/ )
2857 ParseCSS1_length( pExpr, rPropInfo.m_nWidth, rPropInfo.m_eWidthType, true );
2860 static void ParseCSS1_height( const CSS1Expression *pExpr,
2861 SfxItemSet & /*rItemSet*/,
2862 SvxCSS1PropertyInfo& rPropInfo,
2863 const SvxCSS1Parser& /*rParser*/ )
2865 ParseCSS1_length( pExpr, rPropInfo.m_nHeight, rPropInfo.m_eHeightType, false );
2868 static void ParseCSS1_left( const CSS1Expression *pExpr,
2869 SfxItemSet & /*rItemSet*/,
2870 SvxCSS1PropertyInfo& rPropInfo,
2871 const SvxCSS1Parser& /*rParser*/ )
2873 ParseCSS1_length( pExpr, rPropInfo.m_nLeft, rPropInfo.m_eLeftType, true );
2876 static void ParseCSS1_top( const CSS1Expression *pExpr,
2877 SfxItemSet & /*rItemSet*/,
2878 SvxCSS1PropertyInfo& rPropInfo,
2879 const SvxCSS1Parser& /*rParser*/ )
2881 ParseCSS1_length( pExpr, rPropInfo.m_nTop, rPropInfo.m_eTopType, false );
2884 // Feature: PrintExt
2885 static void ParseCSS1_size( const CSS1Expression *pExpr,
2886 SfxItemSet & /*rItemSet*/,
2887 SvxCSS1PropertyInfo& rPropInfo,
2888 const SvxCSS1Parser& /*rParser*/ )
2890 int n=0;
2891 while( n<2 && pExpr && !pExpr->GetOp() )
2893 switch( pExpr->GetType() )
2895 case CSS1_IDENT:
2897 sal_uInt16 nValue;
2898 if( SvxCSS1Parser::GetEnum( aSizeTable, pExpr->GetString(),
2899 nValue ) )
2901 rPropInfo.m_eSizeType = static_cast<SvxCSS1SizeType>(nValue);
2904 break;
2906 case CSS1_LENGTH:
2907 rPropInfo.m_nHeight = pExpr->GetSLength();
2908 if( n==0 )
2909 rPropInfo.m_nWidth = rPropInfo.m_nHeight;
2910 rPropInfo.m_eSizeType = SVX_CSS1_STYPE_TWIP;
2911 break;
2913 case CSS1_PIXLENGTH:
2915 double fHeight = pExpr->GetNumber();
2916 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
2918 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
2919 tools::Long nPWidth = n==0 ? nPHeight : 0;
2920 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2921 rPropInfo.m_nHeight = nPHeight;
2922 if( n==0 )
2923 rPropInfo.m_nWidth = nPWidth;
2924 rPropInfo.m_eSizeType = SVX_CSS1_STYPE_TWIP;
2926 break;
2928 default:
2932 pExpr = pExpr->GetNext();
2933 n++;
2937 static void ParseCSS1_page_break_xxx( const CSS1Expression *pExpr,
2938 SvxCSS1PageBreak& rPBreak )
2940 if( CSS1_IDENT == pExpr->GetType() )
2942 sal_uInt16 nValue;
2943 if( SvxCSS1Parser::GetEnum( aPageBreakTable, pExpr->GetString(),
2944 nValue ) )
2946 rPBreak = static_cast<SvxCSS1PageBreak>(nValue);
2951 static void ParseCSS1_page_break_before( const CSS1Expression *pExpr,
2952 SfxItemSet & /*rItemSet*/,
2953 SvxCSS1PropertyInfo& rPropInfo,
2954 const SvxCSS1Parser& /*rParser*/ )
2956 ParseCSS1_page_break_xxx( pExpr, rPropInfo.m_ePageBreakBefore );
2959 static void ParseCSS1_page_break_after( const CSS1Expression *pExpr,
2960 SfxItemSet & /*rItemSet*/,
2961 SvxCSS1PropertyInfo& rPropInfo,
2962 const SvxCSS1Parser& /*rParser*/ )
2964 ParseCSS1_page_break_xxx( pExpr, rPropInfo.m_ePageBreakAfter );
2967 static void ParseCSS1_page_break_inside( const CSS1Expression *pExpr,
2968 SfxItemSet &rItemSet,
2969 SvxCSS1PropertyInfo& /*rPropInfo*/,
2970 const SvxCSS1Parser& /*rParser*/ )
2972 SvxCSS1PageBreak eBreak(SVX_CSS1_PBREAK_NONE);
2973 ParseCSS1_page_break_xxx( pExpr, eBreak );
2975 bool bSetSplit = false, bSplit = true;
2976 switch( eBreak )
2978 case SVX_CSS1_PBREAK_AUTO:
2979 bSetSplit = true;
2980 break;
2981 case SVX_CSS1_PBREAK_AVOID:
2982 bSplit = false;
2983 bSetSplit = true;
2984 break;
2985 default:
2989 if( bSetSplit )
2990 rItemSet.Put( SvxFormatSplitItem( bSplit, aItemIds.nFormatSplit ) );
2993 static void ParseCSS1_widows( const CSS1Expression *pExpr,
2994 SfxItemSet &rItemSet,
2995 SvxCSS1PropertyInfo& /*rPropInfo*/,
2996 const SvxCSS1Parser& /*rParser*/ )
2998 if( CSS1_NUMBER == pExpr->GetType() )
3000 sal_uInt8 nVal = pExpr->GetNumber() <= 255
3001 ? static_cast<sal_uInt8>(pExpr->GetNumber())
3002 : 255;
3003 SvxWidowsItem aWidowsItem( nVal, aItemIds.nWidows );
3004 rItemSet.Put( aWidowsItem );
3008 static void ParseCSS1_orphans( const CSS1Expression *pExpr,
3009 SfxItemSet &rItemSet,
3010 SvxCSS1PropertyInfo& /*rPropInfo*/,
3011 const SvxCSS1Parser& /*rParser*/ )
3013 if( CSS1_NUMBER == pExpr->GetType() )
3015 sal_uInt8 nVal = pExpr->GetNumber() <= 255
3016 ? static_cast<sal_uInt8>(pExpr->GetNumber())
3017 : 255;
3018 SvxOrphansItem aOrphansItem( nVal, aItemIds.nOrphans );
3019 rItemSet.Put( aOrphansItem );
3023 static void ParseCSS1_so_language( const CSS1Expression *pExpr,
3024 SfxItemSet &rItemSet,
3025 SvxCSS1PropertyInfo& /*rPropInfo*/,
3026 const SvxCSS1Parser& /*rParser*/ )
3028 if( CSS1_IDENT != pExpr->GetType() && CSS1_STRING != pExpr->GetType() )
3029 return;
3031 LanguageType eLang = LanguageTag::convertToLanguageTypeWithFallback( pExpr->GetString() );
3032 if( LANGUAGE_DONTKNOW != eLang )
3034 SvxLanguageItem aLang( eLang, aItemIds.nLanguage );
3035 rItemSet.Put( aLang );
3036 aLang.SetWhich( aItemIds.nLanguageCJK );
3037 rItemSet.Put( aLang );
3038 aLang.SetWhich( aItemIds.nLanguageCTL );
3039 rItemSet.Put( aLang );
3043 static void ParseCSS1_visibility(const CSS1Expression* pExpr, SfxItemSet& /*rItemSet*/,
3044 SvxCSS1PropertyInfo& rPropInfo, const SvxCSS1Parser& /*rParser*/)
3046 if (pExpr->GetType() != CSS1_IDENT)
3047 return;
3049 rPropInfo.m_bVisible = pExpr->GetString() != "hidden";
3052 static void ParseCSS1_white_space(const CSS1Expression* pExpr, SfxItemSet& /*rItemSet*/,
3053 SvxCSS1PropertyInfo& rPropInfo, const SvxCSS1Parser& /*rParser*/)
3055 if (pExpr->GetType() == CSS1_IDENT)
3057 if (pExpr->GetString().equalsIgnoreAsciiCase("pre")
3058 || pExpr->GetString().equalsIgnoreAsciiCase("pre-wrap"))
3060 rPropInfo.m_bPreserveSpace = true;
3065 namespace {
3067 // the assignment of property to parsing function
3068 struct CSS1PropEntry
3070 std::string_view pName;
3071 FnParseCSS1Prop pFunc;
3076 // the table with assignments
3077 CSS1PropEntry constexpr aCSS1PropFnTab[] =
3079 { sCSS1_P_background, ParseCSS1_background },
3080 { sCSS1_P_background_color, ParseCSS1_background_color },
3081 { sCSS1_P_border, ParseCSS1_border },
3082 { sCSS1_P_border_bottom, ParseCSS1_border_bottom },
3083 { sCSS1_P_border_bottom_width, ParseCSS1_border_bottom_width },
3084 { sCSS1_P_border_color, ParseCSS1_border_color },
3085 { sCSS1_P_border_left, ParseCSS1_border_left },
3086 { sCSS1_P_border_left_width, ParseCSS1_border_left_width },
3087 { sCSS1_P_border_right, ParseCSS1_border_right },
3088 { sCSS1_P_border_right_width, ParseCSS1_border_right_width },
3089 { sCSS1_P_border_style, ParseCSS1_border_style },
3090 { sCSS1_P_border_top, ParseCSS1_border_top },
3091 { sCSS1_P_border_top_width, ParseCSS1_border_top_width },
3092 { sCSS1_P_border_width, ParseCSS1_border_width },
3093 { sCSS1_P_color, ParseCSS1_color },
3094 { sCSS1_P_column_count, ParseCSS1_column_count },
3095 { sCSS1_P_direction, ParseCSS1_direction },
3096 { sCSS1_P_float, ParseCSS1_float },
3097 { sCSS1_P_font, ParseCSS1_font },
3098 { sCSS1_P_font_family, ParseCSS1_font_family },
3099 { sCSS1_P_font_size, ParseCSS1_font_size },
3100 { sCSS1_P_font_style, ParseCSS1_font_style },
3101 { sCSS1_P_font_variant, ParseCSS1_font_variant },
3102 { sCSS1_P_font_weight, ParseCSS1_font_weight },
3103 { sCSS1_P_height, ParseCSS1_height },
3104 { sCSS1_P_left, ParseCSS1_left },
3105 { sCSS1_P_letter_spacing, ParseCSS1_letter_spacing },
3106 { sCSS1_P_line_height, ParseCSS1_line_height },
3107 { sCSS1_P_list_style_type, ParseCSS1_list_style_type },
3108 { sCSS1_P_margin, ParseCSS1_margin },
3109 { sCSS1_P_margin_bottom, ParseCSS1_margin_bottom },
3110 { sCSS1_P_margin_left, ParseCSS1_margin_left },
3111 { sCSS1_P_margin_right, ParseCSS1_margin_right },
3112 { sCSS1_P_margin_top, ParseCSS1_margin_top },
3113 { sCSS1_P_orphans, ParseCSS1_orphans },
3114 { sCSS1_P_padding, ParseCSS1_padding },
3115 { sCSS1_P_padding_bottom, ParseCSS1_padding_bottom },
3116 { sCSS1_P_padding_left, ParseCSS1_padding_left },
3117 { sCSS1_P_padding_right, ParseCSS1_padding_right },
3118 { sCSS1_P_padding_top, ParseCSS1_padding_top },
3119 { sCSS1_P_page_break_after, ParseCSS1_page_break_after },
3120 { sCSS1_P_page_break_before, ParseCSS1_page_break_before },
3121 { sCSS1_P_page_break_inside, ParseCSS1_page_break_inside },
3122 { sCSS1_P_position, ParseCSS1_position },
3123 { sCSS1_P_size, ParseCSS1_size },
3124 { sCSS1_P_so_language, ParseCSS1_so_language },
3125 { sCSS1_P_text_align, ParseCSS1_text_align },
3126 { sCSS1_P_text_decoration, ParseCSS1_text_decoration },
3127 { sCSS1_P_text_indent, ParseCSS1_text_indent },
3128 { sCSS1_P_text_transform, ParseCSS1_text_transform },
3129 { sCSS1_P_top, ParseCSS1_top },
3130 { sCSS1_P_visibility, ParseCSS1_visibility },
3131 { sCSS1_white_space, ParseCSS1_white_space },
3132 { sCSS1_P_widows, ParseCSS1_widows },
3133 { sCSS1_P_width, ParseCSS1_width },
3136 static_assert(std::is_sorted(std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab),
3137 [](const auto& lhs, const auto& rhs) constexpr
3138 { return lhs.pName < rhs.pName; }));
3140 static bool CSS1PropEntryFindCompare(CSS1PropEntry const & lhs, OUString const & s)
3142 return s.compareToIgnoreAsciiCaseAscii(lhs.pName) > 0;
3145 void SvxCSS1Parser::DeclarationParsed( const OUString& rProperty,
3146 std::unique_ptr<CSS1Expression> pExpr )
3148 assert(m_pItemSet && "DeclarationParsed() without ItemSet");
3150 auto it = std::lower_bound( std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab), rProperty,
3151 CSS1PropEntryFindCompare );
3152 if( it != std::end(aCSS1PropFnTab) && !CSS1PropEntryFindCompare(*it,rProperty) )
3154 it->pFunc( pExpr.get(), *m_pItemSet, *m_pPropInfo, *this );
3158 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */