Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / filter / html / svxcss1.cxx
blob0150971144feda23e3ace44fcb8a92fc5dab476c
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.GetTrueWhich(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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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 OSL_ENSURE( 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(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 OSL_ENSURE( 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(o3tl::narrowing<sal_uInt16>(nLeft), RES_MARGIN_TEXTLEFT);
2050 rItemSet.Put(leftMargin);
2051 rPropInfo.m_bLeftMargin = true;
2054 static void ParseCSS1_margin_right( const CSS1Expression *pExpr,
2055 SfxItemSet &rItemSet,
2056 SvxCSS1PropertyInfo& rPropInfo,
2057 const SvxCSS1Parser& /*rParser*/ )
2059 OSL_ENSURE( pExpr, "no expression" );
2061 tools::Long nRight = 0;
2062 bool bSet = false;
2063 switch( pExpr->GetType() )
2065 case CSS1_LENGTH:
2067 nRight = pExpr->GetSLength();
2068 bSet = true;
2070 break;
2071 case CSS1_PIXLENGTH:
2073 double fRight = pExpr->GetNumber();
2074 if (fRight < SAL_MAX_INT32/2.0 && fRight > SAL_MIN_INT32/2.0)
2076 nRight = static_cast<tools::Long>(fRight);
2077 tools::Long nPHeight = 0;
2078 SvxCSS1Parser::PixelToTwip( nRight, nPHeight );
2079 bSet = true;
2082 break;
2083 case CSS1_PERCENTAGE:
2084 // we aren't able
2085 break;
2086 default:
2090 if (pExpr->GetString() == "auto")
2092 rPropInfo.m_bRightMargin = true;
2093 rPropInfo.m_eRightMarginType = SVX_CSS1_LTYPE_AUTO;
2096 if( !bSet )
2097 return;
2099 rPropInfo.m_nRightMargin = nRight;
2100 if( nRight < 0 )
2101 nRight = 0;
2103 SvxRightMarginItem rightMargin(o3tl::narrowing<sal_uInt16>(nRight), RES_MARGIN_RIGHT);
2104 rItemSet.Put(rightMargin);
2105 rPropInfo.m_bRightMargin = true;
2108 static void ParseCSS1_margin_top( const CSS1Expression *pExpr,
2109 SfxItemSet &rItemSet,
2110 SvxCSS1PropertyInfo& rPropInfo,
2111 const SvxCSS1Parser& /*rParser*/ )
2113 assert(pExpr && "no expression");
2115 sal_uInt16 nUpper = 0;
2116 bool bSet = false;
2117 switch( pExpr->GetType() )
2119 case CSS1_LENGTH:
2121 tools::Long nTmp = pExpr->GetSLength();
2122 if( nTmp < 0 )
2123 nTmp = 0;
2124 nUpper = o3tl::narrowing<sal_uInt16>(nTmp);
2125 bSet = true;
2127 break;
2128 case CSS1_PIXLENGTH:
2130 double fHeight = pExpr->GetNumber();
2131 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
2133 tools::Long nPWidth = 0;
2134 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
2135 if( nPHeight < 0 )
2136 nPHeight = 0;
2137 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2138 nUpper = o3tl::narrowing<sal_uInt16>(nPHeight);
2139 bSet = true;
2142 break;
2143 case CSS1_PERCENTAGE:
2144 // we aren't able
2145 break;
2146 default:
2150 if( !bSet )
2151 return;
2153 if( const SvxULSpaceItem* pItem = rItemSet.GetItemIfSet( aItemIds.nULSpace, false ) )
2155 SvxULSpaceItem aULItem( *pItem );
2156 aULItem.SetUpper( nUpper );
2157 rItemSet.Put( aULItem );
2159 else
2161 SvxULSpaceItem aULItem( aItemIds.nULSpace );
2162 aULItem.SetUpper( nUpper );
2163 rItemSet.Put( aULItem );
2165 rPropInfo.m_bTopMargin = true;
2168 static void ParseCSS1_margin_bottom( const CSS1Expression *pExpr,
2169 SfxItemSet &rItemSet,
2170 SvxCSS1PropertyInfo& rPropInfo,
2171 const SvxCSS1Parser& /*rParser*/ )
2173 OSL_ENSURE( pExpr, "no expression" );
2175 sal_uInt16 nLower = 0;
2176 bool bSet = false;
2177 switch( pExpr->GetType() )
2179 case CSS1_LENGTH:
2181 tools::Long nTmp = pExpr->GetSLength();
2182 if( nTmp < 0 )
2183 nTmp = 0;
2184 nLower = o3tl::narrowing<sal_uInt16>(nTmp);
2185 bSet = true;
2187 break;
2188 case CSS1_PIXLENGTH:
2190 double fHeight = pExpr->GetNumber();
2191 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
2193 tools::Long nPWidth = 0;
2194 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
2195 if( nPHeight < 0 )
2196 nPHeight = 0;
2197 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2198 nLower = o3tl::narrowing<sal_uInt16>(nPHeight);
2199 bSet = true;
2202 break;
2203 case CSS1_PERCENTAGE:
2204 // we aren't able
2205 break;
2206 default:
2210 if( !bSet )
2211 return;
2213 if( const SvxULSpaceItem* pItem = rItemSet.GetItemIfSet( aItemIds.nULSpace, false ) )
2215 SvxULSpaceItem aULItem( *pItem );
2216 aULItem.SetLower( nLower );
2217 rItemSet.Put( aULItem );
2219 else
2221 SvxULSpaceItem aULItem( aItemIds.nULSpace );
2222 aULItem.SetLower( nLower );
2223 rItemSet.Put( aULItem );
2225 rPropInfo.m_bBottomMargin = true;
2228 static void ParseCSS1_margin( const CSS1Expression *pExpr,
2229 SfxItemSet &rItemSet,
2230 SvxCSS1PropertyInfo& rPropInfo,
2231 const SvxCSS1Parser& /*rParser*/ )
2233 OSL_ENSURE( pExpr, "no expression" );
2235 tools::Long nMargins[4] = { 0, 0, 0, 0 };
2236 bool bSetMargins[4] = { false, false, false, false };
2238 for( int i=0; pExpr && i<4 && !pExpr->GetOp(); ++i )
2240 bool bSetThis = false;
2241 tools::Long nMargin = 0;
2243 switch( pExpr->GetType() )
2245 case CSS1_LENGTH:
2247 nMargin = pExpr->GetSLength();
2248 bSetThis = true;
2250 break;
2251 case CSS1_PIXLENGTH:
2253 double fMargin = pExpr->GetNumber();
2254 if (fMargin < SAL_MAX_INT32/2.0 && fMargin > SAL_MIN_INT32/2.0)
2256 nMargin = static_cast<tools::Long>(fMargin);
2257 tools::Long nPWidth = 0;
2258 SvxCSS1Parser::PixelToTwip( nPWidth, nMargin );
2259 bSetThis = true;
2261 else
2263 SAL_WARN("sw.html", "out-of-size pxlength: " << fMargin);
2266 break;
2267 case CSS1_PERCENTAGE:
2268 // we aren't able
2269 break;
2270 default:
2274 if( bSetThis )
2276 // 0 = top
2277 // 1 = right
2278 // 2 = bottom
2279 // 3 = left
2280 switch( i )
2282 case 0:
2283 nMargins[0] = nMargins[1] =nMargins[2] = nMargins[3] = nMargin;
2284 bSetMargins[0] = bSetMargins[1] =
2285 bSetMargins[2] = bSetMargins[3] = true;
2286 break;
2287 case 1:
2288 nMargins[1] = nMargins[3] = nMargin; // right + left
2289 bSetMargins[1] = bSetMargins[3] = true;
2290 break;
2291 case 2:
2292 nMargins[2] = nMargin; // bottom
2293 bSetMargins[2] = true;
2294 break;
2295 case 3:
2296 nMargins[3] = nMargin; // left
2297 bSetMargins[3] = true;
2298 break;
2301 pExpr = pExpr->GetNext();
2304 if( bSetMargins[3] || bSetMargins[1] )
2306 if( bSetMargins[3] )
2308 rPropInfo.m_bLeftMargin = true;
2309 rPropInfo.m_nLeftMargin = nMargins[3];
2310 if( nMargins[3] < 0 )
2311 nMargins[3] = 0;
2313 if( bSetMargins[1] )
2315 rPropInfo.m_bRightMargin = true;
2316 rPropInfo.m_nRightMargin = nMargins[1];
2317 if( nMargins[1] < 0 )
2318 nMargins[1] = 0;
2321 if (bSetMargins[3])
2323 SvxTextLeftMarginItem const leftMargin(o3tl::narrowing<sal_uInt16>(nMargins[3]), RES_MARGIN_TEXTLEFT);
2324 rItemSet.Put(leftMargin);
2326 if (bSetMargins[1])
2328 SvxRightMarginItem const rightMargin(o3tl::narrowing<sal_uInt16>(nMargins[1]), RES_MARGIN_RIGHT);
2329 rItemSet.Put(rightMargin);
2333 if( !(bSetMargins[0] || bSetMargins[2]) )
2334 return;
2336 if( nMargins[0] < 0 )
2337 nMargins[0] = 0;
2338 if( nMargins[2] < 0 )
2339 nMargins[2] = 0;
2341 if( const SvxULSpaceItem* pItem = rItemSet.GetItemIfSet( aItemIds.nULSpace, false ) )
2343 SvxULSpaceItem aULItem( *pItem );
2344 if( bSetMargins[0] )
2345 aULItem.SetUpper( o3tl::narrowing<sal_uInt16>(nMargins[0]) );
2346 if( bSetMargins[2] )
2347 aULItem.SetLower( o3tl::narrowing<sal_uInt16>(nMargins[2]) );
2348 rItemSet.Put( aULItem );
2350 else
2352 SvxULSpaceItem aULItem( aItemIds.nULSpace );
2353 if( bSetMargins[0] )
2354 aULItem.SetUpper( o3tl::narrowing<sal_uInt16>(nMargins[0]) );
2355 if( bSetMargins[2] )
2356 aULItem.SetLower( o3tl::narrowing<sal_uInt16>(nMargins[2]) );
2357 rItemSet.Put( aULItem );
2360 rPropInfo.m_bTopMargin |= bSetMargins[0];
2361 rPropInfo.m_bBottomMargin |= bSetMargins[2];
2364 static bool ParseCSS1_padding_xxx( const CSS1Expression *pExpr,
2365 SvxCSS1PropertyInfo& rPropInfo,
2366 SvxBoxItemLine nWhichLine )
2368 OSL_ENSURE( pExpr, "no expression" );
2370 bool bSet = false;
2371 sal_uInt16 nDist = 0;
2373 switch( pExpr->GetType() )
2375 case CSS1_LENGTH:
2377 tools::Long nTmp = pExpr->GetSLength();
2378 if( nTmp < 0 )
2379 nTmp = 0;
2380 else if( nTmp > SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1 )
2381 nTmp = SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1;
2382 nDist = o3tl::narrowing<sal_uInt16>(nTmp);
2383 bSet = true;
2385 break;
2386 case CSS1_PIXLENGTH:
2388 double fWidth = pExpr->GetNumber();
2389 if (fWidth < SAL_MAX_INT32/2.0 && fWidth > SAL_MIN_INT32/2.0)
2391 tools::Long nPWidth = static_cast<tools::Long>(fWidth);
2392 tools::Long nPHeight = 0;
2393 if( nPWidth < 0 )
2394 nPWidth = 0;
2395 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2396 if( nPWidth > SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1 )
2397 nPWidth = SvxCSS1PropertyInfo::UNSET_BORDER_DISTANCE-1;
2398 nDist = o3tl::narrowing<sal_uInt16>(nPWidth);
2399 bSet = true;
2402 break;
2403 case CSS1_PERCENTAGE:
2404 // we aren't able
2405 break;
2406 default:
2410 if( bSet )
2412 switch( nWhichLine )
2414 case SvxBoxItemLine::TOP: rPropInfo.m_nTopBorderDistance = nDist; break;
2415 case SvxBoxItemLine::BOTTOM: rPropInfo.m_nBottomBorderDistance = nDist;break;
2416 case SvxBoxItemLine::LEFT: rPropInfo.m_nLeftBorderDistance = nDist; break;
2417 case SvxBoxItemLine::RIGHT: rPropInfo.m_nRightBorderDistance = nDist; break;
2421 return bSet;
2424 static void ParseCSS1_padding_top( const CSS1Expression *pExpr,
2425 SfxItemSet & /*rItemSet*/,
2426 SvxCSS1PropertyInfo& rPropInfo,
2427 const SvxCSS1Parser& /*rParser*/ )
2429 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::TOP );
2432 static void ParseCSS1_padding_bottom( const CSS1Expression *pExpr,
2433 SfxItemSet & /*rItemSet*/,
2434 SvxCSS1PropertyInfo& rPropInfo,
2435 const SvxCSS1Parser& /*rParser*/ )
2437 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::BOTTOM );
2440 static void ParseCSS1_padding_left( const CSS1Expression *pExpr,
2441 SfxItemSet & /*rItemSet*/,
2442 SvxCSS1PropertyInfo& rPropInfo,
2443 const SvxCSS1Parser& /*rParser*/ )
2445 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::LEFT );
2448 static void ParseCSS1_padding_right( const CSS1Expression *pExpr,
2449 SfxItemSet & /*rItemSet*/,
2450 SvxCSS1PropertyInfo& rPropInfo,
2451 const SvxCSS1Parser& /*rParser*/ )
2453 ParseCSS1_padding_xxx( pExpr, rPropInfo, SvxBoxItemLine::RIGHT );
2456 static void ParseCSS1_padding( const CSS1Expression *pExpr,
2457 SfxItemSet & /*rItemSet*/,
2458 SvxCSS1PropertyInfo& rPropInfo,
2459 const SvxCSS1Parser& /*rParser*/ )
2461 int n=0;
2462 while( n<4 && pExpr && !pExpr->GetOp() )
2464 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2465 if( ParseCSS1_padding_xxx( pExpr, rPropInfo, nLine ) )
2467 if( n==0 )
2469 rPropInfo.m_nTopBorderDistance = rPropInfo.m_nBottomBorderDistance;
2470 rPropInfo.m_nLeftBorderDistance = rPropInfo.m_nTopBorderDistance;
2472 if( n <= 1 )
2473 rPropInfo.m_nRightBorderDistance = rPropInfo.m_nLeftBorderDistance;
2476 pExpr = pExpr->GetNext();
2477 n++;
2481 static void ParseCSS1_border_xxx( const CSS1Expression *pExpr,
2482 SfxItemSet & /*rItemSet*/,
2483 SvxCSS1PropertyInfo& rPropInfo,
2484 const SvxCSS1Parser& /*rParser*/,
2485 SvxBoxItemLine nWhichLine, bool bAll )
2487 OSL_ENSURE( pExpr, "no expression" );
2489 sal_uInt16 nWidth = USHRT_MAX; // line thickness
2490 sal_uInt16 nNWidth = 1; // named line thickness (and default)
2491 CSS1BorderStyle eStyle = CSS1_BS_NONE; // line style
2492 Color aColor;
2493 bool bColor = false;
2495 while( pExpr && !pExpr->GetOp() )
2497 switch( pExpr->GetType() )
2499 case CSS1_RGB:
2500 case CSS1_HEXCOLOR:
2501 if( pExpr->GetColor( aColor ) )
2502 bColor = true;
2503 break;
2505 case CSS1_IDENT:
2507 const OUString& rValue = pExpr->GetString();
2508 sal_uInt16 nValue;
2509 if( SvxCSS1Parser::GetEnum( aBorderWidthTable, rValue, nValue ) )
2511 nNWidth = nValue;
2513 else if( SvxCSS1Parser::GetEnum( aBorderStyleTable, rValue, nValue ) )
2515 eStyle = static_cast<CSS1BorderStyle>(nValue);
2517 else if( pExpr->GetColor( aColor ) )
2519 bColor = true;
2522 break;
2524 case CSS1_LENGTH:
2525 nWidth = o3tl::narrowing<sal_uInt16>(pExpr->GetULength());
2526 break;
2528 case CSS1_PIXLENGTH:
2530 // One Pixel becomes a hairline (is prettier)
2531 double fWidth = pExpr->GetNumber();
2532 if (fWidth > 1.0 && fWidth < SAL_MAX_INT32/2.0)
2534 bool bHori = nWhichLine == SvxBoxItemLine::TOP ||
2535 nWhichLine == SvxBoxItemLine::BOTTOM;
2537 tools::Long nPWidth = bHori ? 0 : fWidth;
2538 tools::Long nPHeight = bHori ? fWidth : 0;
2539 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2540 nWidth = o3tl::narrowing<sal_uInt16>(bHori ? nPHeight : nPWidth);
2542 else
2543 nWidth = 1;
2545 break;
2547 default:
2551 pExpr = pExpr->GetNext();
2554 for( int i=0; i<4; ++i )
2556 SvxBoxItemLine nLine = SvxBoxItemLine::TOP;
2557 switch( i )
2559 case 0: nLine = SvxBoxItemLine::TOP; break;
2560 case 1: nLine = SvxBoxItemLine::BOTTOM; break;
2561 case 2: nLine = SvxBoxItemLine::LEFT; break;
2562 case 3: nLine = SvxBoxItemLine::RIGHT; break;
2565 if( bAll || nLine == nWhichLine )
2567 SvxCSS1BorderInfo *pInfo = rPropInfo.GetBorderInfo( nLine );
2568 pInfo->eStyle = eStyle;
2569 pInfo->nAbsWidth = nWidth;
2570 pInfo->nNamedWidth = nNWidth;
2571 if( bColor )
2572 pInfo->aColor = aColor;
2577 static void ParseCSS1_border_xxx_width( const CSS1Expression *pExpr,
2578 SfxItemSet & /*rItemSet*/,
2579 SvxCSS1PropertyInfo& rPropInfo,
2580 const SvxCSS1Parser& /*rParser*/,
2581 SvxBoxItemLine nWhichLine )
2583 OSL_ENSURE( pExpr, "no expression" );
2585 sal_uInt16 nWidth = USHRT_MAX; // line thickness
2586 sal_uInt16 nNWidth = 1; // named line thickness (and default)
2588 switch( pExpr->GetType() )
2590 case CSS1_IDENT:
2592 sal_uInt16 nValue;
2593 if( SvxCSS1Parser::GetEnum( aBorderWidthTable, pExpr->GetString(), nValue ) )
2595 nNWidth = nValue;
2598 break;
2600 case CSS1_LENGTH:
2601 nWidth = o3tl::narrowing<sal_uInt16>(pExpr->GetULength());
2602 break;
2604 case CSS1_PIXLENGTH:
2606 double fLength = pExpr->GetNumber();
2607 if (fLength < SAL_MAX_INT32/2.0 && fLength > SAL_MIN_INT32/2.0)
2609 tools::Long nWidthL = static_cast<tools::Long>(fLength);
2611 bool bHori = nWhichLine == SvxBoxItemLine::TOP ||
2612 nWhichLine == SvxBoxItemLine::BOTTOM;
2614 tools::Long nPWidth = bHori ? 0 : nWidthL;
2615 tools::Long nPHeight = bHori ? nWidthL : 0;
2616 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2617 nWidth = o3tl::narrowing<sal_uInt16>(bHori ? nPHeight : nPWidth);
2620 break;
2622 default:
2626 SvxCSS1BorderInfo *pInfo = rPropInfo.GetBorderInfo( nWhichLine );
2627 pInfo->nAbsWidth = nWidth;
2628 pInfo->nNamedWidth = nNWidth;
2631 static void ParseCSS1_border_top_width( const CSS1Expression *pExpr,
2632 SfxItemSet &rItemSet,
2633 SvxCSS1PropertyInfo& rPropInfo,
2634 const SvxCSS1Parser& rParser )
2636 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::TOP );
2639 static void ParseCSS1_border_right_width( const CSS1Expression *pExpr,
2640 SfxItemSet &rItemSet,
2641 SvxCSS1PropertyInfo& rPropInfo,
2642 const SvxCSS1Parser& rParser )
2644 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::RIGHT );
2647 static void ParseCSS1_border_bottom_width( const CSS1Expression *pExpr,
2648 SfxItemSet &rItemSet,
2649 SvxCSS1PropertyInfo& rPropInfo,
2650 const SvxCSS1Parser& rParser )
2652 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::BOTTOM );
2655 static void ParseCSS1_border_left_width( const CSS1Expression *pExpr,
2656 SfxItemSet &rItemSet,
2657 SvxCSS1PropertyInfo& rPropInfo,
2658 const SvxCSS1Parser& rParser )
2660 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::LEFT );
2663 static void ParseCSS1_border_width( const CSS1Expression *pExpr,
2664 SfxItemSet &rItemSet,
2665 SvxCSS1PropertyInfo& rPropInfo,
2666 const SvxCSS1Parser& rParser )
2668 sal_uInt16 n=0;
2669 while( n<4 && pExpr && !pExpr->GetOp() )
2671 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2672 ParseCSS1_border_xxx_width( pExpr, rItemSet, rPropInfo, rParser, nLine );
2673 rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_WIDTH );
2675 pExpr = pExpr->GetNext();
2676 n++;
2680 static void ParseCSS1_border_color( const CSS1Expression *pExpr,
2681 SfxItemSet & /*rItemSet*/,
2682 SvxCSS1PropertyInfo& rPropInfo,
2683 const SvxCSS1Parser& /*rParser*/ )
2685 sal_uInt16 n=0;
2686 while( n<4 && pExpr && !pExpr->GetOp() )
2688 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2689 Color aColor;
2690 switch( pExpr->GetType() )
2692 case CSS1_RGB:
2693 case CSS1_HEXCOLOR:
2694 case CSS1_IDENT:
2695 if( pExpr->GetColor( aColor ) )
2696 rPropInfo.GetBorderInfo( nLine )->aColor = aColor;
2697 break;
2698 default:
2701 rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_COLOR );
2703 pExpr = pExpr->GetNext();
2704 n++;
2708 static void ParseCSS1_border_style( const CSS1Expression *pExpr,
2709 SfxItemSet & /*rItemSet*/,
2710 SvxCSS1PropertyInfo& rPropInfo,
2711 const SvxCSS1Parser& /*rParser*/ )
2713 sal_uInt16 n=0;
2714 while( n<4 && pExpr && !pExpr->GetOp() )
2716 SvxBoxItemLine nLine = n==0 || n==2 ? SvxBoxItemLine::BOTTOM : SvxBoxItemLine::LEFT;
2717 sal_uInt16 nValue = 0;
2718 if( CSS1_IDENT==pExpr->GetType() &&
2719 SvxCSS1Parser::GetEnum( aBorderStyleTable, pExpr->GetString(),
2720 nValue ) )
2722 rPropInfo.GetBorderInfo( nLine )->eStyle = static_cast<CSS1BorderStyle>(nValue);
2724 rPropInfo.CopyBorderInfo( n, SVX_CSS1_BORDERINFO_STYLE );
2726 pExpr = pExpr->GetNext();
2727 n++;
2731 static void ParseCSS1_border_top( const CSS1Expression *pExpr,
2732 SfxItemSet &rItemSet,
2733 SvxCSS1PropertyInfo& rPropInfo,
2734 const SvxCSS1Parser& rParser )
2736 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::TOP, false );
2739 static void ParseCSS1_border_right( const CSS1Expression *pExpr,
2740 SfxItemSet &rItemSet,
2741 SvxCSS1PropertyInfo& rPropInfo,
2742 const SvxCSS1Parser& rParser )
2744 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::RIGHT, false );
2747 static void ParseCSS1_border_bottom( const CSS1Expression *pExpr,
2748 SfxItemSet &rItemSet,
2749 SvxCSS1PropertyInfo& rPropInfo,
2750 const SvxCSS1Parser& rParser )
2752 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::BOTTOM, false );
2755 static void ParseCSS1_border_left( const CSS1Expression *pExpr,
2756 SfxItemSet &rItemSet,
2757 SvxCSS1PropertyInfo& rPropInfo,
2758 const SvxCSS1Parser& rParser )
2760 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::LEFT, false );
2763 static void ParseCSS1_border( const CSS1Expression *pExpr,
2764 SfxItemSet &rItemSet,
2765 SvxCSS1PropertyInfo& rPropInfo,
2766 const SvxCSS1Parser& rParser )
2768 ParseCSS1_border_xxx( pExpr, rItemSet, rPropInfo, rParser, SvxBoxItemLine::TOP, true );
2771 static void ParseCSS1_float( const CSS1Expression *pExpr,
2772 SfxItemSet & /*rItemSet*/,
2773 SvxCSS1PropertyInfo& rPropInfo,
2774 const SvxCSS1Parser& /*rParser*/ )
2776 OSL_ENSURE( pExpr, "no expression" );
2778 if( CSS1_IDENT==pExpr->GetType() )
2780 sal_uInt16 nFloat;
2781 if( SvxCSS1Parser::GetEnum( aFloatTable, pExpr->GetString(), nFloat ) )
2782 rPropInfo.m_eFloat = static_cast<SvxAdjust>(nFloat);
2786 static void ParseCSS1_position( const CSS1Expression *pExpr,
2787 SfxItemSet & /*rItemSet*/,
2788 SvxCSS1PropertyInfo& rPropInfo,
2789 const SvxCSS1Parser& /*rParser*/ )
2791 OSL_ENSURE( pExpr, "no expression" );
2793 if( CSS1_IDENT==pExpr->GetType() )
2795 sal_uInt16 nPos;
2796 if( SvxCSS1Parser::GetEnum( aPositionTable, pExpr->GetString(), nPos ) )
2797 rPropInfo.m_ePosition = static_cast<SvxCSS1Position>(nPos);
2801 static void ParseCSS1_length( const CSS1Expression *pExpr,
2802 tools::Long& rLength,
2803 SvxCSS1LengthType& rLengthType,
2804 bool bHori )
2806 switch( pExpr->GetType() )
2808 case CSS1_IDENT:
2809 if( pExpr->GetString().equalsIgnoreAsciiCase( "auto" ) )
2811 rLength = 0;
2812 rLengthType = SVX_CSS1_LTYPE_AUTO;
2814 break;
2816 case CSS1_LENGTH:
2817 rLength = pExpr->GetSLength();
2818 rLengthType = SVX_CSS1_LTYPE_TWIP;
2819 break;
2821 case CSS1_PIXLENGTH:
2822 case CSS1_NUMBER: // because of Netscape and IE
2824 double fLength = pExpr->GetNumber();
2825 if (fLength < SAL_MAX_INT32/2.0 && fLength > SAL_MIN_INT32/2.0)
2827 tools::Long nWidthL = static_cast<tools::Long>(fLength);
2828 tools::Long nPWidth = bHori ? 0 : nWidthL;
2829 tools::Long nPHeight = bHori ? nWidthL : 0;
2830 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2831 rLength = (bHori ? nPHeight : nPWidth);
2832 rLengthType = SVX_CSS1_LTYPE_TWIP;
2835 break;
2837 case CSS1_PERCENTAGE:
2838 rLength = static_cast<tools::Long>(std::min(pExpr->GetNumber(), 100.0));
2839 rLengthType = SVX_CSS1_LTYPE_PERCENTAGE;
2840 break;
2842 default:
2847 static void ParseCSS1_width( const CSS1Expression *pExpr,
2848 SfxItemSet & /*rItemSet*/,
2849 SvxCSS1PropertyInfo& rPropInfo,
2850 const SvxCSS1Parser& /*rParser*/ )
2852 ParseCSS1_length( pExpr, rPropInfo.m_nWidth, rPropInfo.m_eWidthType, true );
2855 static void ParseCSS1_height( const CSS1Expression *pExpr,
2856 SfxItemSet & /*rItemSet*/,
2857 SvxCSS1PropertyInfo& rPropInfo,
2858 const SvxCSS1Parser& /*rParser*/ )
2860 ParseCSS1_length( pExpr, rPropInfo.m_nHeight, rPropInfo.m_eHeightType, false );
2863 static void ParseCSS1_left( const CSS1Expression *pExpr,
2864 SfxItemSet & /*rItemSet*/,
2865 SvxCSS1PropertyInfo& rPropInfo,
2866 const SvxCSS1Parser& /*rParser*/ )
2868 ParseCSS1_length( pExpr, rPropInfo.m_nLeft, rPropInfo.m_eLeftType, true );
2871 static void ParseCSS1_top( const CSS1Expression *pExpr,
2872 SfxItemSet & /*rItemSet*/,
2873 SvxCSS1PropertyInfo& rPropInfo,
2874 const SvxCSS1Parser& /*rParser*/ )
2876 ParseCSS1_length( pExpr, rPropInfo.m_nTop, rPropInfo.m_eTopType, false );
2879 // Feature: PrintExt
2880 static void ParseCSS1_size( const CSS1Expression *pExpr,
2881 SfxItemSet & /*rItemSet*/,
2882 SvxCSS1PropertyInfo& rPropInfo,
2883 const SvxCSS1Parser& /*rParser*/ )
2885 int n=0;
2886 while( n<2 && pExpr && !pExpr->GetOp() )
2888 switch( pExpr->GetType() )
2890 case CSS1_IDENT:
2892 sal_uInt16 nValue;
2893 if( SvxCSS1Parser::GetEnum( aSizeTable, pExpr->GetString(),
2894 nValue ) )
2896 rPropInfo.m_eSizeType = static_cast<SvxCSS1SizeType>(nValue);
2899 break;
2901 case CSS1_LENGTH:
2902 rPropInfo.m_nHeight = pExpr->GetSLength();
2903 if( n==0 )
2904 rPropInfo.m_nWidth = rPropInfo.m_nHeight;
2905 rPropInfo.m_eSizeType = SVX_CSS1_STYPE_TWIP;
2906 break;
2908 case CSS1_PIXLENGTH:
2910 double fHeight = pExpr->GetNumber();
2911 if (fHeight < SAL_MAX_INT32/2.0 && fHeight > SAL_MIN_INT32/2.0)
2913 tools::Long nPHeight = static_cast<tools::Long>(fHeight);
2914 tools::Long nPWidth = n==0 ? nPHeight : 0;
2915 SvxCSS1Parser::PixelToTwip( nPWidth, nPHeight );
2916 rPropInfo.m_nHeight = nPHeight;
2917 if( n==0 )
2918 rPropInfo.m_nWidth = nPWidth;
2919 rPropInfo.m_eSizeType = SVX_CSS1_STYPE_TWIP;
2921 break;
2923 default:
2927 pExpr = pExpr->GetNext();
2928 n++;
2932 static void ParseCSS1_page_break_xxx( const CSS1Expression *pExpr,
2933 SvxCSS1PageBreak& rPBreak )
2935 if( CSS1_IDENT == pExpr->GetType() )
2937 sal_uInt16 nValue;
2938 if( SvxCSS1Parser::GetEnum( aPageBreakTable, pExpr->GetString(),
2939 nValue ) )
2941 rPBreak = static_cast<SvxCSS1PageBreak>(nValue);
2946 static void ParseCSS1_page_break_before( const CSS1Expression *pExpr,
2947 SfxItemSet & /*rItemSet*/,
2948 SvxCSS1PropertyInfo& rPropInfo,
2949 const SvxCSS1Parser& /*rParser*/ )
2951 ParseCSS1_page_break_xxx( pExpr, rPropInfo.m_ePageBreakBefore );
2954 static void ParseCSS1_page_break_after( const CSS1Expression *pExpr,
2955 SfxItemSet & /*rItemSet*/,
2956 SvxCSS1PropertyInfo& rPropInfo,
2957 const SvxCSS1Parser& /*rParser*/ )
2959 ParseCSS1_page_break_xxx( pExpr, rPropInfo.m_ePageBreakAfter );
2962 static void ParseCSS1_page_break_inside( const CSS1Expression *pExpr,
2963 SfxItemSet &rItemSet,
2964 SvxCSS1PropertyInfo& /*rPropInfo*/,
2965 const SvxCSS1Parser& /*rParser*/ )
2967 SvxCSS1PageBreak eBreak(SVX_CSS1_PBREAK_NONE);
2968 ParseCSS1_page_break_xxx( pExpr, eBreak );
2970 bool bSetSplit = false, bSplit = true;
2971 switch( eBreak )
2973 case SVX_CSS1_PBREAK_AUTO:
2974 bSetSplit = true;
2975 break;
2976 case SVX_CSS1_PBREAK_AVOID:
2977 bSplit = false;
2978 bSetSplit = true;
2979 break;
2980 default:
2984 if( bSetSplit )
2985 rItemSet.Put( SvxFormatSplitItem( bSplit, aItemIds.nFormatSplit ) );
2988 static void ParseCSS1_widows( const CSS1Expression *pExpr,
2989 SfxItemSet &rItemSet,
2990 SvxCSS1PropertyInfo& /*rPropInfo*/,
2991 const SvxCSS1Parser& /*rParser*/ )
2993 if( CSS1_NUMBER == pExpr->GetType() )
2995 sal_uInt8 nVal = pExpr->GetNumber() <= 255
2996 ? static_cast<sal_uInt8>(pExpr->GetNumber())
2997 : 255;
2998 SvxWidowsItem aWidowsItem( nVal, aItemIds.nWidows );
2999 rItemSet.Put( aWidowsItem );
3003 static void ParseCSS1_orphans( const CSS1Expression *pExpr,
3004 SfxItemSet &rItemSet,
3005 SvxCSS1PropertyInfo& /*rPropInfo*/,
3006 const SvxCSS1Parser& /*rParser*/ )
3008 if( CSS1_NUMBER == pExpr->GetType() )
3010 sal_uInt8 nVal = pExpr->GetNumber() <= 255
3011 ? static_cast<sal_uInt8>(pExpr->GetNumber())
3012 : 255;
3013 SvxOrphansItem aOrphansItem( nVal, aItemIds.nOrphans );
3014 rItemSet.Put( aOrphansItem );
3018 static void ParseCSS1_so_language( const CSS1Expression *pExpr,
3019 SfxItemSet &rItemSet,
3020 SvxCSS1PropertyInfo& /*rPropInfo*/,
3021 const SvxCSS1Parser& /*rParser*/ )
3023 if( CSS1_IDENT != pExpr->GetType() && CSS1_STRING != pExpr->GetType() )
3024 return;
3026 LanguageType eLang = LanguageTag::convertToLanguageTypeWithFallback( pExpr->GetString() );
3027 if( LANGUAGE_DONTKNOW != eLang )
3029 SvxLanguageItem aLang( eLang, aItemIds.nLanguage );
3030 rItemSet.Put( aLang );
3031 aLang.SetWhich( aItemIds.nLanguageCJK );
3032 rItemSet.Put( aLang );
3033 aLang.SetWhich( aItemIds.nLanguageCTL );
3034 rItemSet.Put( aLang );
3038 static void ParseCSS1_visibility(const CSS1Expression* pExpr, SfxItemSet& /*rItemSet*/,
3039 SvxCSS1PropertyInfo& rPropInfo, const SvxCSS1Parser& /*rParser*/)
3041 if (pExpr->GetType() != CSS1_IDENT)
3042 return;
3044 rPropInfo.m_bVisible = pExpr->GetString() != "hidden";
3047 namespace {
3049 // the assignment of property to parsing function
3050 struct CSS1PropEntry
3052 std::string_view pName;
3053 FnParseCSS1Prop pFunc;
3058 // the table with assignments
3059 CSS1PropEntry const aCSS1PropFnTab[] =
3061 { sCSS1_P_background, ParseCSS1_background },
3062 { sCSS1_P_background_color, ParseCSS1_background_color },
3063 { sCSS1_P_border, ParseCSS1_border },
3064 { sCSS1_P_border_bottom, ParseCSS1_border_bottom },
3065 { sCSS1_P_border_bottom_width, ParseCSS1_border_bottom_width },
3066 { sCSS1_P_border_color, ParseCSS1_border_color },
3067 { sCSS1_P_border_left, ParseCSS1_border_left },
3068 { sCSS1_P_border_left_width, ParseCSS1_border_left_width },
3069 { sCSS1_P_border_right, ParseCSS1_border_right },
3070 { sCSS1_P_border_right_width, ParseCSS1_border_right_width },
3071 { sCSS1_P_border_style, ParseCSS1_border_style },
3072 { sCSS1_P_border_top, ParseCSS1_border_top },
3073 { sCSS1_P_border_top_width, ParseCSS1_border_top_width },
3074 { sCSS1_P_border_width, ParseCSS1_border_width },
3075 { sCSS1_P_color, ParseCSS1_color },
3076 { sCSS1_P_column_count, ParseCSS1_column_count },
3077 { sCSS1_P_direction, ParseCSS1_direction },
3078 { sCSS1_P_float, ParseCSS1_float },
3079 { sCSS1_P_font, ParseCSS1_font },
3080 { sCSS1_P_font_family, ParseCSS1_font_family },
3081 { sCSS1_P_font_size, ParseCSS1_font_size },
3082 { sCSS1_P_font_style, ParseCSS1_font_style },
3083 { sCSS1_P_font_variant, ParseCSS1_font_variant },
3084 { sCSS1_P_font_weight, ParseCSS1_font_weight },
3085 { sCSS1_P_height, ParseCSS1_height },
3086 { sCSS1_P_left, ParseCSS1_left },
3087 { sCSS1_P_letter_spacing, ParseCSS1_letter_spacing },
3088 { sCSS1_P_line_height, ParseCSS1_line_height },
3089 { sCSS1_P_list_style_type, ParseCSS1_list_style_type },
3090 { sCSS1_P_margin, ParseCSS1_margin },
3091 { sCSS1_P_margin_bottom, ParseCSS1_margin_bottom },
3092 { sCSS1_P_margin_left, ParseCSS1_margin_left },
3093 { sCSS1_P_margin_right, ParseCSS1_margin_right },
3094 { sCSS1_P_margin_top, ParseCSS1_margin_top },
3095 { sCSS1_P_orphans, ParseCSS1_orphans },
3096 { sCSS1_P_padding, ParseCSS1_padding },
3097 { sCSS1_P_padding_bottom, ParseCSS1_padding_bottom },
3098 { sCSS1_P_padding_left, ParseCSS1_padding_left },
3099 { sCSS1_P_padding_right, ParseCSS1_padding_right },
3100 { sCSS1_P_padding_top, ParseCSS1_padding_top },
3101 { sCSS1_P_page_break_after, ParseCSS1_page_break_after },
3102 { sCSS1_P_page_break_before, ParseCSS1_page_break_before },
3103 { sCSS1_P_page_break_inside, ParseCSS1_page_break_inside },
3104 { sCSS1_P_position, ParseCSS1_position },
3105 { sCSS1_P_size, ParseCSS1_size },
3106 { sCSS1_P_so_language, ParseCSS1_so_language },
3107 { sCSS1_P_text_align, ParseCSS1_text_align },
3108 { sCSS1_P_text_decoration, ParseCSS1_text_decoration },
3109 { sCSS1_P_text_indent, ParseCSS1_text_indent },
3110 { sCSS1_P_text_transform, ParseCSS1_text_transform },
3111 { sCSS1_P_top, ParseCSS1_top },
3112 { sCSS1_P_visibility, ParseCSS1_visibility },
3113 { sCSS1_P_widows, ParseCSS1_widows },
3114 { sCSS1_P_width, ParseCSS1_width },
3117 static bool CSS1PropEntryFindCompare(CSS1PropEntry const & lhs, OUString const & s)
3119 return s.compareToIgnoreAsciiCaseAscii(lhs.pName) > 0;
3122 void SvxCSS1Parser::DeclarationParsed( const OUString& rProperty,
3123 std::unique_ptr<CSS1Expression> pExpr )
3125 OSL_ENSURE( m_pItemSet, "DeclarationParsed() without ItemSet" );
3127 // TODO: convert to static_assert, when C++20 constexpr std::is_sorted is available
3128 [[maybe_unused]] static const bool bSortedPropFns = []() {
3129 assert( std::is_sorted( std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab),
3130 [](const auto& lhs, const auto& rhs) constexpr { return lhs.pName < rhs.pName; } ) );
3131 return true;
3132 }();
3134 auto it = std::lower_bound( std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab), rProperty,
3135 CSS1PropEntryFindCompare );
3136 if( it != std::end(aCSS1PropFnTab) && !CSS1PropEntryFindCompare(*it,rProperty) )
3138 it->pFunc( pExpr.get(), *m_pItemSet, *m_pPropInfo, *this );
3142 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */