CalculatedStyleValue.cpp 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
  4. * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
  5. * Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include "CalculatedStyleValue.h"
  10. #include <LibWeb/CSS/Percentage.h>
  11. #include <LibWeb/CSS/PropertyID.h>
  12. namespace Web::CSS {
  13. static bool is_number(CalculatedStyleValue::ResolvedType type)
  14. {
  15. return type == CalculatedStyleValue::ResolvedType::Number || type == CalculatedStyleValue::ResolvedType::Integer;
  16. }
  17. static bool is_dimension(CalculatedStyleValue::ResolvedType type)
  18. {
  19. return type != CalculatedStyleValue::ResolvedType::Number
  20. && type != CalculatedStyleValue::ResolvedType::Integer
  21. && type != CalculatedStyleValue::ResolvedType::Percentage;
  22. }
  23. static double resolve_value_radians(CalculatedStyleValue::CalculationResult::Value value)
  24. {
  25. return value.visit(
  26. [](Number const& number) { return number.value(); },
  27. [](Angle const& angle) { return angle.to_radians(); },
  28. [](auto const&) { VERIFY_NOT_REACHED(); return 0.0; });
  29. }
  30. static double resolve_value(CalculatedStyleValue::CalculationResult::Value value, Optional<Length::ResolutionContext const&> context)
  31. {
  32. return value.visit(
  33. [](Number const& number) { return number.value(); },
  34. [](Angle const& angle) { return angle.to_degrees(); },
  35. [](Frequency const& frequency) { return frequency.to_hertz(); },
  36. [&context](Length const& length) { return length.to_px(*context).to_double(); },
  37. [](Percentage const& percentage) { return percentage.value(); },
  38. [](Time const& time) { return time.to_seconds(); });
  39. }
  40. static Optional<CSSNumericType> add_the_types(Vector<NonnullOwnPtr<CalculationNode>> const& nodes, PropertyID property_id)
  41. {
  42. Optional<CSSNumericType> left_type;
  43. for (auto const& value : nodes) {
  44. auto right_type = value->determine_type(property_id);
  45. if (!right_type.has_value())
  46. return {};
  47. if (left_type.has_value()) {
  48. left_type = left_type->added_to(right_type.value());
  49. } else {
  50. left_type = right_type;
  51. }
  52. if (!left_type.has_value())
  53. return {};
  54. }
  55. return left_type;
  56. }
  57. static CalculatedStyleValue::CalculationResult to_resolved_type(CalculatedStyleValue::ResolvedType type, double value)
  58. {
  59. switch (type) {
  60. case CalculatedStyleValue::ResolvedType::Integer:
  61. return { Number(Number::Type::Integer, value) };
  62. case CalculatedStyleValue::ResolvedType::Number:
  63. return { Number(Number::Type::Number, value) };
  64. case CalculatedStyleValue::ResolvedType::Angle:
  65. return { Angle::make_degrees(value) };
  66. case CalculatedStyleValue::ResolvedType::Frequency:
  67. return { Frequency::make_hertz(value) };
  68. case CalculatedStyleValue::ResolvedType::Length:
  69. return { Length::make_px(value) };
  70. case CalculatedStyleValue::ResolvedType::Percentage:
  71. return { Percentage(value) };
  72. case CalculatedStyleValue::ResolvedType::Time:
  73. return { Time::make_seconds(value) };
  74. }
  75. VERIFY_NOT_REACHED();
  76. }
  77. Optional<CalculationNode::ConstantType> CalculationNode::constant_type_from_string(StringView string)
  78. {
  79. if (string.equals_ignoring_ascii_case("e"sv))
  80. return CalculationNode::ConstantType::E;
  81. if (string.equals_ignoring_ascii_case("pi"sv))
  82. return CalculationNode::ConstantType::Pi;
  83. if (string.equals_ignoring_ascii_case("infinity"sv))
  84. return CalculationNode::ConstantType::Infinity;
  85. if (string.equals_ignoring_ascii_case("-infinity"sv))
  86. return CalculationNode::ConstantType::MinusInfinity;
  87. if (string.equals_ignoring_ascii_case("NaN"sv))
  88. return CalculationNode::ConstantType::NaN;
  89. return {};
  90. }
  91. CalculationNode::CalculationNode(Type type)
  92. : m_type(type)
  93. {
  94. }
  95. CalculationNode::~CalculationNode() = default;
  96. NonnullOwnPtr<NumericCalculationNode> NumericCalculationNode::create(NumericValue value)
  97. {
  98. return adopt_own(*new (nothrow) NumericCalculationNode(move(value)));
  99. }
  100. NumericCalculationNode::NumericCalculationNode(NumericValue value)
  101. : CalculationNode(Type::Numeric)
  102. , m_value(move(value))
  103. {
  104. }
  105. NumericCalculationNode::~NumericCalculationNode() = default;
  106. String NumericCalculationNode::to_string() const
  107. {
  108. return m_value.visit([](auto& value) { return value.to_string(); });
  109. }
  110. Optional<CalculatedStyleValue::ResolvedType> NumericCalculationNode::resolved_type() const
  111. {
  112. return m_value.visit(
  113. [](Number const&) { return CalculatedStyleValue::ResolvedType::Number; },
  114. [](Angle const&) { return CalculatedStyleValue::ResolvedType::Angle; },
  115. [](Frequency const&) { return CalculatedStyleValue::ResolvedType::Frequency; },
  116. [](Length const&) { return CalculatedStyleValue::ResolvedType::Length; },
  117. [](Percentage const&) { return CalculatedStyleValue::ResolvedType::Percentage; },
  118. [](Time const&) { return CalculatedStyleValue::ResolvedType::Time; });
  119. }
  120. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  121. Optional<CSSNumericType> NumericCalculationNode::determine_type(PropertyID property_id) const
  122. {
  123. // Anything else is a terminal value, whose type is determined based on its CSS type:
  124. return m_value.visit(
  125. [](Number const&) {
  126. // -> <number>
  127. // -> <integer>
  128. // the type is «[ ]» (empty map)
  129. return CSSNumericType {};
  130. },
  131. [](Length const&) {
  132. // -> <length>
  133. // the type is «[ "length" → 1 ]»
  134. return CSSNumericType { CSSNumericType::BaseType::Length, 1 };
  135. },
  136. [](Angle const&) {
  137. // -> <angle>
  138. // the type is «[ "angle" → 1 ]»
  139. return CSSNumericType { CSSNumericType::BaseType::Angle, 1 };
  140. },
  141. [](Time const&) {
  142. // -> <time>
  143. // the type is «[ "time" → 1 ]»
  144. return CSSNumericType { CSSNumericType::BaseType::Time, 1 };
  145. },
  146. [](Frequency const&) {
  147. // -> <frequency>
  148. // the type is «[ "frequency" → 1 ]»
  149. return CSSNumericType { CSSNumericType::BaseType::Frequency, 1 };
  150. },
  151. // FIXME: <resolution>
  152. // FIXME: <flex>
  153. // NOTE: <calc-constant> is a separate node type. (FIXME: Should it be?)
  154. [property_id](Percentage const&) {
  155. // -> <percentage>
  156. // If, in the context in which the math function containing this calculation is placed,
  157. // <percentage>s are resolved relative to another type of value (such as in width,
  158. // where <percentage> is resolved against a <length>), and that other type is not <number>,
  159. // the type is determined as the other type.
  160. auto percentage_resolved_type = property_resolves_percentages_relative_to(property_id);
  161. if (percentage_resolved_type.has_value() && percentage_resolved_type != ValueType::Number && percentage_resolved_type != ValueType::Percentage) {
  162. auto base_type = CSSNumericType::base_type_from_value_type(*percentage_resolved_type);
  163. VERIFY(base_type.has_value());
  164. return CSSNumericType { base_type.value(), 1 };
  165. }
  166. // Otherwise, the type is «[ "percent" → 1 ]».
  167. return CSSNumericType { CSSNumericType::BaseType::Percent, 1 };
  168. });
  169. // In all cases, the associated percent hint is null.
  170. }
  171. bool NumericCalculationNode::contains_percentage() const
  172. {
  173. return m_value.has<Percentage>();
  174. }
  175. CalculatedStyleValue::CalculationResult NumericCalculationNode::resolve(Optional<Length::ResolutionContext const&>, CalculatedStyleValue::PercentageBasis const&) const
  176. {
  177. return m_value;
  178. }
  179. void NumericCalculationNode::dump(StringBuilder& builder, int indent) const
  180. {
  181. builder.appendff("{: >{}}NUMERIC({})\n", "", indent, m_value.visit([](auto& it) { return it.to_string(); }));
  182. }
  183. NonnullOwnPtr<SumCalculationNode> SumCalculationNode::create(Vector<NonnullOwnPtr<CalculationNode>> values)
  184. {
  185. return adopt_own(*new (nothrow) SumCalculationNode(move(values)));
  186. }
  187. SumCalculationNode::SumCalculationNode(Vector<NonnullOwnPtr<CalculationNode>> values)
  188. : CalculationNode(Type::Sum)
  189. , m_values(move(values))
  190. {
  191. VERIFY(!m_values.is_empty());
  192. }
  193. SumCalculationNode::~SumCalculationNode() = default;
  194. String SumCalculationNode::to_string() const
  195. {
  196. bool first = true;
  197. StringBuilder builder;
  198. for (auto& value : m_values) {
  199. if (!first)
  200. builder.append(" + "sv);
  201. builder.append(value->to_string());
  202. first = false;
  203. }
  204. return MUST(builder.to_string());
  205. }
  206. Optional<CalculatedStyleValue::ResolvedType> SumCalculationNode::resolved_type() const
  207. {
  208. // FIXME: Implement https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  209. // For now, this is just ad-hoc, based on the old implementation.
  210. Optional<CalculatedStyleValue::ResolvedType> type;
  211. for (auto const& value : m_values) {
  212. auto maybe_value_type = value->resolved_type();
  213. if (!maybe_value_type.has_value())
  214. return {};
  215. auto value_type = maybe_value_type.value();
  216. if (!type.has_value()) {
  217. type = value_type;
  218. continue;
  219. }
  220. // At + or -, check that both sides have the same type, or that one side is a <number> and the other is an <integer>.
  221. // If both sides are the same type, resolve to that type.
  222. if (value_type == type)
  223. continue;
  224. // If one side is a <number> and the other is an <integer>, resolve to <number>.
  225. if (is_number(*type) && is_number(value_type)) {
  226. type = CalculatedStyleValue::ResolvedType::Number;
  227. continue;
  228. }
  229. // FIXME: calc() handles <percentage> by allowing them to pretend to be whatever <dimension> type is allowed at this location.
  230. // Since we can't easily check what that type is, we just allow <percentage> to combine with any other <dimension> type.
  231. if (type == CalculatedStyleValue::ResolvedType::Percentage && is_dimension(value_type)) {
  232. type = value_type;
  233. continue;
  234. }
  235. if (is_dimension(*type) && value_type == CalculatedStyleValue::ResolvedType::Percentage)
  236. continue;
  237. return {};
  238. }
  239. return type;
  240. }
  241. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  242. Optional<CSSNumericType> SumCalculationNode::determine_type(PropertyID property_id) const
  243. {
  244. // At a + or - sub-expression, attempt to add the types of the left and right arguments.
  245. // If this returns failure, the entire calculation’s type is failure.
  246. // Otherwise, the sub-expression’s type is the returned type.
  247. return add_the_types(m_values, property_id);
  248. }
  249. bool SumCalculationNode::contains_percentage() const
  250. {
  251. for (auto const& value : m_values) {
  252. if (value->contains_percentage())
  253. return true;
  254. }
  255. return false;
  256. }
  257. CalculatedStyleValue::CalculationResult SumCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  258. {
  259. Optional<CalculatedStyleValue::CalculationResult> total;
  260. for (auto& additional_product : m_values) {
  261. auto additional_value = additional_product->resolve(context, percentage_basis);
  262. if (!total.has_value()) {
  263. total = additional_value;
  264. continue;
  265. }
  266. total->add(additional_value, context, percentage_basis);
  267. }
  268. return total.value();
  269. }
  270. void SumCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  271. {
  272. for (auto& item : m_values) {
  273. item->for_each_child_node(callback);
  274. callback(item);
  275. }
  276. }
  277. void SumCalculationNode::dump(StringBuilder& builder, int indent) const
  278. {
  279. builder.appendff("{: >{}}SUM:\n", "", indent);
  280. for (auto const& item : m_values)
  281. item->dump(builder, indent + 2);
  282. }
  283. NonnullOwnPtr<ProductCalculationNode> ProductCalculationNode::create(Vector<NonnullOwnPtr<CalculationNode>> values)
  284. {
  285. return adopt_own(*new (nothrow) ProductCalculationNode(move(values)));
  286. }
  287. ProductCalculationNode::ProductCalculationNode(Vector<NonnullOwnPtr<CalculationNode>> values)
  288. : CalculationNode(Type::Product)
  289. , m_values(move(values))
  290. {
  291. VERIFY(!m_values.is_empty());
  292. }
  293. ProductCalculationNode::~ProductCalculationNode() = default;
  294. String ProductCalculationNode::to_string() const
  295. {
  296. bool first = true;
  297. StringBuilder builder;
  298. for (auto& value : m_values) {
  299. if (!first)
  300. builder.append(" * "sv);
  301. builder.append(value->to_string());
  302. first = false;
  303. }
  304. return MUST(builder.to_string());
  305. }
  306. Optional<CalculatedStyleValue::ResolvedType> ProductCalculationNode::resolved_type() const
  307. {
  308. // FIXME: Implement https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  309. // For now, this is just ad-hoc, based on the old implementation.
  310. Optional<CalculatedStyleValue::ResolvedType> type;
  311. for (auto const& value : m_values) {
  312. auto maybe_value_type = value->resolved_type();
  313. if (!maybe_value_type.has_value())
  314. return {};
  315. auto value_type = maybe_value_type.value();
  316. if (!type.has_value()) {
  317. type = value_type;
  318. continue;
  319. }
  320. // At *, check that at least one side is <number>.
  321. if (!(is_number(*type) || is_number(value_type)))
  322. return {};
  323. // If both sides are <integer>, resolve to <integer>.
  324. if (type == CalculatedStyleValue::ResolvedType::Integer && value_type == CalculatedStyleValue::ResolvedType::Integer) {
  325. type = CalculatedStyleValue::ResolvedType::Integer;
  326. } else {
  327. // Otherwise, resolve to the type of the other side.
  328. if (is_number(*type))
  329. type = value_type;
  330. }
  331. }
  332. return type;
  333. }
  334. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  335. Optional<CSSNumericType> ProductCalculationNode::determine_type(PropertyID property_id) const
  336. {
  337. // At a * sub-expression, multiply the types of the left and right arguments.
  338. // The sub-expression’s type is the returned result.
  339. Optional<CSSNumericType> left_type;
  340. for (auto const& value : m_values) {
  341. auto right_type = value->determine_type(property_id);
  342. if (!right_type.has_value())
  343. return {};
  344. if (left_type.has_value()) {
  345. left_type = left_type->multiplied_by(right_type.value());
  346. } else {
  347. left_type = right_type;
  348. }
  349. if (!left_type.has_value())
  350. return {};
  351. }
  352. return left_type;
  353. }
  354. bool ProductCalculationNode::contains_percentage() const
  355. {
  356. for (auto const& value : m_values) {
  357. if (value->contains_percentage())
  358. return true;
  359. }
  360. return false;
  361. }
  362. CalculatedStyleValue::CalculationResult ProductCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  363. {
  364. Optional<CalculatedStyleValue::CalculationResult> total;
  365. for (auto& additional_product : m_values) {
  366. auto additional_value = additional_product->resolve(context, percentage_basis);
  367. if (!total.has_value()) {
  368. total = additional_value;
  369. continue;
  370. }
  371. total->multiply_by(additional_value, context);
  372. }
  373. return total.value();
  374. }
  375. void ProductCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  376. {
  377. for (auto& item : m_values) {
  378. item->for_each_child_node(callback);
  379. callback(item);
  380. }
  381. }
  382. void ProductCalculationNode::dump(StringBuilder& builder, int indent) const
  383. {
  384. builder.appendff("{: >{}}PRODUCT:\n", "", indent);
  385. for (auto const& item : m_values)
  386. item->dump(builder, indent + 2);
  387. }
  388. NonnullOwnPtr<NegateCalculationNode> NegateCalculationNode::create(NonnullOwnPtr<Web::CSS::CalculationNode> value)
  389. {
  390. return adopt_own(*new (nothrow) NegateCalculationNode(move(value)));
  391. }
  392. NegateCalculationNode::NegateCalculationNode(NonnullOwnPtr<CalculationNode> value)
  393. : CalculationNode(Type::Negate)
  394. , m_value(move(value))
  395. {
  396. }
  397. NegateCalculationNode::~NegateCalculationNode() = default;
  398. String NegateCalculationNode::to_string() const
  399. {
  400. return MUST(String::formatted("(0 - {})", m_value->to_string()));
  401. }
  402. Optional<CalculatedStyleValue::ResolvedType> NegateCalculationNode::resolved_type() const
  403. {
  404. return m_value->resolved_type();
  405. }
  406. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  407. Optional<CSSNumericType> NegateCalculationNode::determine_type(PropertyID property_id) const
  408. {
  409. // NOTE: `- foo` doesn't change the type
  410. return m_value->determine_type(property_id);
  411. }
  412. bool NegateCalculationNode::contains_percentage() const
  413. {
  414. return m_value->contains_percentage();
  415. }
  416. CalculatedStyleValue::CalculationResult NegateCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  417. {
  418. auto child_value = m_value->resolve(context, percentage_basis);
  419. child_value.negate();
  420. return child_value;
  421. }
  422. void NegateCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  423. {
  424. m_value->for_each_child_node(callback);
  425. callback(m_value);
  426. }
  427. void NegateCalculationNode::dump(StringBuilder& builder, int indent) const
  428. {
  429. builder.appendff("{: >{}}NEGATE:\n", "", indent);
  430. m_value->dump(builder, indent + 2);
  431. }
  432. NonnullOwnPtr<InvertCalculationNode> InvertCalculationNode::create(NonnullOwnPtr<Web::CSS::CalculationNode> value)
  433. {
  434. return adopt_own(*new (nothrow) InvertCalculationNode(move(value)));
  435. }
  436. InvertCalculationNode::InvertCalculationNode(NonnullOwnPtr<CalculationNode> value)
  437. : CalculationNode(Type::Invert)
  438. , m_value(move(value))
  439. {
  440. }
  441. InvertCalculationNode::~InvertCalculationNode() = default;
  442. String InvertCalculationNode::to_string() const
  443. {
  444. return MUST(String::formatted("(1 / {})", m_value->to_string()));
  445. }
  446. Optional<CalculatedStyleValue::ResolvedType> InvertCalculationNode::resolved_type() const
  447. {
  448. auto type = m_value->resolved_type();
  449. if (type == CalculatedStyleValue::ResolvedType::Integer)
  450. return CalculatedStyleValue::ResolvedType::Number;
  451. return type;
  452. }
  453. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  454. Optional<CSSNumericType> InvertCalculationNode::determine_type(PropertyID property_id) const
  455. {
  456. // At a / sub-expression, let left type be the result of finding the types of its left argument,
  457. // and right type be the result of finding the types of its right argument and then inverting it.
  458. // The sub-expression’s type is the result of multiplying the left type and right type.
  459. // NOTE: An InvertCalculationNode only represents the right argument here, and the multiplication
  460. // is handled in the parent ProductCalculationNode.
  461. return m_value->determine_type(property_id).map([](auto& it) { return it.inverted(); });
  462. }
  463. bool InvertCalculationNode::contains_percentage() const
  464. {
  465. return m_value->contains_percentage();
  466. }
  467. CalculatedStyleValue::CalculationResult InvertCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  468. {
  469. auto child_value = m_value->resolve(context, percentage_basis);
  470. child_value.invert();
  471. return child_value;
  472. }
  473. void InvertCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  474. {
  475. m_value->for_each_child_node(callback);
  476. callback(m_value);
  477. }
  478. void InvertCalculationNode::dump(StringBuilder& builder, int indent) const
  479. {
  480. builder.appendff("{: >{}}INVERT:\n", "", indent);
  481. m_value->dump(builder, indent + 2);
  482. }
  483. NonnullOwnPtr<MinCalculationNode> MinCalculationNode::create(Vector<NonnullOwnPtr<Web::CSS::CalculationNode>> values)
  484. {
  485. return adopt_own(*new (nothrow) MinCalculationNode(move(values)));
  486. }
  487. MinCalculationNode::MinCalculationNode(Vector<NonnullOwnPtr<CalculationNode>> values)
  488. : CalculationNode(Type::Min)
  489. , m_values(move(values))
  490. {
  491. }
  492. MinCalculationNode::~MinCalculationNode() = default;
  493. String MinCalculationNode::to_string() const
  494. {
  495. StringBuilder builder;
  496. builder.append("min("sv);
  497. for (size_t i = 0; i < m_values.size(); ++i) {
  498. if (i != 0)
  499. builder.append(", "sv);
  500. builder.append(m_values[i]->to_string());
  501. }
  502. builder.append(")"sv);
  503. return MUST(builder.to_string());
  504. }
  505. Optional<CalculatedStyleValue::ResolvedType> MinCalculationNode::resolved_type() const
  506. {
  507. // NOTE: We check during parsing that all values have the same type.
  508. return m_values[0]->resolved_type();
  509. }
  510. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  511. Optional<CSSNumericType> MinCalculationNode::determine_type(PropertyID property_id) const
  512. {
  513. // The result of adding the types of its comma-separated calculations.
  514. return add_the_types(m_values, property_id);
  515. }
  516. bool MinCalculationNode::contains_percentage() const
  517. {
  518. for (auto const& value : m_values) {
  519. if (value->contains_percentage())
  520. return true;
  521. }
  522. return false;
  523. }
  524. CalculatedStyleValue::CalculationResult MinCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  525. {
  526. CalculatedStyleValue::CalculationResult smallest_node = m_values.first()->resolve(context, percentage_basis);
  527. auto smallest_value = resolve_value(smallest_node.value(), context);
  528. for (size_t i = 1; i < m_values.size(); i++) {
  529. auto child_resolved = m_values[i]->resolve(context, percentage_basis);
  530. auto child_value = resolve_value(child_resolved.value(), context);
  531. if (child_value < smallest_value) {
  532. smallest_value = child_value;
  533. smallest_node = child_resolved;
  534. }
  535. }
  536. return smallest_node;
  537. }
  538. void MinCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  539. {
  540. for (auto& value : m_values) {
  541. value->for_each_child_node(callback);
  542. callback(value);
  543. }
  544. }
  545. void MinCalculationNode::dump(StringBuilder& builder, int indent) const
  546. {
  547. builder.appendff("{: >{}}MIN:\n", "", indent);
  548. for (auto const& value : m_values)
  549. value->dump(builder, indent + 2);
  550. }
  551. NonnullOwnPtr<MaxCalculationNode> MaxCalculationNode::create(Vector<NonnullOwnPtr<Web::CSS::CalculationNode>> values)
  552. {
  553. return adopt_own(*new (nothrow) MaxCalculationNode(move(values)));
  554. }
  555. MaxCalculationNode::MaxCalculationNode(Vector<NonnullOwnPtr<CalculationNode>> values)
  556. : CalculationNode(Type::Max)
  557. , m_values(move(values))
  558. {
  559. }
  560. MaxCalculationNode::~MaxCalculationNode() = default;
  561. String MaxCalculationNode::to_string() const
  562. {
  563. StringBuilder builder;
  564. builder.append("max("sv);
  565. for (size_t i = 0; i < m_values.size(); ++i) {
  566. if (i != 0)
  567. builder.append(", "sv);
  568. builder.append(m_values[i]->to_string());
  569. }
  570. builder.append(")"sv);
  571. return MUST(builder.to_string());
  572. }
  573. Optional<CalculatedStyleValue::ResolvedType> MaxCalculationNode::resolved_type() const
  574. {
  575. // NOTE: We check during parsing that all values have the same type.
  576. return m_values[0]->resolved_type();
  577. }
  578. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  579. Optional<CSSNumericType> MaxCalculationNode::determine_type(PropertyID property_id) const
  580. {
  581. // The result of adding the types of its comma-separated calculations.
  582. return add_the_types(m_values, property_id);
  583. }
  584. bool MaxCalculationNode::contains_percentage() const
  585. {
  586. for (auto const& value : m_values) {
  587. if (value->contains_percentage())
  588. return true;
  589. }
  590. return false;
  591. }
  592. CalculatedStyleValue::CalculationResult MaxCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  593. {
  594. CalculatedStyleValue::CalculationResult largest_node = m_values.first()->resolve(context, percentage_basis);
  595. auto largest_value = resolve_value(largest_node.value(), context);
  596. for (size_t i = 1; i < m_values.size(); i++) {
  597. auto child_resolved = m_values[i]->resolve(context, percentage_basis);
  598. auto child_value = resolve_value(child_resolved.value(), context);
  599. if (child_value > largest_value) {
  600. largest_value = child_value;
  601. largest_node = child_resolved;
  602. }
  603. }
  604. return largest_node;
  605. }
  606. void MaxCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  607. {
  608. for (auto& value : m_values) {
  609. value->for_each_child_node(callback);
  610. callback(value);
  611. }
  612. }
  613. void MaxCalculationNode::dump(StringBuilder& builder, int indent) const
  614. {
  615. builder.appendff("{: >{}}MAX:\n", "", indent);
  616. for (auto const& value : m_values)
  617. value->dump(builder, indent + 2);
  618. }
  619. NonnullOwnPtr<ClampCalculationNode> ClampCalculationNode::create(NonnullOwnPtr<CalculationNode> min, NonnullOwnPtr<CalculationNode> center, NonnullOwnPtr<CalculationNode> max)
  620. {
  621. return adopt_own(*new (nothrow) ClampCalculationNode(move(min), move(center), move(max)));
  622. }
  623. ClampCalculationNode::ClampCalculationNode(NonnullOwnPtr<CalculationNode> min, NonnullOwnPtr<CalculationNode> center, NonnullOwnPtr<CalculationNode> max)
  624. : CalculationNode(Type::Clamp)
  625. , m_min_value(move(min))
  626. , m_center_value(move(center))
  627. , m_max_value(move(max))
  628. {
  629. }
  630. ClampCalculationNode::~ClampCalculationNode() = default;
  631. String ClampCalculationNode::to_string() const
  632. {
  633. StringBuilder builder;
  634. builder.append("clamp("sv);
  635. builder.append(m_min_value->to_string());
  636. builder.append(", "sv);
  637. builder.append(m_center_value->to_string());
  638. builder.append(", "sv);
  639. builder.append(m_max_value->to_string());
  640. builder.append(")"sv);
  641. return MUST(builder.to_string());
  642. }
  643. Optional<CalculatedStyleValue::ResolvedType> ClampCalculationNode::resolved_type() const
  644. {
  645. // NOTE: We check during parsing that all values have the same type.
  646. return m_min_value->resolved_type();
  647. }
  648. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  649. Optional<CSSNumericType> ClampCalculationNode::determine_type(PropertyID property_id) const
  650. {
  651. // The result of adding the types of its comma-separated calculations.
  652. auto min_type = m_min_value->determine_type(property_id);
  653. auto center_type = m_center_value->determine_type(property_id);
  654. auto max_type = m_max_value->determine_type(property_id);
  655. if (!min_type.has_value() || !center_type.has_value() || !max_type.has_value())
  656. return {};
  657. auto result = min_type->added_to(*center_type);
  658. if (!result.has_value())
  659. return {};
  660. return result->added_to(*max_type);
  661. }
  662. bool ClampCalculationNode::contains_percentage() const
  663. {
  664. return m_min_value->contains_percentage() || m_center_value->contains_percentage() || m_max_value->contains_percentage();
  665. }
  666. CalculatedStyleValue::CalculationResult ClampCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  667. {
  668. auto min_node = m_min_value->resolve(context, percentage_basis);
  669. auto center_node = m_center_value->resolve(context, percentage_basis);
  670. auto max_node = m_max_value->resolve(context, percentage_basis);
  671. auto min_value = resolve_value(min_node.value(), context);
  672. auto center_value = resolve_value(center_node.value(), context);
  673. auto max_value = resolve_value(max_node.value(), context);
  674. // NOTE: The value should be returned as "max(MIN, min(VAL, MAX))"
  675. auto chosen_value = max(min_value, min(center_value, max_value));
  676. if (chosen_value == min_value)
  677. return min_node;
  678. if (chosen_value == center_value)
  679. return center_node;
  680. if (chosen_value == max_value)
  681. return max_node;
  682. VERIFY_NOT_REACHED();
  683. }
  684. void ClampCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  685. {
  686. m_min_value->for_each_child_node(callback);
  687. m_center_value->for_each_child_node(callback);
  688. m_max_value->for_each_child_node(callback);
  689. callback(m_min_value);
  690. callback(m_center_value);
  691. callback(m_max_value);
  692. }
  693. void ClampCalculationNode::dump(StringBuilder& builder, int indent) const
  694. {
  695. builder.appendff("{: >{}}CLAMP:\n", "", indent);
  696. m_min_value->dump(builder, indent + 2);
  697. m_center_value->dump(builder, indent + 2);
  698. m_max_value->dump(builder, indent + 2);
  699. }
  700. NonnullOwnPtr<AbsCalculationNode> AbsCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  701. {
  702. return adopt_own(*new (nothrow) AbsCalculationNode(move(value)));
  703. }
  704. AbsCalculationNode::AbsCalculationNode(NonnullOwnPtr<CalculationNode> value)
  705. : CalculationNode(Type::Abs)
  706. , m_value(move(value))
  707. {
  708. }
  709. AbsCalculationNode::~AbsCalculationNode() = default;
  710. String AbsCalculationNode::to_string() const
  711. {
  712. StringBuilder builder;
  713. builder.append("abs("sv);
  714. builder.append(m_value->to_string());
  715. builder.append(")"sv);
  716. return MUST(builder.to_string());
  717. }
  718. Optional<CalculatedStyleValue::ResolvedType> AbsCalculationNode::resolved_type() const
  719. {
  720. return m_value->resolved_type();
  721. }
  722. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  723. Optional<CSSNumericType> AbsCalculationNode::determine_type(PropertyID property_id) const
  724. {
  725. // The type of its contained calculation.
  726. return m_value->determine_type(property_id);
  727. }
  728. bool AbsCalculationNode::contains_percentage() const
  729. {
  730. return m_value->contains_percentage();
  731. }
  732. CalculatedStyleValue::CalculationResult AbsCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  733. {
  734. auto resolved_type = m_value->resolved_type().value();
  735. auto node_a = m_value->resolve(context, percentage_basis);
  736. auto node_a_value = resolve_value(node_a.value(), context);
  737. if (node_a_value < 0)
  738. return to_resolved_type(resolved_type, -node_a_value);
  739. return node_a;
  740. }
  741. void AbsCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  742. {
  743. m_value->for_each_child_node(callback);
  744. callback(m_value);
  745. }
  746. void AbsCalculationNode::dump(StringBuilder& builder, int indent) const
  747. {
  748. builder.appendff("{: >{}}ABS: {}\n", "", indent, to_string());
  749. }
  750. NonnullOwnPtr<SignCalculationNode> SignCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  751. {
  752. return adopt_own(*new (nothrow) SignCalculationNode(move(value)));
  753. }
  754. SignCalculationNode::SignCalculationNode(NonnullOwnPtr<CalculationNode> value)
  755. : CalculationNode(Type::Sign)
  756. , m_value(move(value))
  757. {
  758. }
  759. SignCalculationNode::~SignCalculationNode() = default;
  760. String SignCalculationNode::to_string() const
  761. {
  762. StringBuilder builder;
  763. builder.append("sign("sv);
  764. builder.append(m_value->to_string());
  765. builder.append(")"sv);
  766. return MUST(builder.to_string());
  767. }
  768. Optional<CalculatedStyleValue::ResolvedType> SignCalculationNode::resolved_type() const
  769. {
  770. return CalculatedStyleValue::ResolvedType::Integer;
  771. }
  772. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  773. Optional<CSSNumericType> SignCalculationNode::determine_type(PropertyID) const
  774. {
  775. // «[ ]» (empty map).
  776. return CSSNumericType {};
  777. }
  778. bool SignCalculationNode::contains_percentage() const
  779. {
  780. return m_value->contains_percentage();
  781. }
  782. CalculatedStyleValue::CalculationResult SignCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  783. {
  784. auto node_a = m_value->resolve(context, percentage_basis);
  785. auto node_a_value = resolve_value(node_a.value(), context);
  786. if (node_a_value < 0)
  787. return { Number(Number::Type::Integer, -1) };
  788. if (node_a_value > 0)
  789. return { Number(Number::Type::Integer, 1) };
  790. return { Number(Number::Type::Integer, 0) };
  791. }
  792. void SignCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  793. {
  794. m_value->for_each_child_node(callback);
  795. callback(m_value);
  796. }
  797. void SignCalculationNode::dump(StringBuilder& builder, int indent) const
  798. {
  799. builder.appendff("{: >{}}SIGN: {}\n", "", indent, to_string());
  800. }
  801. NonnullOwnPtr<ConstantCalculationNode> ConstantCalculationNode::create(ConstantType constant)
  802. {
  803. return adopt_own(*new (nothrow) ConstantCalculationNode(constant));
  804. }
  805. ConstantCalculationNode::ConstantCalculationNode(ConstantType constant)
  806. : CalculationNode(Type::Constant)
  807. , m_constant(constant)
  808. {
  809. }
  810. ConstantCalculationNode::~ConstantCalculationNode() = default;
  811. String ConstantCalculationNode::to_string() const
  812. {
  813. switch (m_constant) {
  814. case CalculationNode::ConstantType::E:
  815. return "e"_string;
  816. case CalculationNode::ConstantType::Pi:
  817. return "pi"_string;
  818. case CalculationNode::ConstantType::Infinity:
  819. return "infinity"_string;
  820. case CalculationNode::ConstantType::MinusInfinity:
  821. return "-infinity"_string;
  822. case CalculationNode::ConstantType::NaN:
  823. return "NaN"_string;
  824. }
  825. VERIFY_NOT_REACHED();
  826. }
  827. Optional<CalculatedStyleValue::ResolvedType> ConstantCalculationNode::resolved_type() const
  828. {
  829. return CalculatedStyleValue::ResolvedType::Number;
  830. }
  831. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  832. Optional<CSSNumericType> ConstantCalculationNode::determine_type(PropertyID) const
  833. {
  834. // Anything else is a terminal value, whose type is determined based on its CSS type:
  835. // -> <calc-constant>
  836. // the type is «[ ]» (empty map)
  837. return CSSNumericType {};
  838. }
  839. CalculatedStyleValue::CalculationResult ConstantCalculationNode::resolve([[maybe_unused]] Optional<Length::ResolutionContext const&> context, [[maybe_unused]] CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  840. {
  841. switch (m_constant) {
  842. case CalculationNode::ConstantType::E:
  843. return { Number(Number::Type::Number, M_E) };
  844. case CalculationNode::ConstantType::Pi:
  845. return { Number(Number::Type::Number, M_PI) };
  846. // FIXME: We need to keep track of Infinity and NaN across all nodes, since they require special handling.
  847. case CalculationNode::ConstantType::Infinity:
  848. return { Number(Number::Type::Number, NumericLimits<double>::max()) };
  849. case CalculationNode::ConstantType::MinusInfinity:
  850. return { Number(Number::Type::Number, NumericLimits<double>::lowest()) };
  851. case CalculationNode::ConstantType::NaN:
  852. return { Number(Number::Type::Number, NAN) };
  853. }
  854. VERIFY_NOT_REACHED();
  855. }
  856. void ConstantCalculationNode::dump(StringBuilder& builder, int indent) const
  857. {
  858. builder.appendff("{: >{}}CONSTANT: {}\n", "", indent, to_string());
  859. }
  860. NonnullOwnPtr<SinCalculationNode> SinCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  861. {
  862. return adopt_own(*new (nothrow) SinCalculationNode(move(value)));
  863. }
  864. SinCalculationNode::SinCalculationNode(NonnullOwnPtr<CalculationNode> value)
  865. : CalculationNode(Type::Sin)
  866. , m_value(move(value))
  867. {
  868. }
  869. SinCalculationNode::~SinCalculationNode() = default;
  870. String SinCalculationNode::to_string() const
  871. {
  872. StringBuilder builder;
  873. builder.append("sin("sv);
  874. builder.append(m_value->to_string());
  875. builder.append(")"sv);
  876. return MUST(builder.to_string());
  877. }
  878. Optional<CalculatedStyleValue::ResolvedType> SinCalculationNode::resolved_type() const
  879. {
  880. return CalculatedStyleValue::ResolvedType::Number;
  881. }
  882. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  883. Optional<CSSNumericType> SinCalculationNode::determine_type(PropertyID) const
  884. {
  885. // «[ ]» (empty map).
  886. return CSSNumericType {};
  887. }
  888. bool SinCalculationNode::contains_percentage() const
  889. {
  890. return m_value->contains_percentage();
  891. }
  892. CalculatedStyleValue::CalculationResult SinCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  893. {
  894. auto node_a = m_value->resolve(context, percentage_basis);
  895. auto node_a_value = resolve_value_radians(node_a.value());
  896. auto result = sin(node_a_value);
  897. return { Number(Number::Type::Number, result) };
  898. }
  899. void SinCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  900. {
  901. m_value->for_each_child_node(callback);
  902. callback(m_value);
  903. }
  904. void SinCalculationNode::dump(StringBuilder& builder, int indent) const
  905. {
  906. builder.appendff("{: >{}}SIN: {}\n", "", indent, to_string());
  907. }
  908. NonnullOwnPtr<CosCalculationNode> CosCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  909. {
  910. return adopt_own(*new (nothrow) CosCalculationNode(move(value)));
  911. }
  912. CosCalculationNode::CosCalculationNode(NonnullOwnPtr<CalculationNode> value)
  913. : CalculationNode(Type::Cos)
  914. , m_value(move(value))
  915. {
  916. }
  917. CosCalculationNode::~CosCalculationNode() = default;
  918. String CosCalculationNode::to_string() const
  919. {
  920. StringBuilder builder;
  921. builder.append("cos("sv);
  922. builder.append(m_value->to_string());
  923. builder.append(")"sv);
  924. return MUST(builder.to_string());
  925. }
  926. Optional<CalculatedStyleValue::ResolvedType> CosCalculationNode::resolved_type() const
  927. {
  928. return CalculatedStyleValue::ResolvedType::Number;
  929. }
  930. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  931. Optional<CSSNumericType> CosCalculationNode::determine_type(PropertyID) const
  932. {
  933. // «[ ]» (empty map).
  934. return CSSNumericType {};
  935. }
  936. bool CosCalculationNode::contains_percentage() const
  937. {
  938. return m_value->contains_percentage();
  939. }
  940. CalculatedStyleValue::CalculationResult CosCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  941. {
  942. auto node_a = m_value->resolve(context, percentage_basis);
  943. auto node_a_value = resolve_value_radians(node_a.value());
  944. auto result = cos(node_a_value);
  945. return { Number(Number::Type::Number, result) };
  946. }
  947. void CosCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  948. {
  949. m_value->for_each_child_node(callback);
  950. callback(m_value);
  951. }
  952. void CosCalculationNode::dump(StringBuilder& builder, int indent) const
  953. {
  954. builder.appendff("{: >{}}COS: {}\n", "", indent, to_string());
  955. }
  956. NonnullOwnPtr<TanCalculationNode> TanCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  957. {
  958. return adopt_own(*new (nothrow) TanCalculationNode(move(value)));
  959. }
  960. TanCalculationNode::TanCalculationNode(NonnullOwnPtr<CalculationNode> value)
  961. : CalculationNode(Type::Tan)
  962. , m_value(move(value))
  963. {
  964. }
  965. TanCalculationNode::~TanCalculationNode() = default;
  966. String TanCalculationNode::to_string() const
  967. {
  968. StringBuilder builder;
  969. builder.append("tan("sv);
  970. builder.append(m_value->to_string());
  971. builder.append(")"sv);
  972. return MUST(builder.to_string());
  973. }
  974. Optional<CalculatedStyleValue::ResolvedType> TanCalculationNode::resolved_type() const
  975. {
  976. return CalculatedStyleValue::ResolvedType::Number;
  977. }
  978. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  979. Optional<CSSNumericType> TanCalculationNode::determine_type(PropertyID) const
  980. {
  981. // «[ ]» (empty map).
  982. return CSSNumericType {};
  983. }
  984. bool TanCalculationNode::contains_percentage() const
  985. {
  986. return m_value->contains_percentage();
  987. }
  988. CalculatedStyleValue::CalculationResult TanCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  989. {
  990. auto node_a = m_value->resolve(context, percentage_basis);
  991. auto node_a_value = resolve_value_radians(node_a.value());
  992. auto result = tan(node_a_value);
  993. return { Number(Number::Type::Number, result) };
  994. }
  995. void TanCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  996. {
  997. m_value->for_each_child_node(callback);
  998. callback(m_value);
  999. }
  1000. void TanCalculationNode::dump(StringBuilder& builder, int indent) const
  1001. {
  1002. builder.appendff("{: >{}}TAN: {}\n", "", indent, to_string());
  1003. }
  1004. NonnullOwnPtr<AsinCalculationNode> AsinCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  1005. {
  1006. return adopt_own(*new (nothrow) AsinCalculationNode(move(value)));
  1007. }
  1008. AsinCalculationNode::AsinCalculationNode(NonnullOwnPtr<CalculationNode> value)
  1009. : CalculationNode(Type::Asin)
  1010. , m_value(move(value))
  1011. {
  1012. }
  1013. AsinCalculationNode::~AsinCalculationNode() = default;
  1014. String AsinCalculationNode::to_string() const
  1015. {
  1016. StringBuilder builder;
  1017. builder.append("asin("sv);
  1018. builder.append(m_value->to_string());
  1019. builder.append(")"sv);
  1020. return MUST(builder.to_string());
  1021. }
  1022. Optional<CalculatedStyleValue::ResolvedType> AsinCalculationNode::resolved_type() const
  1023. {
  1024. return CalculatedStyleValue::ResolvedType::Angle;
  1025. }
  1026. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1027. Optional<CSSNumericType> AsinCalculationNode::determine_type(PropertyID) const
  1028. {
  1029. // «[ "angle" → 1 ]».
  1030. return CSSNumericType { CSSNumericType::BaseType::Angle, 1 };
  1031. }
  1032. bool AsinCalculationNode::contains_percentage() const
  1033. {
  1034. return m_value->contains_percentage();
  1035. }
  1036. CalculatedStyleValue::CalculationResult AsinCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1037. {
  1038. auto node_a = m_value->resolve(context, percentage_basis);
  1039. auto node_a_value = resolve_value(node_a.value(), context);
  1040. auto result = asin(node_a_value);
  1041. return { Angle(result, Angle::Type::Rad) };
  1042. }
  1043. void AsinCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1044. {
  1045. m_value->for_each_child_node(callback);
  1046. callback(m_value);
  1047. }
  1048. void AsinCalculationNode::dump(StringBuilder& builder, int indent) const
  1049. {
  1050. builder.appendff("{: >{}}ASIN: {}\n", "", indent, to_string());
  1051. }
  1052. NonnullOwnPtr<AcosCalculationNode> AcosCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  1053. {
  1054. return adopt_own(*new (nothrow) AcosCalculationNode(move(value)));
  1055. }
  1056. AcosCalculationNode::AcosCalculationNode(NonnullOwnPtr<CalculationNode> value)
  1057. : CalculationNode(Type::Acos)
  1058. , m_value(move(value))
  1059. {
  1060. }
  1061. AcosCalculationNode::~AcosCalculationNode() = default;
  1062. String AcosCalculationNode::to_string() const
  1063. {
  1064. StringBuilder builder;
  1065. builder.append("acos("sv);
  1066. builder.append(m_value->to_string());
  1067. builder.append(")"sv);
  1068. return MUST(builder.to_string());
  1069. }
  1070. Optional<CalculatedStyleValue::ResolvedType> AcosCalculationNode::resolved_type() const
  1071. {
  1072. return CalculatedStyleValue::ResolvedType::Angle;
  1073. }
  1074. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1075. Optional<CSSNumericType> AcosCalculationNode::determine_type(PropertyID) const
  1076. {
  1077. // «[ "angle" → 1 ]».
  1078. return CSSNumericType { CSSNumericType::BaseType::Angle, 1 };
  1079. }
  1080. bool AcosCalculationNode::contains_percentage() const
  1081. {
  1082. return m_value->contains_percentage();
  1083. }
  1084. CalculatedStyleValue::CalculationResult AcosCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1085. {
  1086. auto node_a = m_value->resolve(context, percentage_basis);
  1087. auto node_a_value = resolve_value(node_a.value(), context);
  1088. auto result = acos(node_a_value);
  1089. return { Angle(result, Angle::Type::Rad) };
  1090. }
  1091. void AcosCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1092. {
  1093. m_value->for_each_child_node(callback);
  1094. callback(m_value);
  1095. }
  1096. void AcosCalculationNode::dump(StringBuilder& builder, int indent) const
  1097. {
  1098. builder.appendff("{: >{}}ACOS: {}\n", "", indent, to_string());
  1099. }
  1100. NonnullOwnPtr<AtanCalculationNode> AtanCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  1101. {
  1102. return adopt_own(*new (nothrow) AtanCalculationNode(move(value)));
  1103. }
  1104. AtanCalculationNode::AtanCalculationNode(NonnullOwnPtr<CalculationNode> value)
  1105. : CalculationNode(Type::Atan)
  1106. , m_value(move(value))
  1107. {
  1108. }
  1109. AtanCalculationNode::~AtanCalculationNode() = default;
  1110. String AtanCalculationNode::to_string() const
  1111. {
  1112. StringBuilder builder;
  1113. builder.append("atan("sv);
  1114. builder.append(m_value->to_string());
  1115. builder.append(")"sv);
  1116. return MUST(builder.to_string());
  1117. }
  1118. Optional<CalculatedStyleValue::ResolvedType> AtanCalculationNode::resolved_type() const
  1119. {
  1120. return CalculatedStyleValue::ResolvedType::Angle;
  1121. }
  1122. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1123. Optional<CSSNumericType> AtanCalculationNode::determine_type(PropertyID) const
  1124. {
  1125. // «[ "angle" → 1 ]».
  1126. return CSSNumericType { CSSNumericType::BaseType::Angle, 1 };
  1127. }
  1128. bool AtanCalculationNode::contains_percentage() const
  1129. {
  1130. return m_value->contains_percentage();
  1131. }
  1132. CalculatedStyleValue::CalculationResult AtanCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1133. {
  1134. auto node_a = m_value->resolve(context, percentage_basis);
  1135. auto node_a_value = resolve_value(node_a.value(), context);
  1136. auto result = atan(node_a_value);
  1137. return { Angle(result, Angle::Type::Rad) };
  1138. }
  1139. void AtanCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1140. {
  1141. m_value->for_each_child_node(callback);
  1142. callback(m_value);
  1143. }
  1144. void AtanCalculationNode::dump(StringBuilder& builder, int indent) const
  1145. {
  1146. builder.appendff("{: >{}}ATAN: {}\n", "", indent, to_string());
  1147. }
  1148. NonnullOwnPtr<Atan2CalculationNode> Atan2CalculationNode::create(NonnullOwnPtr<CalculationNode> y, NonnullOwnPtr<CalculationNode> x)
  1149. {
  1150. return adopt_own(*new (nothrow) Atan2CalculationNode(move(y), move(x)));
  1151. }
  1152. Atan2CalculationNode::Atan2CalculationNode(NonnullOwnPtr<CalculationNode> y, NonnullOwnPtr<CalculationNode> x)
  1153. : CalculationNode(Type::Atan2)
  1154. , m_y(move(y))
  1155. , m_x(move(x))
  1156. {
  1157. }
  1158. Atan2CalculationNode::~Atan2CalculationNode() = default;
  1159. String Atan2CalculationNode::to_string() const
  1160. {
  1161. StringBuilder builder;
  1162. builder.append("atan2("sv);
  1163. builder.append(m_y->to_string());
  1164. builder.append(", "sv);
  1165. builder.append(m_x->to_string());
  1166. builder.append(")"sv);
  1167. return MUST(builder.to_string());
  1168. }
  1169. Optional<CalculatedStyleValue::ResolvedType> Atan2CalculationNode::resolved_type() const
  1170. {
  1171. return CalculatedStyleValue::ResolvedType::Angle;
  1172. }
  1173. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1174. Optional<CSSNumericType> Atan2CalculationNode::determine_type(PropertyID) const
  1175. {
  1176. // «[ "angle" → 1 ]».
  1177. return CSSNumericType { CSSNumericType::BaseType::Angle, 1 };
  1178. }
  1179. bool Atan2CalculationNode::contains_percentage() const
  1180. {
  1181. return m_y->contains_percentage() || m_x->contains_percentage();
  1182. }
  1183. CalculatedStyleValue::CalculationResult Atan2CalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1184. {
  1185. auto node_a = m_y->resolve(context, percentage_basis);
  1186. auto node_a_value = resolve_value(node_a.value(), context);
  1187. auto node_b = m_x->resolve(context, percentage_basis);
  1188. auto node_b_value = resolve_value(node_b.value(), context);
  1189. auto result = atan2(node_a_value, node_b_value);
  1190. return { Angle(result, Angle::Type::Rad) };
  1191. }
  1192. void Atan2CalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1193. {
  1194. m_y->for_each_child_node(callback);
  1195. m_x->for_each_child_node(callback);
  1196. callback(m_y);
  1197. callback(m_x);
  1198. }
  1199. void Atan2CalculationNode::dump(StringBuilder& builder, int indent) const
  1200. {
  1201. builder.appendff("{: >{}}ATAN2: {}\n", "", indent, to_string());
  1202. }
  1203. NonnullOwnPtr<PowCalculationNode> PowCalculationNode::create(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1204. {
  1205. return adopt_own(*new (nothrow) PowCalculationNode(move(x), move(y)));
  1206. }
  1207. PowCalculationNode::PowCalculationNode(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1208. : CalculationNode(Type::Pow)
  1209. , m_x(move(x))
  1210. , m_y(move(y))
  1211. {
  1212. }
  1213. PowCalculationNode::~PowCalculationNode() = default;
  1214. String PowCalculationNode::to_string() const
  1215. {
  1216. StringBuilder builder;
  1217. builder.append("pow("sv);
  1218. builder.append(m_x->to_string());
  1219. builder.append(", "sv);
  1220. builder.append(m_y->to_string());
  1221. builder.append(")"sv);
  1222. return MUST(builder.to_string());
  1223. }
  1224. Optional<CalculatedStyleValue::ResolvedType> PowCalculationNode::resolved_type() const
  1225. {
  1226. return CalculatedStyleValue::ResolvedType::Number;
  1227. }
  1228. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1229. Optional<CSSNumericType> PowCalculationNode::determine_type(PropertyID) const
  1230. {
  1231. // «[ ]» (empty map).
  1232. return CSSNumericType {};
  1233. }
  1234. CalculatedStyleValue::CalculationResult PowCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1235. {
  1236. auto node_a = m_x->resolve(context, percentage_basis);
  1237. auto node_a_value = resolve_value(node_a.value(), context);
  1238. auto node_b = m_y->resolve(context, percentage_basis);
  1239. auto node_b_value = resolve_value(node_b.value(), context);
  1240. auto result = pow(node_a_value, node_b_value);
  1241. return { Number(Number::Type::Number, result) };
  1242. }
  1243. void PowCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1244. {
  1245. m_x->for_each_child_node(callback);
  1246. m_y->for_each_child_node(callback);
  1247. callback(m_x);
  1248. callback(m_y);
  1249. }
  1250. void PowCalculationNode::dump(StringBuilder& builder, int indent) const
  1251. {
  1252. builder.appendff("{: >{}}POW: {}\n", "", indent, to_string());
  1253. }
  1254. NonnullOwnPtr<SqrtCalculationNode> SqrtCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  1255. {
  1256. return adopt_own(*new (nothrow) SqrtCalculationNode(move(value)));
  1257. }
  1258. SqrtCalculationNode::SqrtCalculationNode(NonnullOwnPtr<CalculationNode> value)
  1259. : CalculationNode(Type::Sqrt)
  1260. , m_value(move(value))
  1261. {
  1262. }
  1263. SqrtCalculationNode::~SqrtCalculationNode() = default;
  1264. String SqrtCalculationNode::to_string() const
  1265. {
  1266. StringBuilder builder;
  1267. builder.append("sqrt("sv);
  1268. builder.append(m_value->to_string());
  1269. builder.append(")"sv);
  1270. return MUST(builder.to_string());
  1271. }
  1272. Optional<CalculatedStyleValue::ResolvedType> SqrtCalculationNode::resolved_type() const
  1273. {
  1274. return CalculatedStyleValue::ResolvedType::Number;
  1275. }
  1276. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1277. Optional<CSSNumericType> SqrtCalculationNode::determine_type(PropertyID) const
  1278. {
  1279. // «[ ]» (empty map).
  1280. return CSSNumericType {};
  1281. }
  1282. CalculatedStyleValue::CalculationResult SqrtCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1283. {
  1284. auto node_a = m_value->resolve(context, percentage_basis);
  1285. auto node_a_value = resolve_value(node_a.value(), context);
  1286. auto result = sqrt(node_a_value);
  1287. return { Number(Number::Type::Number, result) };
  1288. }
  1289. void SqrtCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1290. {
  1291. m_value->for_each_child_node(callback);
  1292. callback(m_value);
  1293. }
  1294. void SqrtCalculationNode::dump(StringBuilder& builder, int indent) const
  1295. {
  1296. builder.appendff("{: >{}}SQRT: {}\n", "", indent, to_string());
  1297. }
  1298. NonnullOwnPtr<HypotCalculationNode> HypotCalculationNode::create(Vector<NonnullOwnPtr<Web::CSS::CalculationNode>> values)
  1299. {
  1300. return adopt_own(*new (nothrow) HypotCalculationNode(move(values)));
  1301. }
  1302. HypotCalculationNode::HypotCalculationNode(Vector<NonnullOwnPtr<CalculationNode>> values)
  1303. : CalculationNode(Type::Hypot)
  1304. , m_values(move(values))
  1305. {
  1306. }
  1307. HypotCalculationNode::~HypotCalculationNode() = default;
  1308. String HypotCalculationNode::to_string() const
  1309. {
  1310. StringBuilder builder;
  1311. builder.append("hypot("sv);
  1312. for (size_t i = 0; i < m_values.size(); ++i) {
  1313. if (i != 0)
  1314. builder.append(", "sv);
  1315. builder.append(m_values[i]->to_string());
  1316. }
  1317. builder.append(")"sv);
  1318. return MUST(builder.to_string());
  1319. }
  1320. Optional<CalculatedStyleValue::ResolvedType> HypotCalculationNode::resolved_type() const
  1321. {
  1322. // NOTE: We check during parsing that all values have the same type.
  1323. return m_values[0]->resolved_type();
  1324. }
  1325. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1326. Optional<CSSNumericType> HypotCalculationNode::determine_type(PropertyID property_id) const
  1327. {
  1328. // The result of adding the types of its comma-separated calculations.
  1329. return add_the_types(m_values, property_id);
  1330. }
  1331. bool HypotCalculationNode::contains_percentage() const
  1332. {
  1333. for (auto const& value : m_values) {
  1334. if (value->contains_percentage())
  1335. return true;
  1336. }
  1337. return false;
  1338. }
  1339. CalculatedStyleValue::CalculationResult HypotCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1340. {
  1341. double square_sum = 0.0;
  1342. for (auto const& value : m_values) {
  1343. auto child_resolved = value->resolve(context, percentage_basis);
  1344. auto child_value = resolve_value(child_resolved.value(), context);
  1345. square_sum += child_value * child_value;
  1346. }
  1347. auto result = sqrt(square_sum);
  1348. return to_resolved_type(resolved_type().value(), result);
  1349. }
  1350. void HypotCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1351. {
  1352. for (auto& value : m_values) {
  1353. value->for_each_child_node(callback);
  1354. callback(value);
  1355. }
  1356. }
  1357. void HypotCalculationNode::dump(StringBuilder& builder, int indent) const
  1358. {
  1359. builder.appendff("{: >{}}HYPOT:\n", "", indent);
  1360. for (auto const& value : m_values)
  1361. value->dump(builder, indent + 2);
  1362. }
  1363. NonnullOwnPtr<LogCalculationNode> LogCalculationNode::create(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1364. {
  1365. return adopt_own(*new (nothrow) LogCalculationNode(move(x), move(y)));
  1366. }
  1367. LogCalculationNode::LogCalculationNode(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1368. : CalculationNode(Type::Log)
  1369. , m_x(move(x))
  1370. , m_y(move(y))
  1371. {
  1372. }
  1373. LogCalculationNode::~LogCalculationNode() = default;
  1374. String LogCalculationNode::to_string() const
  1375. {
  1376. StringBuilder builder;
  1377. builder.append("log("sv);
  1378. builder.append(m_x->to_string());
  1379. builder.append(", "sv);
  1380. builder.append(m_y->to_string());
  1381. builder.append(")"sv);
  1382. return MUST(builder.to_string());
  1383. }
  1384. Optional<CalculatedStyleValue::ResolvedType> LogCalculationNode::resolved_type() const
  1385. {
  1386. return CalculatedStyleValue::ResolvedType::Number;
  1387. }
  1388. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1389. Optional<CSSNumericType> LogCalculationNode::determine_type(PropertyID) const
  1390. {
  1391. // «[ ]» (empty map).
  1392. return CSSNumericType {};
  1393. }
  1394. CalculatedStyleValue::CalculationResult LogCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1395. {
  1396. auto node_a = m_x->resolve(context, percentage_basis);
  1397. auto node_a_value = resolve_value(node_a.value(), context);
  1398. auto node_b = m_y->resolve(context, percentage_basis);
  1399. auto node_b_value = resolve_value(node_b.value(), context);
  1400. auto result = log2(node_a_value) / log2(node_b_value);
  1401. return { Number(Number::Type::Number, result) };
  1402. }
  1403. void LogCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1404. {
  1405. m_x->for_each_child_node(callback);
  1406. m_y->for_each_child_node(callback);
  1407. callback(m_x);
  1408. callback(m_y);
  1409. }
  1410. void LogCalculationNode::dump(StringBuilder& builder, int indent) const
  1411. {
  1412. builder.appendff("{: >{}}LOG: {}\n", "", indent, to_string());
  1413. }
  1414. NonnullOwnPtr<ExpCalculationNode> ExpCalculationNode::create(NonnullOwnPtr<CalculationNode> value)
  1415. {
  1416. return adopt_own(*new (nothrow) ExpCalculationNode(move(value)));
  1417. }
  1418. ExpCalculationNode::ExpCalculationNode(NonnullOwnPtr<CalculationNode> value)
  1419. : CalculationNode(Type::Exp)
  1420. , m_value(move(value))
  1421. {
  1422. }
  1423. ExpCalculationNode::~ExpCalculationNode() = default;
  1424. String ExpCalculationNode::to_string() const
  1425. {
  1426. StringBuilder builder;
  1427. builder.append("exp("sv);
  1428. builder.append(m_value->to_string());
  1429. builder.append(")"sv);
  1430. return MUST(builder.to_string());
  1431. }
  1432. Optional<CalculatedStyleValue::ResolvedType> ExpCalculationNode::resolved_type() const
  1433. {
  1434. return CalculatedStyleValue::ResolvedType::Number;
  1435. }
  1436. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1437. Optional<CSSNumericType> ExpCalculationNode::determine_type(PropertyID) const
  1438. {
  1439. // «[ ]» (empty map).
  1440. return CSSNumericType {};
  1441. }
  1442. CalculatedStyleValue::CalculationResult ExpCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1443. {
  1444. auto node_a = m_value->resolve(context, percentage_basis);
  1445. auto node_a_value = resolve_value(node_a.value(), context);
  1446. auto result = exp(node_a_value);
  1447. return { Number(Number::Type::Number, result) };
  1448. }
  1449. void ExpCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1450. {
  1451. m_value->for_each_child_node(callback);
  1452. callback(m_value);
  1453. }
  1454. void ExpCalculationNode::dump(StringBuilder& builder, int indent) const
  1455. {
  1456. builder.appendff("{: >{}}EXP: {}\n", "", indent, to_string());
  1457. }
  1458. NonnullOwnPtr<RoundCalculationNode> RoundCalculationNode::create(RoundingStrategy strategy, NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1459. {
  1460. return adopt_own(*new (nothrow) RoundCalculationNode(strategy, move(x), move(y)));
  1461. }
  1462. RoundCalculationNode::RoundCalculationNode(RoundingStrategy mode, NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1463. : CalculationNode(Type::Round)
  1464. , m_strategy(mode)
  1465. , m_x(move(x))
  1466. , m_y(move(y))
  1467. {
  1468. }
  1469. RoundCalculationNode::~RoundCalculationNode() = default;
  1470. String RoundCalculationNode::to_string() const
  1471. {
  1472. StringBuilder builder;
  1473. builder.append("round("sv);
  1474. builder.append(CSS::to_string(m_strategy));
  1475. builder.append(", "sv);
  1476. builder.append(m_x->to_string());
  1477. builder.append(", "sv);
  1478. builder.append(m_y->to_string());
  1479. builder.append(")"sv);
  1480. return MUST(builder.to_string());
  1481. }
  1482. Optional<CalculatedStyleValue::ResolvedType> RoundCalculationNode::resolved_type() const
  1483. {
  1484. // Note: We check during parsing that all values have the same type
  1485. return m_x->resolved_type();
  1486. }
  1487. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1488. Optional<CSSNumericType> RoundCalculationNode::determine_type(PropertyID property_id) const
  1489. {
  1490. // The result of adding the types of its comma-separated calculations.
  1491. auto x_type = m_x->determine_type(property_id);
  1492. auto y_type = m_y->determine_type(property_id);
  1493. if (!x_type.has_value() || !y_type.has_value())
  1494. return {};
  1495. return x_type->added_to(*y_type);
  1496. }
  1497. bool RoundCalculationNode::contains_percentage() const
  1498. {
  1499. return m_x->contains_percentage() || m_y->contains_percentage();
  1500. }
  1501. CalculatedStyleValue::CalculationResult RoundCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1502. {
  1503. auto resolved_type = m_x->resolved_type().value();
  1504. auto node_a = m_x->resolve(context, percentage_basis);
  1505. auto node_b = m_y->resolve(context, percentage_basis);
  1506. auto node_a_value = resolve_value(node_a.value(), context);
  1507. auto node_b_value = resolve_value(node_b.value(), context);
  1508. auto upper_b = ceil(node_a_value / node_b_value) * node_b_value;
  1509. auto lower_b = floor(node_a_value / node_b_value) * node_b_value;
  1510. if (m_strategy == RoundingStrategy::Nearest) {
  1511. auto upper_diff = fabs(upper_b - node_a_value);
  1512. auto lower_diff = fabs(node_a_value - lower_b);
  1513. auto rounded_value = upper_diff < lower_diff ? upper_b : lower_b;
  1514. return to_resolved_type(resolved_type, rounded_value);
  1515. }
  1516. if (m_strategy == RoundingStrategy::Up) {
  1517. return to_resolved_type(resolved_type, upper_b);
  1518. }
  1519. if (m_strategy == RoundingStrategy::Down) {
  1520. return to_resolved_type(resolved_type, lower_b);
  1521. }
  1522. if (m_strategy == RoundingStrategy::ToZero) {
  1523. auto upper_diff = fabs(upper_b);
  1524. auto lower_diff = fabs(lower_b);
  1525. auto rounded_value = upper_diff < lower_diff ? upper_b : lower_b;
  1526. return to_resolved_type(resolved_type, rounded_value);
  1527. }
  1528. VERIFY_NOT_REACHED();
  1529. }
  1530. void RoundCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1531. {
  1532. m_x->for_each_child_node(callback);
  1533. m_y->for_each_child_node(callback);
  1534. callback(m_x);
  1535. callback(m_y);
  1536. }
  1537. void RoundCalculationNode::dump(StringBuilder& builder, int indent) const
  1538. {
  1539. builder.appendff("{: >{}}ROUND: {}\n", "", indent, to_string());
  1540. }
  1541. NonnullOwnPtr<ModCalculationNode> ModCalculationNode::create(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1542. {
  1543. return adopt_own(*new (nothrow) ModCalculationNode(move(x), move(y)));
  1544. }
  1545. ModCalculationNode::ModCalculationNode(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1546. : CalculationNode(Type::Mod)
  1547. , m_x(move(x))
  1548. , m_y(move(y))
  1549. {
  1550. }
  1551. ModCalculationNode::~ModCalculationNode() = default;
  1552. String ModCalculationNode::to_string() const
  1553. {
  1554. StringBuilder builder;
  1555. builder.append("mod("sv);
  1556. builder.append(m_x->to_string());
  1557. builder.append(", "sv);
  1558. builder.append(m_y->to_string());
  1559. builder.append(")"sv);
  1560. return MUST(builder.to_string());
  1561. }
  1562. Optional<CalculatedStyleValue::ResolvedType> ModCalculationNode::resolved_type() const
  1563. {
  1564. // Note: We check during parsing that all values have the same type
  1565. return m_x->resolved_type();
  1566. }
  1567. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1568. Optional<CSSNumericType> ModCalculationNode::determine_type(PropertyID property_id) const
  1569. {
  1570. // The result of adding the types of its comma-separated calculations.
  1571. auto x_type = m_x->determine_type(property_id);
  1572. auto y_type = m_y->determine_type(property_id);
  1573. if (!x_type.has_value() || !y_type.has_value())
  1574. return {};
  1575. return x_type->added_to(*y_type);
  1576. }
  1577. bool ModCalculationNode::contains_percentage() const
  1578. {
  1579. return m_x->contains_percentage() || m_y->contains_percentage();
  1580. }
  1581. CalculatedStyleValue::CalculationResult ModCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1582. {
  1583. auto resolved_type = m_x->resolved_type().value();
  1584. auto node_a = m_x->resolve(context, percentage_basis);
  1585. auto node_b = m_y->resolve(context, percentage_basis);
  1586. auto node_a_value = resolve_value(node_a.value(), context);
  1587. auto node_b_value = resolve_value(node_b.value(), context);
  1588. auto quotient = floor(node_a_value / node_b_value);
  1589. auto value = node_a_value - (node_b_value * quotient);
  1590. return to_resolved_type(resolved_type, value);
  1591. }
  1592. void ModCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1593. {
  1594. m_x->for_each_child_node(callback);
  1595. m_y->for_each_child_node(callback);
  1596. callback(m_x);
  1597. callback(m_y);
  1598. }
  1599. void ModCalculationNode::dump(StringBuilder& builder, int indent) const
  1600. {
  1601. builder.appendff("{: >{}}MOD: {}\n", "", indent, to_string());
  1602. }
  1603. NonnullOwnPtr<RemCalculationNode> RemCalculationNode::create(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1604. {
  1605. return adopt_own(*new (nothrow) RemCalculationNode(move(x), move(y)));
  1606. }
  1607. RemCalculationNode::RemCalculationNode(NonnullOwnPtr<CalculationNode> x, NonnullOwnPtr<CalculationNode> y)
  1608. : CalculationNode(Type::Rem)
  1609. , m_x(move(x))
  1610. , m_y(move(y))
  1611. {
  1612. }
  1613. RemCalculationNode::~RemCalculationNode() = default;
  1614. String RemCalculationNode::to_string() const
  1615. {
  1616. StringBuilder builder;
  1617. builder.append("rem("sv);
  1618. builder.append(m_x->to_string());
  1619. builder.append(", "sv);
  1620. builder.append(m_y->to_string());
  1621. builder.append(")"sv);
  1622. return MUST(builder.to_string());
  1623. }
  1624. Optional<CalculatedStyleValue::ResolvedType> RemCalculationNode::resolved_type() const
  1625. {
  1626. // Note: We check during parsing that all values have the same type
  1627. return m_x->resolved_type();
  1628. }
  1629. // https://www.w3.org/TR/css-values-4/#determine-the-type-of-a-calculation
  1630. Optional<CSSNumericType> RemCalculationNode::determine_type(PropertyID property_id) const
  1631. {
  1632. // The result of adding the types of its comma-separated calculations.
  1633. auto x_type = m_x->determine_type(property_id);
  1634. auto y_type = m_y->determine_type(property_id);
  1635. if (!x_type.has_value() || !y_type.has_value())
  1636. return {};
  1637. return x_type->added_to(*y_type);
  1638. }
  1639. bool RemCalculationNode::contains_percentage() const
  1640. {
  1641. return m_x->contains_percentage() || m_y->contains_percentage();
  1642. }
  1643. CalculatedStyleValue::CalculationResult RemCalculationNode::resolve(Optional<Length::ResolutionContext const&> context, CalculatedStyleValue::PercentageBasis const& percentage_basis) const
  1644. {
  1645. auto resolved_type = m_x->resolved_type().value();
  1646. auto node_a = m_x->resolve(context, percentage_basis);
  1647. auto node_b = m_y->resolve(context, percentage_basis);
  1648. auto node_a_value = resolve_value(node_a.value(), context);
  1649. auto node_b_value = resolve_value(node_b.value(), context);
  1650. auto value = fmod(node_a_value, node_b_value);
  1651. return to_resolved_type(resolved_type, value);
  1652. }
  1653. void RemCalculationNode::for_each_child_node(Function<void(NonnullOwnPtr<CalculationNode>&)> const& callback)
  1654. {
  1655. m_x->for_each_child_node(callback);
  1656. m_y->for_each_child_node(callback);
  1657. callback(m_x);
  1658. callback(m_y);
  1659. }
  1660. void RemCalculationNode::dump(StringBuilder& builder, int indent) const
  1661. {
  1662. builder.appendff("{: >{}}REM: {}\n", "", indent, to_string());
  1663. }
  1664. void CalculatedStyleValue::CalculationResult::add(CalculationResult const& other, Optional<Length::ResolutionContext const&> context, PercentageBasis const& percentage_basis)
  1665. {
  1666. add_or_subtract_internal(SumOperation::Add, other, context, percentage_basis);
  1667. }
  1668. void CalculatedStyleValue::CalculationResult::subtract(CalculationResult const& other, Optional<Length::ResolutionContext const&> context, PercentageBasis const& percentage_basis)
  1669. {
  1670. add_or_subtract_internal(SumOperation::Subtract, other, context, percentage_basis);
  1671. }
  1672. void CalculatedStyleValue::CalculationResult::add_or_subtract_internal(SumOperation op, CalculationResult const& other, Optional<Length::ResolutionContext const&> context, PercentageBasis const& percentage_basis)
  1673. {
  1674. // We know from validation when resolving the type, that "both sides have the same type, or that one side is a <number> and the other is an <integer>".
  1675. // Though, having the same type may mean that one side is a <dimension> and the other a <percentage>.
  1676. // Note: This is almost identical to ::add()
  1677. m_value.visit(
  1678. [&](Number const& number) {
  1679. auto other_number = other.m_value.get<Number>();
  1680. if (op == SumOperation::Add) {
  1681. m_value = number + other_number;
  1682. } else {
  1683. m_value = number - other_number;
  1684. }
  1685. },
  1686. [&](Angle const& angle) {
  1687. auto this_degrees = angle.to_degrees();
  1688. if (other.m_value.has<Angle>()) {
  1689. auto other_degrees = other.m_value.get<Angle>().to_degrees();
  1690. if (op == SumOperation::Add)
  1691. m_value = Angle::make_degrees(this_degrees + other_degrees);
  1692. else
  1693. m_value = Angle::make_degrees(this_degrees - other_degrees);
  1694. } else {
  1695. VERIFY(percentage_basis.has<Angle>());
  1696. auto other_degrees = percentage_basis.get<Angle>().percentage_of(other.m_value.get<Percentage>()).to_degrees();
  1697. if (op == SumOperation::Add)
  1698. m_value = Angle::make_degrees(this_degrees + other_degrees);
  1699. else
  1700. m_value = Angle::make_degrees(this_degrees - other_degrees);
  1701. }
  1702. },
  1703. [&](Frequency const& frequency) {
  1704. auto this_hertz = frequency.to_hertz();
  1705. if (other.m_value.has<Frequency>()) {
  1706. auto other_hertz = other.m_value.get<Frequency>().to_hertz();
  1707. if (op == SumOperation::Add)
  1708. m_value = Frequency::make_hertz(this_hertz + other_hertz);
  1709. else
  1710. m_value = Frequency::make_hertz(this_hertz - other_hertz);
  1711. } else {
  1712. VERIFY(percentage_basis.has<Frequency>());
  1713. auto other_hertz = percentage_basis.get<Frequency>().percentage_of(other.m_value.get<Percentage>()).to_hertz();
  1714. if (op == SumOperation::Add)
  1715. m_value = Frequency::make_hertz(this_hertz + other_hertz);
  1716. else
  1717. m_value = Frequency::make_hertz(this_hertz - other_hertz);
  1718. }
  1719. },
  1720. [&](Length const& length) {
  1721. auto this_px = length.to_px(*context);
  1722. if (other.m_value.has<Length>()) {
  1723. auto other_px = other.m_value.get<Length>().to_px(*context);
  1724. if (op == SumOperation::Add)
  1725. m_value = Length::make_px(this_px + other_px);
  1726. else
  1727. m_value = Length::make_px(this_px - other_px);
  1728. } else {
  1729. VERIFY(percentage_basis.has<Length>());
  1730. auto other_px = percentage_basis.get<Length>().percentage_of(other.m_value.get<Percentage>()).to_px(*context);
  1731. if (op == SumOperation::Add)
  1732. m_value = Length::make_px(this_px + other_px);
  1733. else
  1734. m_value = Length::make_px(this_px - other_px);
  1735. }
  1736. },
  1737. [&](Time const& time) {
  1738. auto this_seconds = time.to_seconds();
  1739. if (other.m_value.has<Time>()) {
  1740. auto other_seconds = other.m_value.get<Time>().to_seconds();
  1741. if (op == SumOperation::Add)
  1742. m_value = Time::make_seconds(this_seconds + other_seconds);
  1743. else
  1744. m_value = Time::make_seconds(this_seconds - other_seconds);
  1745. } else {
  1746. VERIFY(percentage_basis.has<Time>());
  1747. auto other_seconds = percentage_basis.get<Time>().percentage_of(other.m_value.get<Percentage>()).to_seconds();
  1748. if (op == SumOperation::Add)
  1749. m_value = Time::make_seconds(this_seconds + other_seconds);
  1750. else
  1751. m_value = Time::make_seconds(this_seconds - other_seconds);
  1752. }
  1753. },
  1754. [&](Percentage const& percentage) {
  1755. if (other.m_value.has<Percentage>()) {
  1756. if (op == SumOperation::Add)
  1757. m_value = Percentage { percentage.value() + other.m_value.get<Percentage>().value() };
  1758. else
  1759. m_value = Percentage { percentage.value() - other.m_value.get<Percentage>().value() };
  1760. return;
  1761. }
  1762. // Other side isn't a percentage, so the easiest way to handle it without duplicating all the logic, is just to swap `this` and `other`.
  1763. CalculationResult new_value = other;
  1764. if (op == SumOperation::Add) {
  1765. new_value.add(*this, context, percentage_basis);
  1766. } else {
  1767. // Turn 'this - other' into '-other + this', as 'A + B == B + A', but 'A - B != B - A'
  1768. new_value.multiply_by({ Number { Number::Type::Integer, -1.0f } }, context);
  1769. new_value.add(*this, context, percentage_basis);
  1770. }
  1771. *this = new_value;
  1772. });
  1773. }
  1774. void CalculatedStyleValue::CalculationResult::multiply_by(CalculationResult const& other, Optional<Length::ResolutionContext const&> context)
  1775. {
  1776. // We know from validation when resolving the type, that at least one side must be a <number> or <integer>.
  1777. // Both of these are represented as a double.
  1778. VERIFY(m_value.has<Number>() || other.m_value.has<Number>());
  1779. bool other_is_number = other.m_value.has<Number>();
  1780. m_value.visit(
  1781. [&](Number const& number) {
  1782. if (other_is_number) {
  1783. m_value = number * other.m_value.get<Number>();
  1784. } else {
  1785. // Avoid duplicating all the logic by swapping `this` and `other`.
  1786. CalculationResult new_value = other;
  1787. new_value.multiply_by(*this, context);
  1788. *this = new_value;
  1789. }
  1790. },
  1791. [&](Angle const& angle) {
  1792. m_value = Angle::make_degrees(angle.to_degrees() * other.m_value.get<Number>().value());
  1793. },
  1794. [&](Frequency const& frequency) {
  1795. m_value = Frequency::make_hertz(frequency.to_hertz() * other.m_value.get<Number>().value());
  1796. },
  1797. [&](Length const& length) {
  1798. m_value = Length::make_px(length.to_px(*context) * static_cast<double>(other.m_value.get<Number>().value()));
  1799. },
  1800. [&](Time const& time) {
  1801. m_value = Time::make_seconds(time.to_seconds() * other.m_value.get<Number>().value());
  1802. },
  1803. [&](Percentage const& percentage) {
  1804. m_value = Percentage { percentage.value() * other.m_value.get<Number>().value() };
  1805. });
  1806. }
  1807. void CalculatedStyleValue::CalculationResult::divide_by(CalculationResult const& other, Optional<Length::ResolutionContext const&> context)
  1808. {
  1809. // We know from validation when resolving the type, that `other` must be a <number> or <integer>.
  1810. // Both of these are represented as a Number.
  1811. auto denominator = other.m_value.get<Number>().value();
  1812. // FIXME: Dividing by 0 is invalid, and should be caught during parsing.
  1813. VERIFY(denominator != 0.0);
  1814. m_value.visit(
  1815. [&](Number const& number) {
  1816. m_value = Number {
  1817. Number::Type::Number,
  1818. number.value() / denominator
  1819. };
  1820. },
  1821. [&](Angle const& angle) {
  1822. m_value = Angle::make_degrees(angle.to_degrees() / denominator);
  1823. },
  1824. [&](Frequency const& frequency) {
  1825. m_value = Frequency::make_hertz(frequency.to_hertz() / denominator);
  1826. },
  1827. [&](Length const& length) {
  1828. m_value = Length::make_px(length.to_px(*context) / static_cast<double>(denominator));
  1829. },
  1830. [&](Time const& time) {
  1831. m_value = Time::make_seconds(time.to_seconds() / denominator);
  1832. },
  1833. [&](Percentage const& percentage) {
  1834. m_value = Percentage { percentage.value() / denominator };
  1835. });
  1836. }
  1837. void CalculatedStyleValue::CalculationResult::negate()
  1838. {
  1839. m_value.visit(
  1840. [&](Number const& number) {
  1841. m_value = Number { number.type(), 0 - number.value() };
  1842. },
  1843. [&](Angle const& angle) {
  1844. m_value = Angle { 0 - angle.raw_value(), angle.type() };
  1845. },
  1846. [&](Frequency const& frequency) {
  1847. m_value = Frequency { 0 - frequency.raw_value(), frequency.type() };
  1848. },
  1849. [&](Length const& length) {
  1850. m_value = Length { 0 - length.raw_value(), length.type() };
  1851. },
  1852. [&](Time const& time) {
  1853. m_value = Time { 0 - time.raw_value(), time.type() };
  1854. },
  1855. [&](Percentage const& percentage) {
  1856. m_value = Percentage { 0 - percentage.value() };
  1857. });
  1858. }
  1859. void CalculatedStyleValue::CalculationResult::invert()
  1860. {
  1861. // FIXME: Correctly handle division by zero.
  1862. m_value.visit(
  1863. [&](Number const& number) {
  1864. m_value = Number { Number::Type::Number, 1 / number.value() };
  1865. },
  1866. [&](Angle const& angle) {
  1867. m_value = Angle { 1 / angle.raw_value(), angle.type() };
  1868. },
  1869. [&](Frequency const& frequency) {
  1870. m_value = Frequency { 1 / frequency.raw_value(), frequency.type() };
  1871. },
  1872. [&](Length const& length) {
  1873. m_value = Length { 1 / length.raw_value(), length.type() };
  1874. },
  1875. [&](Time const& time) {
  1876. m_value = Time { 1 / time.raw_value(), time.type() };
  1877. },
  1878. [&](Percentage const& percentage) {
  1879. m_value = Percentage { 1 / percentage.value() };
  1880. });
  1881. }
  1882. String CalculatedStyleValue::to_string() const
  1883. {
  1884. // FIXME: Implement this according to https://www.w3.org/TR/css-values-4/#calc-serialize once that stabilizes.
  1885. return MUST(String::formatted("calc({})", m_calculation->to_string()));
  1886. }
  1887. bool CalculatedStyleValue::equals(StyleValue const& other) const
  1888. {
  1889. if (type() != other.type())
  1890. return false;
  1891. // This is a case where comparing the strings actually makes sense.
  1892. return to_string() == other.to_string();
  1893. }
  1894. Optional<Angle> CalculatedStyleValue::resolve_angle() const
  1895. {
  1896. auto result = m_calculation->resolve({}, {});
  1897. if (result.value().has<Angle>())
  1898. return result.value().get<Angle>();
  1899. return {};
  1900. }
  1901. Optional<Angle> CalculatedStyleValue::resolve_angle_percentage(Angle const& percentage_basis) const
  1902. {
  1903. auto result = m_calculation->resolve({}, percentage_basis);
  1904. return result.value().visit(
  1905. [&](Angle const& angle) -> Optional<Angle> {
  1906. return angle;
  1907. },
  1908. [&](Percentage const& percentage) -> Optional<Angle> {
  1909. return percentage_basis.percentage_of(percentage);
  1910. },
  1911. [&](auto const&) -> Optional<Angle> {
  1912. return {};
  1913. });
  1914. }
  1915. Optional<Frequency> CalculatedStyleValue::resolve_frequency() const
  1916. {
  1917. auto result = m_calculation->resolve({}, {});
  1918. if (result.value().has<Frequency>())
  1919. return result.value().get<Frequency>();
  1920. return {};
  1921. }
  1922. Optional<Frequency> CalculatedStyleValue::resolve_frequency_percentage(Frequency const& percentage_basis) const
  1923. {
  1924. auto result = m_calculation->resolve({}, percentage_basis);
  1925. return result.value().visit(
  1926. [&](Frequency const& frequency) -> Optional<Frequency> {
  1927. return frequency;
  1928. },
  1929. [&](Percentage const& percentage) -> Optional<Frequency> {
  1930. return percentage_basis.percentage_of(percentage);
  1931. },
  1932. [&](auto const&) -> Optional<Frequency> {
  1933. return {};
  1934. });
  1935. }
  1936. Optional<Length> CalculatedStyleValue::resolve_length(Length::ResolutionContext const& context) const
  1937. {
  1938. auto result = m_calculation->resolve(context, {});
  1939. if (result.value().has<Length>())
  1940. return result.value().get<Length>();
  1941. return {};
  1942. }
  1943. Optional<Length> CalculatedStyleValue::resolve_length(Layout::Node const& layout_node) const
  1944. {
  1945. return resolve_length(Length::ResolutionContext::for_layout_node(layout_node));
  1946. }
  1947. Optional<Length> CalculatedStyleValue::resolve_length_percentage(Layout::Node const& layout_node, Length const& percentage_basis) const
  1948. {
  1949. auto result = m_calculation->resolve(Length::ResolutionContext::for_layout_node(layout_node), percentage_basis);
  1950. return result.value().visit(
  1951. [&](Length const& length) -> Optional<Length> {
  1952. return length;
  1953. },
  1954. [&](Percentage const& percentage) -> Optional<Length> {
  1955. return percentage_basis.percentage_of(percentage);
  1956. },
  1957. [&](auto const&) -> Optional<Length> {
  1958. return {};
  1959. });
  1960. }
  1961. Optional<Percentage> CalculatedStyleValue::resolve_percentage() const
  1962. {
  1963. auto result = m_calculation->resolve({}, {});
  1964. if (result.value().has<Percentage>())
  1965. return result.value().get<Percentage>();
  1966. return {};
  1967. }
  1968. Optional<Time> CalculatedStyleValue::resolve_time() const
  1969. {
  1970. auto result = m_calculation->resolve({}, {});
  1971. if (result.value().has<Time>())
  1972. return result.value().get<Time>();
  1973. return {};
  1974. }
  1975. Optional<Time> CalculatedStyleValue::resolve_time_percentage(Time const& percentage_basis) const
  1976. {
  1977. auto result = m_calculation->resolve({}, percentage_basis);
  1978. return result.value().visit(
  1979. [&](Time const& time) -> Optional<Time> {
  1980. return time;
  1981. },
  1982. [&](auto const&) -> Optional<Time> {
  1983. return {};
  1984. });
  1985. }
  1986. Optional<double> CalculatedStyleValue::resolve_number() const
  1987. {
  1988. auto result = m_calculation->resolve({}, {});
  1989. if (result.value().has<Number>())
  1990. return result.value().get<Number>().value();
  1991. return {};
  1992. }
  1993. Optional<i64> CalculatedStyleValue::resolve_integer()
  1994. {
  1995. auto result = m_calculation->resolve({}, {});
  1996. if (result.value().has<Number>())
  1997. return result.value().get<Number>().integer_value();
  1998. return {};
  1999. }
  2000. bool CalculatedStyleValue::contains_percentage() const
  2001. {
  2002. return m_calculation->contains_percentage();
  2003. }
  2004. }