]> git.mxchange.org Git - simgear.git/blob - simgear/misc/CSSBorder.cxx
Canvas: separate CSSBorder parsing from image.
[simgear.git] / simgear / misc / CSSBorder.cxx
1 // Parse and represent CSS border definitions (eg. margin, border-image-width)
2 //
3 // Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Library General Public
7 // License as published by the Free Software Foundation; either
8 // version 2 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // Library General Public License for more details.
14 //
15 // You should have received a copy of the GNU Library General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
18
19 #include "CSSBorder.hxx"
20
21 #include <boost/lexical_cast.hpp>
22 #include <boost/range.hpp>
23 #include <boost/tokenizer.hpp>
24
25 namespace simgear
26 {
27
28   //----------------------------------------------------------------------------
29   bool CSSBorder::isValid() const
30   {
31     return valid;
32   }
33
34   //----------------------------------------------------------------------------
35   bool CSSBorder::isNone() const
36   {
37     return !valid
38         || (  offsets.t == 0
39            && offsets.r == 0
40            && offsets.b == 0
41            && offsets.l == 0 );
42   }
43
44   //----------------------------------------------------------------------------
45   const std::string& CSSBorder::getKeyword() const
46   {
47     return keyword;
48   }
49
50   //----------------------------------------------------------------------------
51   CSSBorder::Offsets CSSBorder::getRelOffsets(const SGRect<int>& dim) const
52   {
53     Offsets ret;
54     for(int i = 0; i < 4; ++i)
55     {
56       ret.val[i] = offsets.val[i];
57       if( !types.rel[i] )
58         ret.val[i] /= (i & 1) ? dim.height() : dim.width();
59     }
60     return ret;
61   }
62
63   //----------------------------------------------------------------------------
64   CSSBorder::Offsets CSSBorder::getAbsOffsets(const SGRect<int>& dim) const
65   {
66     Offsets ret;
67     for(int i = 0; i < 4; ++i)
68     {
69       ret.val[i] = offsets.val[i];
70       if( types.rel[i] )
71         ret.val[i] *= (i & 1) ? dim.height() : dim.width();
72     }
73     return ret;
74   }
75
76   //----------------------------------------------------------------------------
77   CSSBorder CSSBorder::parse(const std::string& str)
78   {
79     if( str.empty() )
80       return CSSBorder();
81
82     // [<number>'%'?]{1,4} (top[,right[,bottom[,left]]])
83     //
84     // Percentages are relative to the size of the image: the width of the
85     // image for the horizontal offsets, the height for vertical offsets.
86     // Numbers represent pixels in the image.
87     int c = 0;
88     CSSBorder ret;
89
90     typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
91     const boost::char_separator<char> del(" \t\n");
92
93     tokenizer tokens(str.begin(), str.end(), del);
94     for( tokenizer::const_iterator tok = tokens.begin();
95          tok != tokens.end() && c < 4;
96          ++tok )
97     {
98       if( isalpha(*tok->begin()) )
99         ret.keyword = *tok;
100       else
101       {
102         bool rel = ret.types.rel[c] = (*tok->rbegin() == '%');
103         ret.offsets.val[c] =
104           // Negative values are not allowed and values bigger than the size of
105           // the image are interpreted as ‘100%’. TODO check max
106           std::max
107           (
108             0.f,
109             boost::lexical_cast<float>
110             (
111               rel ? boost::make_iterator_range(tok->begin(), tok->end() - 1)
112                   : *tok
113             )
114             /
115             (rel ? 100 : 1)
116           );
117         ++c;
118       }
119     }
120
121     // When four values are specified, they set the offsets on the top, right,
122     // bottom and left sides in that order.
123
124 #define CSS_COPY_VAL(dest, src)\
125   {\
126     ret.offsets.val[dest] = ret.offsets.val[src];\
127     ret.types.rel[dest] = ret.types.rel[src];\
128   }
129
130     if( c < 4 )
131     {
132       if( c < 3 )
133       {
134         if( c < 2 )
135           // if the right is missing, it is the same as the top.
136           CSS_COPY_VAL(1, 0);
137
138         // if the bottom is missing, it is the same as the top
139         CSS_COPY_VAL(2, 0);
140       }
141
142       // If the left is missing, it is the same as the right
143       CSS_COPY_VAL(3, 1);
144     }
145
146 #undef CSS_COPY_VAL
147
148     if( ret.keyword == "none" )
149     {
150       memset(&ret.offsets, 0, sizeof(Offsets));
151       ret.keyword.clear();
152     }
153
154     ret.valid = true;
155     return ret;
156   }
157
158 } // namespace simgear