1 /*
2 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3 *
4 * See the LICENSE file for terms of use.
5 */
6 #include "Wt/WApplication.h"
7 #include "Wt/WEnvironment.h"
8 #include "Wt/WException.h"
9 #include "Wt/WLength.h"
10 #include "Wt/WLogger.h"
11
12 #include "WebUtils.h"
13
14 #include <cstring>
15 #include <boost/algorithm/string.hpp>
16
17 namespace Wt {
18
19 LOGGER("WLength");
20
21 WLength WLength::Auto;
22
WLength()23 WLength::WLength()
24 : auto_(true),
25 unit_(LengthUnit::Pixel),
26 value_(-1)
27 { }
28
WLength(const std::string & str)29 WLength::WLength(const std::string &str)
30 {
31 parseCssString(str.c_str());
32 }
33
parseCssString(const char * s)34 void WLength::parseCssString(const char *s)
35 {
36 auto_ = false;
37 unit_ = LengthUnit::Pixel;
38 value_ = -1;
39
40 if (std::string("auto") == s) {
41 auto_ = true;
42 return;
43 }
44
45 char *end = nullptr;
46 #ifndef WT_TARGET_JAVA
47 value_ = std::strtod(s, &end);
48 #else
49 Utils::stringToDouble(s, &end, value_);
50 #endif
51
52 if (s == end) {
53 LOG_ERROR("cannot parse CSS length: '" << s << "'");
54 auto_ = true;
55 return;
56 }
57
58 std::string unit(end);
59 boost::trim(unit);
60
61 if (unit == "em")
62 unit_ = LengthUnit::FontEm;
63 else if (unit == "ex")
64 unit_ = LengthUnit::FontEx;
65 else if (unit.empty() || unit == "px")
66 unit_ = LengthUnit::Pixel;
67 else if (unit == "in")
68 unit_ = LengthUnit::Inch;
69 else if (unit == "cm")
70 unit_ = LengthUnit::Centimeter;
71 else if (unit == "mm")
72 unit_ = LengthUnit::Millimeter;
73 else if (unit == "pt")
74 unit_ = LengthUnit::Point;
75 else if (unit == "pc")
76 unit_ = LengthUnit::Pica;
77 else if (unit == "%")
78 unit_ = LengthUnit::Percentage;
79 else if (unit == "vw")
80 unit_ = LengthUnit::ViewportWidth;
81 else if (unit == "vh")
82 unit_ = LengthUnit::ViewportHeight;
83 else if (unit == "vmin")
84 unit_ = LengthUnit::ViewportMin;
85 else if (unit == "vmax")
86 unit_ = LengthUnit::ViewportMax;
87 else {
88 LOG_ERROR("unrecognized unit in '" << s << "'");
89 auto_ = true;
90 value_ = -1;
91 unit_ = LengthUnit::Pixel;
92 }
93 }
94
WLength(double value,LengthUnit unit)95 WLength::WLength(double value, LengthUnit unit)
96 : auto_(false),
97 value_(value)
98 {
99 setUnit(unit);
100 }
101
setUnit(LengthUnit unit)102 void WLength::setUnit(LengthUnit unit)
103 {
104 unit_ = unit;
105 }
106
107 bool WLength::operator== (const WLength& other) const
108 {
109 return
110 auto_ == other.auto_
111 && unit_ == other.unit_
112 && value_ == other.value_;
113 }
114
115 bool WLength::operator!= (const WLength& other) const
116 {
117 return !(*this == other);
118 }
119
cssText()120 const std::string WLength::cssText() const
121 {
122 static const char *unitText[]
123 = { "em", "ex", "px", "in", "cm", "mm", "pt", "pc", "%", "vw", "vh", "vmin", "vmax" };
124
125 if (auto_)
126 return "auto";
127 else {
128 #ifndef WT_TARGET_JAVA
129 char buf[30];
130 Utils::round_css_str(value_, 1, buf);
131 if (unit_ == LengthUnit::ViewportMin) {
132 WApplication *app = WApplication::instance();
133 if (app && app->environment().agentIsIElt(10)) {
134 std::strcat(buf, "vm");
135 } else {
136 std::strcat(buf, "vmin");
137 }
138 } else {
139 std::strcat(buf, unitText[static_cast<unsigned int>(unit_)]);
140 }
141 return buf;
142 #else
143 return std::to_string(value_) + unitText[static_cast<unsigned int>(unit_)];
144 #endif
145 }
146 }
147
toPixels(double fontSize)148 double WLength::toPixels(double fontSize) const
149 {
150 static const double pxPerPt = 4.0/3.0;
151 static const double unitFactor[]
152 = { 1,
153 72 * pxPerPt, // 72 'CSS'points in an inch
154 72 / 2.54 * pxPerPt, // 2.54 cm in an inch
155 72 / 25.4 * pxPerPt, // 25.4 mm in an inch
156 pxPerPt,
157 12 * pxPerPt }; // 12 points per pica
158
159 if (auto_)
160 return 0;
161 else
162 if (unit_ == LengthUnit::FontEm)
163 return value_ * fontSize;
164 else if (unit_ == LengthUnit::FontEx)
165 return value_ * fontSize / 2.0; // approximate: ex/em is 0.46 to 0.56...
166 else if (unit_ == LengthUnit::Percentage ||
167 unit_ == LengthUnit::ViewportWidth ||
168 unit_ == LengthUnit::ViewportHeight ||
169 unit_ == LengthUnit::ViewportMin ||
170 unit_ == LengthUnit::ViewportMax)
171 return value_ * fontSize / 100.0; // assuming relative to font size...
172 else
173 return value_ * unitFactor[static_cast<unsigned int>(unit_) - 2];
174 }
175
176 }
177