1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2021 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/misc/types_nl.h"
24 #include "nel/gui/html_element.h"
25 #include "nel/gui/css_style.h"
26 #include "nel/gui/css_parser.h"
27 #include "nel/gui/libwww.h"
29 using namespace NLMISC
;
37 uint
CCssStyle::SStyleRule::specificity() const
40 for(uint i
= 0; i
< Selector
.size(); ++i
)
42 count
+= Selector
[i
].specificity();
44 // counted as element tag like DIV
45 if (!PseudoElement
.empty())
53 // ***************************************************************************
54 void CCssStyle::reset()
59 Root
= CStyleParams();
60 Current
= CStyleParams();
63 // ***************************************************************************
65 struct CCssSpecificityPred
67 bool operator()(CCssStyle::SStyleRule lhs
, CCssStyle::SStyleRule rhs
) const
69 return lhs
.specificity() < rhs
.specificity();
73 // ***************************************************************************
74 void CCssStyle::parseStylesheet(const std::string
&styleString
)
77 parser
.parseStylesheet(styleString
, _StyleRules
);
79 // keep the list sorted
80 std::stable_sort(_StyleRules
.begin(), _StyleRules
.end(), CCssSpecificityPred());
83 void CCssStyle::getStyleFor(CHtmlElement
&elm
) const
85 std::vector
<SStyleRule
> mRules
;
86 for (std::vector
<SStyleRule
>::const_iterator it
= _StyleRules
.begin(); it
!= _StyleRules
.end(); ++it
)
88 if (match(it
->Selector
, elm
))
90 mRules
.push_back(*it
);
99 // style is sorted by specificity (lowest first), eg. html, .class, html.class, #id, html#id.class
100 for(std::vector
<SStyleRule
>::const_iterator i
= mRules
.begin(); i
!= mRules
.end(); ++i
)
102 if (i
->PseudoElement
.empty())
104 merge(elm
.Style
, i
->Properties
);
109 merge(props
, i
->Properties
);
110 elm
.setPseudo(i
->PseudoElement
, props
);
115 // style from "style" attribute overrides <style>
116 if (elm
.hasNonEmptyAttribute("style"))
118 TStyleVec styles
= CCssParser::parseDecls(elm
.getAttribute("style"));
119 merge(elm
.Style
, styles
);
123 void CCssStyle::merge(TStyle
&dst
, const TStyleVec
&src
) const
125 // TODO: does not use '!important' flag
126 for(TStyleVec::const_iterator it
= src
.begin(); it
!= src
.end(); ++it
)
128 dst
[it
->first
] = it
->second
;
129 expandShorthand(it
->first
, it
->second
, dst
);
133 bool CCssStyle::match(const std::vector
<CCssSelector
> &selector
, const CHtmlElement
&elm
) const
135 if (selector
.empty()) return false;
137 // first selector, '>' immediate parent
138 bool matches
= false;
139 bool mustMatchNext
= true;
140 bool matchGeneralChild
= false;
141 bool matchGeneralSibling
= false;
143 const CHtmlElement
*child
;
145 std::vector
<CCssSelector
>::const_reverse_iterator ritSelector
= selector
.rbegin();
146 char matchCombinator
= '\0';
147 while(ritSelector
!= selector
.rend())
154 matches
= ritSelector
->match(*child
);
155 if (!matches
&& mustMatchNext
)
162 if (matchCombinator
== ' ')
168 child
= child
->parent
;
169 // walk up the tree until there is match for current selector
173 if (matchCombinator
== '~')
175 // any previous sibling must match current selector
176 if (!child
->previousSibling
)
180 child
= child
->previousSibling
;
182 // check siblings until there is match for current selector
187 mustMatchNext
= false;
188 switch(ritSelector
->Combinator
)
191 // default case when single selector
195 // general child - match child->parent to current/previous selector
200 child
= child
->parent
;
201 matchCombinator
= ritSelector
->Combinator
;
206 // any previous sibling must match current selector
207 if (!child
->previousSibling
)
211 child
= child
->previousSibling
;
212 matchCombinator
= ritSelector
->Combinator
;
217 // adjacent sibling - previous sibling must match previous selector
218 if (!child
->previousSibling
)
222 child
= child
->previousSibling
;
223 mustMatchNext
= true;
228 // child of - immediate parent must match previous selector
233 child
= child
->parent
;
234 mustMatchNext
= true;
248 // ***************************************************************************
249 void CCssStyle::applyRootStyle(const std::string
&styleString
)
251 getStyleParams(styleString
, Root
, Root
);
254 // ***************************************************************************
255 void CCssStyle::applyRootStyle(const TStyle
&styleRules
)
257 getStyleParams(styleRules
, Root
, Root
);
260 // ***************************************************************************
261 void CCssStyle::applyStyle(const std::string
&styleString
)
263 if (styleString
.empty()) return;
265 if (_StyleStack
.empty())
267 getStyleParams(styleString
, Current
, Root
);
271 getStyleParams(styleString
, Current
, _StyleStack
.back());
275 // ***************************************************************************
276 void CCssStyle::applyStyle(const TStyle
&styleRules
)
278 if (_StyleStack
.empty())
280 getStyleParams(styleRules
, Current
, Root
);
284 getStyleParams(styleRules
, Current
, _StyleStack
.back());
288 // ***************************************************************************
289 bool CCssStyle::scanCssLength(const std::string
& str
, uint32
&px
) const
291 if (fromString(str
, px
))
313 // ***************************************************************************
314 void CCssStyle::splitParams(const std::string
&str
, char sep
, std::vector
<std::string
> &result
) const
316 // TODO: does not handle utf8
319 for(uint i
= 0; i
< str
.size(); i
++)
321 // split by separator first, then check if string or function
324 std::string sub
= trim(str
.substr(pos
, i
- pos
));
326 result
.push_back(str
.substr(pos
, i
- pos
));
330 else if (str
[i
] == '"' || str
[i
] == '(')
332 // string "this is string", or function rgb(1, 2, 3)
336 else if (str
[i
] == '\'')
343 while(i
< str
.size() && str
[i
] != endChar
)
351 if (pos
< str
.size())
352 result
.push_back(str
.substr(pos
).c_str());
355 // ***************************************************************************
356 // CStyleParams style;
357 // style.FontSize; // font-size: 10px;
358 // style.TextColor; // color: #ABCDEF;
359 // style.Underlined; // text-decoration: underline; text-decoration-line: underline;
360 // style.StrikeThrough; // text-decoration: line-through; text-decoration-line: line-through;
361 void CCssStyle::getStyleParams(const std::string
&styleString
, CStyleParams
&style
, const CStyleParams
¤t
) const
363 TStyleVec stylevec
= CCssParser::parseDecls(styleString
);
366 merge(styles
, stylevec
);
368 getStyleParams(styles
, style
, current
);
371 void CCssStyle::getStyleParams(const TStyle
&styleRules
, CStyleParams
&style
, const CStyleParams
¤t
) const
374 TStyle::const_iterator it
;
376 if(styleRules
.empty())
381 normalize(styleRules
, style
, current
);
382 apply(style
, current
);
386 // - get font-size for 'em' sizes
387 // - split shorthand to its parts
388 // - get TextColor value that could be used for 'currentcolor'
389 // - normalize values
390 void CCssStyle::normalize(const TStyle
&styleRules
, CStyleParams
&style
, const CStyleParams
¤t
) const
392 std::set
<std::string
> seenProperties
;
394 TStyle::const_iterator it
;
395 for (it
=styleRules
.begin(); it
!= styleRules
.end(); ++it
)
397 std::string value
= it
->second
;
399 // replace possible custom properties, ignore property if var() fails
400 if (!cssFuncVar(value
, styleRules
, seenProperties
))
403 // update local copy of applied style
404 style
.StyleRules
[it
->first
] = value
;
406 if (it
->first
== "color")
408 if (value
== "inherit")
410 style
.TextColor
= current
.TextColor
;
414 scanHTMLColor(value
.c_str(), style
.TextColor
);
418 if (it
->first
== "font")
420 if (value
== "inherit")
422 style
.FontSize
= current
.FontSize
;
423 style
.FontFamily
= current
.FontFamily
;
424 style
.FontWeight
= current
.FontWeight
;
425 style
.FontOblique
= current
.FontOblique
;
429 if (it
->first
== "font-size")
431 if (value
== "inherit")
433 style
.FontSize
= current
.FontSize
;
435 else if (value
== "x-small")
437 style
.FontSize
= 10; // 62.5%
439 else if (value
== "small")
441 style
.FontSize
= 13; // 80%;
443 else if (value
== "medium")
445 style
.FontSize
= 16; // 100%;
447 else if (value
== "large")
449 style
.FontSize
= 18; // 112.5%
451 else if (value
== "x-large")
453 style
.FontSize
= 24; // 150%
455 else if (value
== "xx-large")
457 style
.FontSize
= 32; // 200%;
459 else if (value
== "smaller")
461 if (style
.FontSize
< 5)
466 else if (value
== "larger")
474 if (getCssLength(tmpf
, unit
, value
.c_str()))
477 style
.FontSize
= Root
.FontSize
* tmpf
;
478 else if (unit
== "em")
479 style
.FontSize
= current
.FontSize
* tmpf
;
480 else if (unit
== "pt")
481 style
.FontSize
= tmpf
/ 0.75f
;
482 else if (unit
== "%")
483 style
.FontSize
= current
.FontSize
* tmpf
/ 100.f
;
485 style
.FontSize
= tmpf
;
490 if (it
->first
== "background-repeat")
492 // old ryzom specific value
494 style
.StyleRules
[it
->first
] = "repeat";
497 if (it
->first
== "display")
499 if (value
== "inherit")
500 style
.DisplayBlock
= current
.DisplayBlock
;
502 style
.DisplayBlock
= (value
== "block" || value
== "table");
507 void CCssStyle::applyBorderWidth(const std::string
&value
, CSSLength
*dest
, const CSSLength
¤tWidth
) const
510 if (value
== "inherit")
512 *dest
= currentWidth
;
514 else if (value
== "thin")
516 dest
->setFloatValue(1, "px");
518 else if (value
== "medium")
520 dest
->setFloatValue(3, "px");
522 else if (value
== "thick")
524 dest
->setFloatValue(5, "px");
528 dest
->parseValue(value
, false, false);
532 void CCssStyle::applyBorderColor(const std::string
&value
, CRGBA
*dest
, const CRGBA
¤tColor
, const CRGBA
&textColor
) const
536 if (value
== "inherit")
537 *dest
= currentColor
;
538 else if (value
== "transparent")
539 *dest
= CRGBA::Transparent
;
540 else if (value
== "currentcolor")
543 scanHTMLColor(value
.c_str(), *dest
);
546 void CCssStyle::applyLineStyle(const std::string
&value
, CSSLineStyle
*dest
, const CSSLineStyle
¤tStyle
) const
550 if (value
== "inherit")
551 *dest
= currentStyle
;
552 else if (value
== "none")
553 *dest
= CSS_LINE_STYLE_NONE
;
554 else if (value
== "hidden")
555 *dest
= CSS_LINE_STYLE_HIDDEN
;
556 else if (value
== "dotted")
557 *dest
= CSS_LINE_STYLE_DOTTED
;
558 else if (value
== "dashed")
559 *dest
= CSS_LINE_STYLE_DASHED
;
560 else if (value
== "solid")
561 *dest
= CSS_LINE_STYLE_SOLID
;
562 else if (value
== "double")
563 *dest
= CSS_LINE_STYLE_DOUBLE
;
564 else if (value
== "groove")
565 *dest
= CSS_LINE_STYLE_GROOVE
;
566 else if (value
== "ridge")
567 *dest
= CSS_LINE_STYLE_RIDGE
;
568 else if (value
== "inset")
569 *dest
= CSS_LINE_STYLE_INSET
;
570 else if (value
== "outset")
571 *dest
= CSS_LINE_STYLE_OUTSET
;
574 void CCssStyle::applyPaddingWidth(const std::string
&value
, uint32
*dest
, const uint32 currentPadding
, uint32 fontSize
) const
578 if (value
== "inherit")
580 *dest
= currentPadding
;
586 if (getCssLength(tmpf
, unit
, value
.c_str()))
589 *dest
= fontSize
* tmpf
;
590 else if (unit
== "em")
591 *dest
= fontSize
* tmpf
;
592 else if (unit
== "pt")
593 *dest
= tmpf
/ 0.75f
;
594 else if (unit
== "%")
595 *dest
= 0; // TODO: requires content width, must remember 'unit' type
601 void CCssStyle::applyMarginWidth(const std::string
&value
, uint32
*dest
, const uint32 current
, uint32 fontSize
) const
605 if (value
== "inherit")
610 else if (value
== "auto")
612 // TODO: requires content width;
619 if (getCssLength(tmpf
, unit
, value
.c_str()))
622 *dest
= fontSize
* tmpf
;
623 else if (unit
== "em")
624 *dest
= fontSize
* tmpf
;
625 else if (unit
== "pt")
626 *dest
= tmpf
/ 0.75f
;
627 else if (unit
== "%")
628 *dest
= 0; // TODO: requires content width, must remember 'unit' type
635 void CCssStyle::apply(CStyleParams
&style
, const CStyleParams
¤t
) const
638 TStyle::const_iterator it
;
639 for (it
=style
.StyleRules
.begin(); it
!= style
.StyleRules
.end(); ++it
)
641 if (it
->first
== "border-top-width") applyBorderWidth(it
->second
, &style
.Border
.Top
.Width
, current
.Border
.Top
.Width
);
642 else if (it
->first
== "border-top-color") applyBorderColor(it
->second
, &style
.Border
.Top
.Color
, current
.Border
.Top
.Color
, current
.TextColor
);
643 else if (it
->first
== "border-top-style") applyLineStyle(it
->second
, &style
.Border
.Top
.Style
, current
.Border
.Top
.Style
);
644 else if (it
->first
== "border-right-width") applyBorderWidth(it
->second
, &style
.Border
.Right
.Width
, current
.Border
.Right
.Width
);
645 else if (it
->first
== "border-right-color") applyBorderColor(it
->second
, &style
.Border
.Right
.Color
, current
.Border
.Right
.Color
, current
.TextColor
);
646 else if (it
->first
== "border-right-style") applyLineStyle(it
->second
, &style
.Border
.Right
.Style
, current
.Border
.Right
.Style
);
647 else if (it
->first
== "border-bottom-width") applyBorderWidth(it
->second
, &style
.Border
.Bottom
.Width
, current
.Border
.Bottom
.Width
);
648 else if (it
->first
== "border-bottom-color") applyBorderColor(it
->second
, &style
.Border
.Bottom
.Color
, current
.Border
.Bottom
.Color
, current
.TextColor
);
649 else if (it
->first
== "border-bottom-style") applyLineStyle(it
->second
, &style
.Border
.Bottom
.Style
, current
.Border
.Bottom
.Style
);
650 else if (it
->first
== "border-left-width") applyBorderWidth(it
->second
, &style
.Border
.Left
.Width
, current
.Border
.Left
.Width
);
651 else if (it
->first
== "border-left-color") applyBorderColor(it
->second
, &style
.Border
.Left
.Color
, current
.Border
.Left
.Color
, current
.TextColor
);
652 else if (it
->first
== "border-left-style") applyLineStyle(it
->second
, &style
.Border
.Left
.Style
, current
.Border
.Left
.Style
);
653 else if (it
->first
== "margin-top") applyMarginWidth(it
->second
, &style
.MarginTop
, current
.MarginTop
, current
.FontSize
);
654 else if (it
->first
== "margin-right") applyMarginWidth(it
->second
, &style
.MarginRight
, current
.MarginRight
, current
.FontSize
);
655 else if (it
->first
== "margin-bottom") applyMarginWidth(it
->second
, &style
.MarginBottom
, current
.MarginBottom
, current
.FontSize
);
656 else if (it
->first
== "margin-left") applyMarginWidth(it
->second
, &style
.MarginLeft
, current
.MarginLeft
, current
.FontSize
);
657 else if (it
->first
== "padding-top") applyPaddingWidth(it
->second
, &style
.PaddingTop
, current
.PaddingTop
, current
.FontSize
);
658 else if (it
->first
== "padding-right") applyPaddingWidth(it
->second
, &style
.PaddingRight
, current
.PaddingRight
, current
.FontSize
);
659 else if (it
->first
== "padding-bottom") applyPaddingWidth(it
->second
, &style
.PaddingBottom
, current
.PaddingBottom
, current
.FontSize
);
660 else if (it
->first
== "padding-left") applyPaddingWidth(it
->second
, &style
.PaddingLeft
, current
.PaddingLeft
, current
.FontSize
);
662 if (it
->first
== "font-style")
664 if (it
->second
== "inherit")
665 style
.FontOblique
= current
.FontOblique
;
667 if (it
->second
== "italic" || it
->second
== "oblique")
668 style
.FontOblique
= true;
671 if (it
->first
== "font-family")
673 if (it
->second
== "inherit")
674 style
.FontFamily
= current
.FontFamily
;
676 style
.FontFamily
= it
->second
;
679 if (it
->first
== "font-weight")
681 // https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight
683 if (it
->second
== "inherit")
684 weight
= current
.FontWeight
;
686 if (it
->second
== "normal")
689 if (it
->second
== "bold")
692 if (it
->second
== "lighter")
694 const uint lighter
[] = {100, 100, 100, 100, 100, 400, 400, 700, 700};
695 uint index
= current
.FontWeight
/ 100 - 1;
696 clamp(index
, 1u, 9u);
697 weight
= lighter
[index
-1];
700 if (it
->second
== "bolder")
702 const uint bolder
[] = {400, 400, 400, 700, 700, 900, 900, 900, 900};
703 uint index
= current
.FontWeight
/ 100 + 1;
704 clamp(index
, 1u, 9u);
705 weight
= bolder
[index
-1];
708 if (fromString(it
->second
, weight
))
710 weight
= (weight
/ 100);
711 clamp(weight
, 1u, 9u);
714 style
.FontWeight
= weight
;
717 if (it
->first
== "text-decoration" || it
->first
== "text-decoration-line")
719 std::string
prop(toLowerAscii(it
->second
));
720 style
.Underlined
= (prop
.find("underline") != std::string::npos
);
721 style
.StrikeThrough
= (prop
.find("line-through") != std::string::npos
);
724 if (it
->first
== "text-stroke" || it
->first
== "-webkit-text-stroke")
726 // text-stroke: length || color
727 bool success
= false;
730 std::vector
<std::string
> parts
;
731 splitParams(it
->second
, ' ', parts
);
732 if (parts
.size() == 1)
734 success
= scanCssLength(parts
[0], px
);
736 success
= scanHTMLColor(parts
[0].c_str(), color
);
738 else if (parts
.size() == 2)
740 success
= scanCssLength(parts
[0], px
);
742 success
= scanHTMLColor(parts
[1].c_str(), color
);
745 success
= scanHTMLColor(parts
[0].c_str(), color
);
746 success
= success
&& scanCssLength(parts
[1], px
);
750 // do not disable shadow if one is already set
753 style
.TextShadow
.Enabled
= (px
> 0);
754 style
.TextShadow
.Color
= color
;
755 style
.TextShadow
.X
= px
;
756 style
.TextShadow
.Y
= px
;
757 style
.TextShadow
.Outline
= true;
761 if (it
->first
== "text-shadow")
763 if (it
->second
== "none")
764 style
.TextShadow
= CStyleParams::STextShadow(false);
766 if (it
->second
== "inherit")
767 style
.TextShadow
= current
.TextShadow
;
770 // text-shadow: offset-x offset-y | blur | #color
771 // text-shadow: #color | offset-x offset-y
773 std::string
prop(it
->second
);
775 pos
= prop
.find_first_of(",\n\r");
776 if (pos
!= std::string::npos
)
777 prop
= prop
.substr(0, pos
);
779 std::vector
<std::string
> parts
;
780 splitParams(prop
, ' ', parts
);
785 success
= scanHTMLColor(it
->second
.c_str(), style
.TextShadow
.Color
);
791 if (!fromString(parts
[0], style
.TextShadow
.X
))
793 success
= scanHTMLColor(parts
[0].c_str(), style
.TextShadow
.Color
);
794 success
= success
&& fromString(parts
[1], style
.TextShadow
.X
);
795 success
= success
&& fromString(parts
[2], style
.TextShadow
.Y
);
799 success
= fromString(parts
[1], style
.TextShadow
.Y
);
800 success
= success
&& scanHTMLColor(parts
[2].c_str(), style
.TextShadow
.Color
);
806 if (!fromString(parts
[0], style
.TextShadow
.X
))
808 success
= scanHTMLColor(parts
[0].c_str(), style
.TextShadow
.Color
);
809 success
= success
&& fromString(parts
[1], style
.TextShadow
.X
);
810 success
= success
&& fromString(parts
[2], style
.TextShadow
.Y
);
815 success
= fromString(parts
[0], style
.TextShadow
.X
);
816 success
= success
&& fromString(parts
[1], style
.TextShadow
.Y
);
818 success
= success
&& scanHTMLColor(parts
[3].c_str(), style
.TextShadow
.Color
);
829 style
.TextShadow
.Enabled
= success
;
833 if (it
->first
== "text-align")
835 if (it
->second
== "inherit")
836 style
.TextAlign
= current
.TextAlign
;
837 else if (it
->second
== "left" || it
->second
== "right" || it
->second
== "center" || it
->second
== "justify")
838 style
.TextAlign
= it
->second
;
841 if (it
->first
== "vertical-align")
843 if (it
->second
== "inherit")
844 style
.VerticalAlign
= current
.VerticalAlign
;
845 else if (it
->second
== "top" || it
->second
== "middle" || it
->second
== "bottom")
846 style
.VerticalAlign
= it
->second
;
849 if (it
->first
== "white-space")
851 if (it
->second
== "inherit")
852 style
.WhiteSpace
= current
.WhiteSpace
;
853 else if (it
->second
== "normal" || it
->second
== "nowrap" || it
->second
== "pre")
854 style
.WhiteSpace
= it
->second
;
857 if (it
->first
== "width")
860 if (getCssLength(tmpf
, unit
, it
->second
.c_str()))
863 style
.Width
= tmpf
* Root
.FontSize
;
864 else if (unit
== "em")
865 style
.Width
= tmpf
* style
.FontSize
;
866 else if (unit
== "pt")
867 style
.FontSize
= tmpf
/ 0.75f
;
868 else if (unit
== "%")
869 style
.Width
= 0; // TODO: style.WidthRatio
875 if (it
->first
== "height")
878 if (getCssLength(tmpf
, unit
, it
->second
.c_str()))
881 style
.Height
= tmpf
* Root
.FontSize
;
882 else if (unit
== "em")
883 style
.Height
= tmpf
* style
.FontSize
;
884 else if (unit
== "pt")
885 style
.FontSize
= tmpf
/ 0.75f
;
886 else if (unit
== "%")
887 style
.Height
= 0; // TODO: style.HeightRatio
893 if (it
->first
== "max-width")
896 if (getCssLength(tmpf
, unit
, it
->second
.c_str()))
899 style
.MaxWidth
= tmpf
* Root
.FontSize
;
900 else if (unit
== "em")
901 style
.MaxWidth
= tmpf
* style
.FontSize
;
902 else if (unit
== "pt")
903 style
.FontSize
= tmpf
/ 0.75f
;
904 else if (unit
== "%")
905 style
.MaxWidth
= 0; // TODO: style.MaxWidthRatio
907 style
.MaxWidth
= tmpf
;
911 if (it
->first
== "max-height")
914 if (getCssLength(tmpf
, unit
, it
->second
.c_str()))
917 style
.MaxHeight
= tmpf
* Root
.FontSize
;
918 else if (unit
== "em")
919 style
.MaxHeight
= tmpf
* style
.FontSize
;
920 else if (unit
== "pt")
921 style
.FontSize
= tmpf
/ 0.75f
;
922 else if (unit
== "%")
923 style
.MaxHeight
= 0; // TODO: style.MaxHeightRatio
925 style
.MaxHeight
= tmpf
;
929 if (it
->first
== "-ryzom-modulate-color")
932 if (it
->second
== "inherit")
933 style
.GlobalColor
= current
.GlobalColor
;
935 if (fromString(it
->second
, b
))
936 style
.GlobalColor
= b
;
939 if (it
->first
== "-ryzom-modulate-text-color")
942 if (it
->second
== "inherit")
943 style
.GlobalColorText
= current
.GlobalColorText
;
945 if (fromString(it
->second
, b
))
946 style
.GlobalColorText
= b
;
949 if (it
->first
== "background-color")
951 if (it
->second
== "inherit")
952 style
.Background
.color
= current
.Background
.color
;
953 else if (it
->second
== "transparent")
954 style
.Background
.color
= CRGBA(0, 0, 0, 0);
955 else if (it
->second
== "currentcolor")
956 style
.Background
.color
= style
.TextColor
;
958 scanHTMLColor(it
->second
.c_str(), style
.Background
.color
);
961 if (it
->first
== "-ryzom-background-color-over")
963 if (it
->second
== "inherit")
964 style
.BackgroundColorOver
= current
.BackgroundColorOver
;
965 else if (it
->second
== "transparent")
966 style
.BackgroundColorOver
= CRGBA(0, 0, 0, 0);
967 else if (it
->second
== "currentcolor")
968 style
.BackgroundColorOver
= style
.TextColor
;
970 scanHTMLColor(it
->second
.c_str(), style
.BackgroundColorOver
);
973 if (it
->first
== "background-image")
976 std::string image
= trim(it
->second
);
977 if (toLowerAscii(image
.substr(0, 4)) == "url(")
979 image
= image
.substr(4, image
.size()-5);
981 style
.StyleRules
[it
->first
] = trimQuotes(image
);
982 style
.Background
.setImage(style
.StyleRules
[it
->first
]);
985 if (it
->first
== "background-repeat")
987 style
.Background
.setRepeat(it
->second
);
988 // TODO: remove after removing old code that depends on this
990 std::string val
= toLowerAscii(trim(it
->second
));
991 std::vector
<std::string
> parts
;
992 splitParams(val
, ' ', parts
);
993 // check for "repeat repeat"
994 if (parts
.size() == 2 && parts
[0] == parts
[1])
997 style
.StyleRules
[it
->first
] = val
;
1000 if (it
->first
== "background-size")
1002 style
.Background
.setSize(it
->second
);
1003 // TODO: remove after removing old code that depends on this
1005 std::string val
= toLowerAscii(trim(it
->second
));
1006 std::vector
<std::string
> parts
;
1007 splitParams(val
, ' ', parts
);
1008 if (parts
.size() == 2 && parts
[0] == parts
[1])
1011 style
.StyleRules
[it
->first
] = val
;
1014 if (it
->first
== "background-position")
1016 // TODO: background-position-x, background-position-y
1017 style
.Background
.setPosition(it
->second
);
1020 if (it
->first
== "background-origin")
1022 style
.Background
.setOrigin(it
->second
);
1025 if (it
->first
== "background-clip")
1027 style
.Background
.setClip(it
->second
);
1030 if (it
->first
== "background-attachment")
1032 style
.Background
.setAttachment(it
->second
);
1036 // if outer element has underline set, then inner element cannot remove it
1037 if (current
.Underlined
)
1038 style
.Underlined
= current
.Underlined
;
1040 // if outer element has line-through set, then inner element cannot remove it
1041 if (current
.StrikeThrough
)
1042 style
.StrikeThrough
= current
.StrikeThrough
;
1045 // ***************************************************************************
1046 void CCssStyle::expandBackgroundShorthand(const std::string
&value
, TStyle
&style
) const
1048 // background: url(image.jpg) top center / 200px 200px no-repeat fixed padding-box content-box red;
1049 // background-image : url(image.jpg)
1050 // background-position : top center
1051 // background-size : 200px 200px
1052 // background-repeat : no-repeat
1053 // background-attachment : fixed
1054 // background-origin : padding-box
1055 // background-clip : content-box
1056 // background-color : red
1058 const uint nbProps
= 8;
1059 std::string props
[nbProps
] = {"background-image", "background-position", "background-size", "background-repeat",
1060 "background-attachment", "background-origin", "background-clip", "background-color"};
1061 std::string values
[nbProps
];
1062 bool found
[nbProps
] = {false};
1063 bool bgClipFound
= false;
1064 std::string bgClipValue
;
1065 std::string bgPositionX
;
1066 std::string bgPositionY
;
1069 std::vector
<std::string
> parts
;
1070 std::vector
<std::string
>::iterator it
;
1071 splitParams(value
, ' ', parts
);
1073 bool failed
= false;
1074 bool allowSize
= false;
1076 while(!failed
&& index
< parts
.size())
1078 std::string val
= toLowerAscii(parts
[index
]);
1079 bool matches
= false;
1080 for(uint i
= 0; i
< nbProps
; i
++)
1082 if (found
[i
]) continue;
1084 if (props
[i
] == "background-image")
1086 if (val
.substr(0, 4) == "url(")
1090 // use original value as 'val' is lowercase
1091 values
[i
] = parts
[index
];
1094 else if (props
[i
] == "background-position")
1103 // first loop -> true
1104 // second loop -> false && break
1107 if (next
>= parts
.size())
1110 val
= toLower(parts
[next
]);
1111 if (val
== "center")
1113 if (bgPositionX
.empty()) bgPositionX
= "center";
1114 if (bgPositionY
.empty()) bgPositionY
= "center";
1118 else if ((bgPositionX
.empty() || bgPositionX
== "center") && (val
== "left" || val
== "right"))
1121 // consume 'left|right'
1123 if (next
< parts
.size() && getCssLength(fval
, unit
, parts
[next
]))
1125 bgPositionX
+= " " + parts
[next
];
1126 // consume css length
1130 else if ((bgPositionY
.empty() || bgPositionY
== "center") && (val
== "top" || val
== "bottom"))
1133 // consume top|bottom
1135 if (next
< parts
.size() && getCssLength(fval
, unit
, parts
[next
]))
1137 bgPositionY
+= " " + parts
[next
];
1138 // consume css length
1142 else if (getCssLength(fval
, unit
, parts
[next
]))
1144 // override X only on first loop
1147 bgPositionX
= parts
[next
];
1149 else if (bgPositionY
.empty())
1151 bgPositionY
= parts
[next
];
1156 bgPositionX
.clear();
1157 bgPositionY
.clear();
1165 bgPositionX
.clear();
1166 bgPositionY
.clear();
1172 if (!bgPositionX
.empty() && !bgPositionY
.empty())
1176 // consume position values if there were any
1179 // look ahead to see if size is next
1180 if (next
< parts
.size() && parts
[next
] == "/")
1184 else if (props
[i
] == "background-size")
1186 if (allowSize
&& val
== "/")
1188 uint next
= index
+ 1;
1189 if (next
< parts
.size())
1191 val
= toLowerAscii(parts
[next
]);
1192 if (val
== "cover" || val
== "contain")
1205 if (val
== "auto" || getCssLength(fval
, unit
, val
))
1213 if (next
< parts
.size())
1215 val
= toLowerAscii(parts
[next
]);
1218 else if (getCssLength(fval
, unit
, val
))
1221 next
--; // not size token
1230 if (!h
.empty() && !v
.empty())
1234 values
[i
] = h
+ " " + v
;
1241 // no size, just '/'
1247 else if (props
[i
] == "background-repeat")
1249 if (val
== "repeat-x" || val
== "repeat-y" || val
== "repeat" || val
== "space" || val
== "round" || val
== "no-repeat")
1254 if (val
== "repeat-x")
1256 values
[i
] = "repeat no-repeat";
1258 else if (val
== "repeat-y")
1260 values
[i
] = "no-repeat repeat";
1264 std::string horiz
= val
;
1265 std::string vert
= val
;
1266 uint next
= index
+ 1;
1267 if (next
< parts
.size())
1269 val
= toLowerAscii(parts
[next
]);
1270 if (val
== "repeat" || val
== "space" || val
== "round" || val
== "no-repeat")
1279 values
[i
] = horiz
+ " " + vert
;
1283 else if (props
[i
] == "background-attachment")
1285 if (val
== "scroll" || val
== "fixed" || val
== "local")
1292 else if (props
[i
] == "background-origin")
1294 if (val
== "padding-box" || val
== "border-box" || val
== "content-box")
1300 // first time background-origin is set, also set background-clip
1308 else if (props
[i
] == "background-clip")
1310 if (val
== "text" || val
== "padding-box" || val
== "border-box" || val
== "content-box")
1318 else if (props
[i
] == "background-color")
1321 if (val
== "transparent" || val
== "currentcolor" || scanHTMLColor(val
.c_str(), color
))
1329 // prop was found and parsed
1338 // invalidate whole rule
1341 bgClipFound
= false;
1342 for(uint i
= 0; i
< nbProps
; i
++)
1348 // apply found styles or use default
1349 for(uint i
= 0; i
< nbProps
; i
++)
1353 if (props
[i
] == "background-position")
1355 style
["background-position"] = bgPositionX
+ " " + bgPositionY
;
1356 style
["background-position-x"] = bgPositionX
;
1357 style
["background-position-y"] = bgPositionY
;
1359 else if (props
[i
] == "background-clip")
1361 style
["background-clip"] = bgClipValue
;
1365 style
[props
[i
]] = values
[i
];
1370 // fill in default if one is not set
1371 if (props
[i
] == "background-image")
1373 style
[props
[i
]] = "";
1375 else if (props
[i
] == "background-position")
1377 style
[props
[i
]] = "0% 0%";
1378 style
["background-position-x"] = "left 0%";
1379 style
["background-position-y"] = "top 0%";
1381 else if (props
[i
] == "background-size")
1383 style
[props
[i
]] = "auto auto";
1385 else if (props
[i
] == "background-repeat")
1387 style
[props
[i
]] = "repeat";
1389 else if(props
[i
] == "background-attachment")
1391 style
[props
[i
]] = "scroll";
1393 else if(props
[i
] == "background-origin")
1395 style
[props
[i
]] = "padding-box";
1397 else if (props
[i
] == "background-clip")
1400 style
[props
[i
]] = bgClipValue
;
1402 style
[props
[i
]] = "border-box";
1404 else if (props
[i
] == "background-color")
1406 style
[props
[i
]] = "transparent";
1412 // ***************************************************************************
1413 bool CCssStyle::getShorthandIndices(const uint32 size
, uint8
&t
, uint8
&r
, uint8
&b
, uint8
&l
) const
1415 if (size
== 0 || size
> 4) return false;
1443 // ***************************************************************************
1444 bool CCssStyle::tryBorderWidthShorthand(const std::string
&prop
, const std::string
&value
, TStyle
&style
) const
1446 std::vector
<std::string
> parts
;
1447 splitParams(toLowerAscii(value
), ' ', parts
);
1451 // verify that parts are valid
1452 uint8 maxSize
= (prop
== "border" || prop
== "border-width") ? 4 : 1;
1453 bool hasTop
= (prop
== "border" || prop
== "border-width" || prop
== "border-top" || prop
== "border-top-width");
1454 bool hasRight
= (prop
== "border" || prop
== "border-width" || prop
== "border-right" || prop
== "border-right-width");
1455 bool hasBottom
= (prop
== "border" || prop
== "border-width" || prop
== "border-bottom" || prop
== "border-bottom-width");
1456 bool hasLeft
= (prop
== "border" || prop
== "border-width" || prop
== "border-left" || prop
== "border-left-width");
1457 if (parts
.size() > maxSize
|| (!hasTop
&& !hasRight
&& !hasBottom
&& !hasLeft
))
1462 for(uint i
= 0; i
< parts
.size(); ++i
)
1464 if (parts
[i
] != "inherit" && parts
[i
] != "thin" && parts
[i
] != "medium" && parts
[i
] != "thick"
1465 && !getCssLength(tmpf
, unit
, parts
[i
].c_str()))
1472 if (!getShorthandIndices(parts
.size(), t
, r
, b
, l
)) return false;
1473 if (hasTop
) style
["border-top-width"] = parts
[t
];
1474 if (hasRight
) style
["border-right-width"] = parts
[r
];
1475 if (hasBottom
) style
["border-bottom-width"] = parts
[b
];
1476 if (hasLeft
) style
["border-left-width"] = parts
[l
];
1480 // ***************************************************************************
1481 bool CCssStyle::tryBorderStyleShorthand(const std::string
&prop
, const std::string
&value
, TStyle
&style
) const
1483 std::vector
<std::string
> parts
;
1484 splitParams(toLowerAscii(value
), ' ', parts
);
1486 // verify that parts are valid
1487 uint8 maxSize
= (prop
== "border" || prop
== "border-style") ? 4 : 1;
1488 bool hasTop
= (prop
== "border" || prop
== "border-style" || prop
== "border-top" || prop
== "border-top-style");
1489 bool hasRight
= (prop
== "border" || prop
== "border-style" || prop
== "border-right" || prop
== "border-right-style");
1490 bool hasBottom
= (prop
== "border" || prop
== "border-style" || prop
== "border-bottom" || prop
== "border-bottom-style");
1491 bool hasLeft
= (prop
== "border" || prop
== "border-style" || prop
== "border-left" || prop
== "border-left-style");
1492 if (parts
.size() > maxSize
|| (!hasTop
&& !hasRight
&& !hasBottom
&& !hasLeft
))
1497 const uint nbValues
= 10;
1498 std::string values
[nbValues
] = {"none", "hidden", "dotted", "dashed",
1499 "solid", "double", "groove", "ridge", "inset", "outset"};
1501 for(uint i
= 0; i
< parts
.size(); ++i
)
1504 for(uint iValue
= 0; iValue
< nbValues
; ++iValue
)
1506 if (parts
[i
] == values
[iValue
])
1521 if (!getShorthandIndices(parts
.size(), t
, r
, b
, l
)) return false;
1522 if (hasTop
) style
["border-top-style"] = parts
[t
];
1523 if (hasRight
) style
["border-right-style"] = parts
[r
];
1524 if (hasBottom
) style
["border-bottom-style"] = parts
[b
];
1525 if (hasLeft
) style
["border-left-style"] = parts
[l
];
1529 // ***************************************************************************
1530 bool CCssStyle::tryBorderColorShorthand(const std::string
&prop
, const std::string
&value
, TStyle
&style
) const
1532 std::vector
<std::string
> parts
;
1533 splitParams(toLowerAscii(value
), ' ', parts
);
1536 // verify that parts are valid
1537 uint8 maxSize
= (prop
== "border" || prop
== "border-color") ? 4 : 1;
1538 bool hasTop
= (prop
== "border" || prop
== "border-color" || prop
== "border-top" || prop
== "border-top-color");
1539 bool hasRight
= (prop
== "border" || prop
== "border-color" || prop
== "border-right" || prop
== "border-right-color");
1540 bool hasBottom
= (prop
== "border" || prop
== "border-color" || prop
== "border-bottom" || prop
== "border-bottom-color");
1541 bool hasLeft
= (prop
== "border" || prop
== "border-color" || prop
== "border-left" || prop
== "border-left-color");
1542 if (parts
.size() > maxSize
|| (!hasTop
&& !hasRight
&& !hasBottom
&& !hasLeft
))
1547 for(uint i
= 0; i
< parts
.size(); ++i
)
1549 if (!scanHTMLColor(parts
[i
].c_str(), color
) && parts
[i
] != "currentcolor" && parts
[i
] != "inherit")
1554 if (!getShorthandIndices(parts
.size(), t
, r
, b
, l
)) return false;
1555 if (hasTop
) style
["border-top-color"] = parts
[t
];
1556 if (hasRight
) style
["border-right-color"] = parts
[r
];
1557 if (hasBottom
) style
["border-bottom-color"] = parts
[b
];
1558 if (hasLeft
) style
["border-left-color"] = parts
[l
];
1563 // ***************************************************************************
1564 void CCssStyle::expandBorderShorthand(const std::string
&prop
, const std::string
&value
, TStyle
&style
) const
1566 // border: 1px solid #000;
1567 bool hasTop
= (prop
== "border" || prop
== "border-top");
1568 bool hasRight
= (prop
== "border" || prop
== "border-right");
1569 bool hasBottom
= (prop
== "border" || prop
== "border-bottom");
1570 bool hasLeft
= (prop
== "border" || prop
== "border-left");
1572 bool foundWidth
= false;
1573 bool foundStyle
= false;
1574 bool foundColor
= false;
1577 std::vector
<std::string
> parts
;
1578 splitParams(toLowerAscii(value
), ' ', parts
);
1580 for(uint index
= 0; index
< parts
.size(); ++index
)
1582 bool matched
= false;
1585 matched
= foundWidth
= tryBorderWidthShorthand(prop
, parts
[index
], borderStyle
);
1588 if (!matched
&& !foundStyle
)
1590 matched
= foundStyle
= tryBorderStyleShorthand(prop
, parts
[index
], borderStyle
);
1593 if (!matched
&& !foundColor
)
1595 matched
= foundColor
= tryBorderColorShorthand(prop
, parts
[index
], borderStyle
);
1598 // invalid rule if nothing gets matched
1605 // apply rules that are present
1606 TStyle::const_iterator it
= borderStyle
.begin();
1607 while(it
!= borderStyle
.end())
1609 style
[it
->first
] = it
->second
;
1613 // reset those not present
1616 if (hasTop
) style
["border-top-width"] = "medium";
1617 if (hasRight
) style
["border-right-width"] = "medium";
1618 if (hasBottom
) style
["border-bottom-width"] = "medium";
1619 if (hasLeft
) style
["border-left-width"] = "medium";
1624 if (hasTop
) style
["border-top-style"] = "none";
1625 if (hasRight
) style
["border-right-style"] = "none";
1626 if (hasBottom
) style
["border-bottom-style"] = "none";
1627 if (hasLeft
) style
["border-left-style"] = "none";
1632 if (hasTop
) style
["border-top-color"] = "currentcolor";
1633 if (hasRight
) style
["border-right-color"] = "currentcolor";
1634 if (hasBottom
) style
["border-bottom-color"] = "currentcolor";
1635 if (hasLeft
) style
["border-left-color"] = "currentcolor";
1639 // ***************************************************************************
1640 void CCssStyle::expandPaddingShorthand(const std::string
&value
, TStyle
&style
) const
1642 std::vector
<std::string
> parts
;
1643 splitParams(toLowerAscii(value
), ' ', parts
);
1646 if (!getShorthandIndices(parts
.size(), t
, r
, b
, l
))
1649 style
["padding-top"] = parts
[t
];
1650 style
["padding-right"] = parts
[r
];
1651 style
["padding-bottom"] = parts
[b
];
1652 style
["padding-left"] = parts
[l
];
1655 // ***************************************************************************
1656 void CCssStyle::expandMarginShorthand(const std::string
&value
, TStyle
&style
) const
1658 std::vector
<std::string
> parts
;
1659 splitParams(toLowerAscii(value
), ' ', parts
);
1662 if (!getShorthandIndices(parts
.size(), t
, r
, b
, l
))
1665 style
["margin-top"] = parts
[t
];
1666 style
["margin-right"] = parts
[r
];
1667 style
["margin-bottom"] = parts
[b
];
1668 style
["margin-left"] = parts
[l
];
1671 // ***************************************************************************
1672 void CCssStyle::expandShorthand(const std::string
&prop
, const std::string
&value
, TStyle
&style
) const
1674 // if shorthand matches, then remove it after expansion
1677 if (prop
== "background")
1679 expandBackgroundShorthand(value
, style
);
1681 else if (prop
== "background-scale")
1683 // replace old ryzom specific rule with background-size
1686 style
["background-size"] = "auto";
1690 style
["background-size"] = "100%";
1693 else if (prop
== "border"
1694 || prop
== "border-top" || prop
== "border-right"
1695 || prop
== "border-bottom" || prop
== "border-left")
1697 // TODO: use enum or bitmap constant instead of passing a string name (prop)
1698 expandBorderShorthand(prop
, value
, style
);
1700 else if (prop
== "border-width")
1702 tryBorderWidthShorthand(prop
, value
, style
);
1704 else if (prop
== "border-style")
1706 tryBorderStyleShorthand(prop
, value
, style
);
1708 else if (prop
== "border-color")
1710 tryBorderColorShorthand(prop
, value
, style
);
1712 else if (prop
== "padding")
1714 expandPaddingShorthand(value
, style
);
1723 TStyle::iterator pos
= style
.find(prop
);
1724 if (pos
!= style
.end())
1729 // ***************************************************************************
1730 void CCssStyle::applyCssMinMax(sint32
&width
, sint32
&height
, sint32 minw
, sint32 minh
, sint32 maxw
, sint32 maxh
) const
1732 if (maxw
<= 0) maxw
= width
;
1733 if (maxh
<= 0) maxh
= height
;
1735 maxw
= std::max(minw
, maxw
);
1736 maxh
= std::max(minh
, maxh
);
1738 float ratio
= (float) width
/ std::max(1, height
);
1742 height
= std::max((sint32
)(maxw
/ratio
), minh
);
1747 height
= std::min((sint32
)(minw
/ ratio
), maxh
);
1751 width
= std::max((sint32
)(maxh
* ratio
), minw
);
1756 width
= std::min((sint32
)(minh
* ratio
), maxw
);
1759 if (width
> maxw
&& height
> maxh
)
1761 if (maxw
/width
<= maxh
/height
)
1764 height
= std::max(minh
, (sint32
)(maxw
/ ratio
));
1768 width
= std::max(minw
, (sint32
)(maxh
* ratio
));
1772 if (width
< minw
&& height
< minh
)
1774 if (minw
/ width
<= minh
/ height
)
1776 width
= std::min(maxw
, (sint32
)(minh
* ratio
));
1782 height
= std::min(maxh
, (sint32
)(minw
/ ratio
));
1785 if (width
< minw
&& height
> maxh
)
1790 if (width
> maxw
&& height
< minh
)
1797 // ***************************************************************************
1798 static void skipString(const std::string
&value
, std::string::size_type
&pos
)
1800 char quote
= value
[pos
];
1801 while(pos
< value
.size() && value
[pos
] != quote
)
1803 if (value
[pos
] == '\\')
1809 static void skipBlock(const std::string
&value
, std::string::size_type
&pos
, bool isString
)
1811 char openChar
= value
[pos
];
1812 char closeChar
= value
[pos
];
1813 if (openChar
== '(') closeChar
= ')';
1814 else if (openChar
== '[') closeChar
= ']';
1815 else if (openChar
== '{') closeChar
= '}';
1818 while(pos
< value
.size())
1820 char c
= value
[pos
];
1823 else if (!isString
&& (c
== '(' || c
== '[' || c
== '{'))
1824 skipBlock(value
, pos
, false);
1825 else if (c
== closeChar
)
1827 else if (c
== '"' || c
== '\'')
1832 skipBlock(value
, pos
, true);
1839 static void skipWhitespace(const std::string
&value
, std::string::size_type
&pos
)
1841 while(pos
< value
.size() && (value
[pos
] == ' ' || value
[pos
] == '\t' || value
[pos
] == '\r'))
1845 // ***************************************************************************
1846 bool CCssStyle::cssFuncVar(std::string
&func
, const TStyle
&styleRules
, const std::set
<std::string
> &seenProperties
) const
1848 // TODO: fails if var() is inside string, ie '--text: ".. var(...) .."';
1851 std::string::size_type pos
= func
.find("var(");
1852 if (pos
== std::string::npos
)
1855 // simple test to make sure 'var' is not substring
1856 if (pos
> 0 && (func
[pos
-1] != '_') && ((func
[pos
-1] >= 'a' && func
[pos
-1] <= 'z') || (func
[pos
-1] >= 'A' && func
[pos
-1] <='Z')))
1860 std::string::size_type funcStart
= pos
;
1861 std::string::size_type funcEnd
= funcStart
+ 3;
1862 skipBlock(func
, funcEnd
, false);
1867 std::string::size_type sep
= func
.find_first_of(",)", pos
);
1873 else if (sep
+ 1 == funcEnd
)
1875 // no whitespace between ',' and ')', ie 'var(--name,)'
1880 std::string name
= func
.substr(funcStart
+ 4, sep
- pos
);
1881 if (seenProperties
.count(name
) > 0)
1885 // if name is not defined or resolves to 'initial', use fallback
1886 bool found
= lookupPropertyValue(name
, value
, styleRules
);
1888 // check if substituted value has 'var()'
1889 std::set
<std::string
> newSeen
= seenProperties
;
1890 newSeen
.insert(name
);
1891 found
= cssFuncVar(value
, styleRules
, newSeen
);
1892 if (value
== "initial")
1896 // --name failed and we have fallback
1897 if (!found
&& func
[sep
] == ',')
1900 skipWhitespace(func
, sep
);
1902 value
= func
.substr(sep
, funcEnd
- sep
);
1909 // check if substituted fallback has 'var()'
1910 std::set
<std::string
> newSeen
= seenProperties
;
1911 newSeen
.insert(name
);
1912 found
= cssFuncVar(value
, styleRules
, newSeen
);
1913 if (value
== "initial")
1918 // invalidate property as both name and fallback failed
1922 // everything before 'var(' and after ')'
1925 result
= trim(func
.substr(0, funcStart
)) + " ";
1927 result
+= trim(value
);
1928 if ((funcEnd
+1) < func
.size())
1929 result
+= " " + trim(func
.substr(funcEnd
+1));
1931 // check replaced string for var()
1932 std::set
<std::string
> newSeen
= seenProperties
;
1933 newSeen
.insert(name
);
1934 bool success
= cssFuncVar(result
, styleRules
, newSeen
);
1935 if (result
== "initial")
1942 // ***************************************************************************
1943 bool CCssStyle::lookupPropertyValue(const std::string
&name
, std::string
&value
, const TStyle
&styleRules
) const
1945 bool success
= true;
1946 TStyle::const_iterator it
= styleRules
.find(name
);
1947 if (it
!= styleRules
.end())
1949 else if (Current
.hasStyle(name
))
1950 value
= Current
.getStyle(name
);
1954 if (success
&& value
!= "inherit")
1957 std::vector
<CStyleParams
>::const_reverse_iterator rit
= _StyleStack
.rbegin();
1958 for(; rit
!= _StyleStack
.rend(); ++rit
)
1960 if (rit
->hasStyle(name
))
1962 value
= rit
->getStyle(name
);
1963 if (value
!= "inherit")