StyleValue.cpp 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
  4. * Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
  5. * Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include <AK/ByteBuffer.h>
  10. #include <LibGfx/Palette.h>
  11. #include <LibWeb/CSS/Serialize.h>
  12. #include <LibWeb/CSS/StyleValue.h>
  13. #include <LibWeb/CSS/StyleValues/AngleStyleValue.h>
  14. #include <LibWeb/CSS/StyleValues/BackgroundRepeatStyleValue.h>
  15. #include <LibWeb/CSS/StyleValues/BackgroundSizeStyleValue.h>
  16. #include <LibWeb/CSS/StyleValues/BackgroundStyleValue.h>
  17. #include <LibWeb/CSS/StyleValues/BorderRadiusShorthandStyleValue.h>
  18. #include <LibWeb/CSS/StyleValues/BorderRadiusStyleValue.h>
  19. #include <LibWeb/CSS/StyleValues/BorderStyleValue.h>
  20. #include <LibWeb/CSS/StyleValues/ColorStyleValue.h>
  21. #include <LibWeb/CSS/StyleValues/ConicGradientStyleValue.h>
  22. #include <LibWeb/CSS/StyleValues/ContentStyleValue.h>
  23. #include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
  24. #include <LibWeb/CSS/StyleValues/FlexFlowStyleValue.h>
  25. #include <LibWeb/CSS/StyleValues/FlexStyleValue.h>
  26. #include <LibWeb/CSS/StyleValues/FontStyleValue.h>
  27. #include <LibWeb/CSS/StyleValues/FrequencyStyleValue.h>
  28. #include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h>
  29. #include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
  30. #include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
  31. #include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
  32. #include <LibWeb/CSS/StyleValues/GridTrackSizeStyleValue.h>
  33. #include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
  34. #include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
  35. #include <LibWeb/CSS/StyleValues/LinearGradientStyleValue.h>
  36. #include <LibWeb/CSS/StyleValues/RadialGradientStyleValue.h>
  37. #include <LibWeb/DOM/Document.h>
  38. #include <LibWeb/HTML/BrowsingContext.h>
  39. #include <LibWeb/Loader/LoadRequest.h>
  40. #include <LibWeb/Loader/ResourceLoader.h>
  41. #include <LibWeb/Page/Page.h>
  42. #include <LibWeb/Painting/GradientPainting.h>
  43. #include <LibWeb/Platform/Timer.h>
  44. namespace Web::CSS {
  45. StyleValue::StyleValue(Type type)
  46. : m_type(type)
  47. {
  48. }
  49. AbstractImageStyleValue const& StyleValue::as_abstract_image() const
  50. {
  51. VERIFY(is_abstract_image());
  52. return static_cast<AbstractImageStyleValue const&>(*this);
  53. }
  54. AngleStyleValue const& StyleValue::as_angle() const
  55. {
  56. VERIFY(is_angle());
  57. return static_cast<AngleStyleValue const&>(*this);
  58. }
  59. BackgroundStyleValue const& StyleValue::as_background() const
  60. {
  61. VERIFY(is_background());
  62. return static_cast<BackgroundStyleValue const&>(*this);
  63. }
  64. BackgroundRepeatStyleValue const& StyleValue::as_background_repeat() const
  65. {
  66. VERIFY(is_background_repeat());
  67. return static_cast<BackgroundRepeatStyleValue const&>(*this);
  68. }
  69. BackgroundSizeStyleValue const& StyleValue::as_background_size() const
  70. {
  71. VERIFY(is_background_size());
  72. return static_cast<BackgroundSizeStyleValue const&>(*this);
  73. }
  74. BorderStyleValue const& StyleValue::as_border() const
  75. {
  76. VERIFY(is_border());
  77. return static_cast<BorderStyleValue const&>(*this);
  78. }
  79. BorderRadiusStyleValue const& StyleValue::as_border_radius() const
  80. {
  81. VERIFY(is_border_radius());
  82. return static_cast<BorderRadiusStyleValue const&>(*this);
  83. }
  84. BorderRadiusShorthandStyleValue const& StyleValue::as_border_radius_shorthand() const
  85. {
  86. VERIFY(is_border_radius_shorthand());
  87. return static_cast<BorderRadiusShorthandStyleValue const&>(*this);
  88. }
  89. ShadowStyleValue const& StyleValue::as_shadow() const
  90. {
  91. VERIFY(is_shadow());
  92. return static_cast<ShadowStyleValue const&>(*this);
  93. }
  94. CalculatedStyleValue const& StyleValue::as_calculated() const
  95. {
  96. VERIFY(is_calculated());
  97. return static_cast<CalculatedStyleValue const&>(*this);
  98. }
  99. ColorStyleValue const& StyleValue::as_color() const
  100. {
  101. VERIFY(is_color());
  102. return static_cast<ColorStyleValue const&>(*this);
  103. }
  104. ConicGradientStyleValue const& StyleValue::as_conic_gradient() const
  105. {
  106. VERIFY(is_conic_gradient());
  107. return static_cast<ConicGradientStyleValue const&>(*this);
  108. }
  109. ContentStyleValue const& StyleValue::as_content() const
  110. {
  111. VERIFY(is_content());
  112. return static_cast<ContentStyleValue const&>(*this);
  113. }
  114. FilterValueListStyleValue const& StyleValue::as_filter_value_list() const
  115. {
  116. VERIFY(is_filter_value_list());
  117. return static_cast<FilterValueListStyleValue const&>(*this);
  118. }
  119. FlexStyleValue const& StyleValue::as_flex() const
  120. {
  121. VERIFY(is_flex());
  122. return static_cast<FlexStyleValue const&>(*this);
  123. }
  124. FlexFlowStyleValue const& StyleValue::as_flex_flow() const
  125. {
  126. VERIFY(is_flex_flow());
  127. return static_cast<FlexFlowStyleValue const&>(*this);
  128. }
  129. FontStyleValue const& StyleValue::as_font() const
  130. {
  131. VERIFY(is_font());
  132. return static_cast<FontStyleValue const&>(*this);
  133. }
  134. FrequencyStyleValue const& StyleValue::as_frequency() const
  135. {
  136. VERIFY(is_frequency());
  137. return static_cast<FrequencyStyleValue const&>(*this);
  138. }
  139. GridTrackPlacementShorthandStyleValue const& StyleValue::as_grid_track_placement_shorthand() const
  140. {
  141. VERIFY(is_grid_track_placement_shorthand());
  142. return static_cast<GridTrackPlacementShorthandStyleValue const&>(*this);
  143. }
  144. GridAreaShorthandStyleValue const& StyleValue::as_grid_area_shorthand() const
  145. {
  146. VERIFY(is_grid_area_shorthand());
  147. return static_cast<GridAreaShorthandStyleValue const&>(*this);
  148. }
  149. GridTemplateAreaStyleValue const& StyleValue::as_grid_template_area() const
  150. {
  151. VERIFY(is_grid_template_area());
  152. return static_cast<GridTemplateAreaStyleValue const&>(*this);
  153. }
  154. GridTrackPlacementStyleValue const& StyleValue::as_grid_track_placement() const
  155. {
  156. VERIFY(is_grid_track_placement());
  157. return static_cast<GridTrackPlacementStyleValue const&>(*this);
  158. }
  159. IdentifierStyleValue const& StyleValue::as_identifier() const
  160. {
  161. VERIFY(is_identifier());
  162. return static_cast<IdentifierStyleValue const&>(*this);
  163. }
  164. ImageStyleValue const& StyleValue::as_image() const
  165. {
  166. VERIFY(is_image());
  167. return static_cast<ImageStyleValue const&>(*this);
  168. }
  169. InheritStyleValue const& StyleValue::as_inherit() const
  170. {
  171. VERIFY(is_inherit());
  172. return static_cast<InheritStyleValue const&>(*this);
  173. }
  174. InitialStyleValue const& StyleValue::as_initial() const
  175. {
  176. VERIFY(is_initial());
  177. return static_cast<InitialStyleValue const&>(*this);
  178. }
  179. LengthStyleValue const& StyleValue::as_length() const
  180. {
  181. VERIFY(is_length());
  182. return static_cast<LengthStyleValue const&>(*this);
  183. }
  184. GridTrackSizeStyleValue const& StyleValue::as_grid_track_size_list() const
  185. {
  186. VERIFY(is_grid_track_size_list());
  187. return static_cast<GridTrackSizeStyleValue const&>(*this);
  188. }
  189. LinearGradientStyleValue const& StyleValue::as_linear_gradient() const
  190. {
  191. VERIFY(is_linear_gradient());
  192. return static_cast<LinearGradientStyleValue const&>(*this);
  193. }
  194. ListStyleStyleValue const& StyleValue::as_list_style() const
  195. {
  196. VERIFY(is_list_style());
  197. return static_cast<ListStyleStyleValue const&>(*this);
  198. }
  199. NumericStyleValue const& StyleValue::as_numeric() const
  200. {
  201. VERIFY(is_numeric());
  202. return static_cast<NumericStyleValue const&>(*this);
  203. }
  204. OverflowStyleValue const& StyleValue::as_overflow() const
  205. {
  206. VERIFY(is_overflow());
  207. return static_cast<OverflowStyleValue const&>(*this);
  208. }
  209. PercentageStyleValue const& StyleValue::as_percentage() const
  210. {
  211. VERIFY(is_percentage());
  212. return static_cast<PercentageStyleValue const&>(*this);
  213. }
  214. PositionStyleValue const& StyleValue::as_position() const
  215. {
  216. VERIFY(is_position());
  217. return static_cast<PositionStyleValue const&>(*this);
  218. }
  219. RadialGradientStyleValue const& StyleValue::as_radial_gradient() const
  220. {
  221. VERIFY(is_radial_gradient());
  222. return static_cast<RadialGradientStyleValue const&>(*this);
  223. }
  224. RectStyleValue const& StyleValue::as_rect() const
  225. {
  226. VERIFY(is_rect());
  227. return static_cast<RectStyleValue const&>(*this);
  228. }
  229. ResolutionStyleValue const& StyleValue::as_resolution() const
  230. {
  231. VERIFY(is_resolution());
  232. return static_cast<ResolutionStyleValue const&>(*this);
  233. }
  234. StringStyleValue const& StyleValue::as_string() const
  235. {
  236. VERIFY(is_string());
  237. return static_cast<StringStyleValue const&>(*this);
  238. }
  239. TextDecorationStyleValue const& StyleValue::as_text_decoration() const
  240. {
  241. VERIFY(is_text_decoration());
  242. return static_cast<TextDecorationStyleValue const&>(*this);
  243. }
  244. TimeStyleValue const& StyleValue::as_time() const
  245. {
  246. VERIFY(is_time());
  247. return static_cast<TimeStyleValue const&>(*this);
  248. }
  249. TransformationStyleValue const& StyleValue::as_transformation() const
  250. {
  251. VERIFY(is_transformation());
  252. return static_cast<TransformationStyleValue const&>(*this);
  253. }
  254. UnresolvedStyleValue const& StyleValue::as_unresolved() const
  255. {
  256. VERIFY(is_unresolved());
  257. return static_cast<UnresolvedStyleValue const&>(*this);
  258. }
  259. UnsetStyleValue const& StyleValue::as_unset() const
  260. {
  261. VERIFY(is_unset());
  262. return static_cast<UnsetStyleValue const&>(*this);
  263. }
  264. StyleValueList const& StyleValue::as_value_list() const
  265. {
  266. VERIFY(is_value_list());
  267. return static_cast<StyleValueList const&>(*this);
  268. }
  269. void CalculatedStyleValue::CalculationResult::add(CalculationResult const& other, Layout::Node const* layout_node, PercentageBasis const& percentage_basis)
  270. {
  271. add_or_subtract_internal(SumOperation::Add, other, layout_node, percentage_basis);
  272. }
  273. void CalculatedStyleValue::CalculationResult::subtract(CalculationResult const& other, Layout::Node const* layout_node, PercentageBasis const& percentage_basis)
  274. {
  275. add_or_subtract_internal(SumOperation::Subtract, other, layout_node, percentage_basis);
  276. }
  277. void CalculatedStyleValue::CalculationResult::add_or_subtract_internal(SumOperation op, CalculationResult const& other, Layout::Node const* layout_node, PercentageBasis const& percentage_basis)
  278. {
  279. // 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>".
  280. // Though, having the same type may mean that one side is a <dimension> and the other a <percentage>.
  281. // Note: This is almost identical to ::add()
  282. m_value.visit(
  283. [&](Number const& number) {
  284. auto other_number = other.m_value.get<Number>();
  285. if (op == SumOperation::Add) {
  286. m_value = number + other_number;
  287. } else {
  288. m_value = number - other_number;
  289. }
  290. },
  291. [&](Angle const& angle) {
  292. auto this_degrees = angle.to_degrees();
  293. if (other.m_value.has<Angle>()) {
  294. auto other_degrees = other.m_value.get<Angle>().to_degrees();
  295. if (op == SumOperation::Add)
  296. m_value = Angle::make_degrees(this_degrees + other_degrees);
  297. else
  298. m_value = Angle::make_degrees(this_degrees - other_degrees);
  299. } else {
  300. VERIFY(percentage_basis.has<Angle>());
  301. auto other_degrees = percentage_basis.get<Angle>().percentage_of(other.m_value.get<Percentage>()).to_degrees();
  302. if (op == SumOperation::Add)
  303. m_value = Angle::make_degrees(this_degrees + other_degrees);
  304. else
  305. m_value = Angle::make_degrees(this_degrees - other_degrees);
  306. }
  307. },
  308. [&](Frequency const& frequency) {
  309. auto this_hertz = frequency.to_hertz();
  310. if (other.m_value.has<Frequency>()) {
  311. auto other_hertz = other.m_value.get<Frequency>().to_hertz();
  312. if (op == SumOperation::Add)
  313. m_value = Frequency::make_hertz(this_hertz + other_hertz);
  314. else
  315. m_value = Frequency::make_hertz(this_hertz - other_hertz);
  316. } else {
  317. VERIFY(percentage_basis.has<Frequency>());
  318. auto other_hertz = percentage_basis.get<Frequency>().percentage_of(other.m_value.get<Percentage>()).to_hertz();
  319. if (op == SumOperation::Add)
  320. m_value = Frequency::make_hertz(this_hertz + other_hertz);
  321. else
  322. m_value = Frequency::make_hertz(this_hertz - other_hertz);
  323. }
  324. },
  325. [&](Length const& length) {
  326. auto this_px = length.to_px(*layout_node);
  327. if (other.m_value.has<Length>()) {
  328. auto other_px = other.m_value.get<Length>().to_px(*layout_node);
  329. if (op == SumOperation::Add)
  330. m_value = Length::make_px(this_px + other_px);
  331. else
  332. m_value = Length::make_px(this_px - other_px);
  333. } else {
  334. VERIFY(percentage_basis.has<Length>());
  335. auto other_px = percentage_basis.get<Length>().percentage_of(other.m_value.get<Percentage>()).to_px(*layout_node);
  336. if (op == SumOperation::Add)
  337. m_value = Length::make_px(this_px + other_px);
  338. else
  339. m_value = Length::make_px(this_px - other_px);
  340. }
  341. },
  342. [&](Time const& time) {
  343. auto this_seconds = time.to_seconds();
  344. if (other.m_value.has<Time>()) {
  345. auto other_seconds = other.m_value.get<Time>().to_seconds();
  346. if (op == SumOperation::Add)
  347. m_value = Time::make_seconds(this_seconds + other_seconds);
  348. else
  349. m_value = Time::make_seconds(this_seconds - other_seconds);
  350. } else {
  351. VERIFY(percentage_basis.has<Time>());
  352. auto other_seconds = percentage_basis.get<Time>().percentage_of(other.m_value.get<Percentage>()).to_seconds();
  353. if (op == SumOperation::Add)
  354. m_value = Time::make_seconds(this_seconds + other_seconds);
  355. else
  356. m_value = Time::make_seconds(this_seconds - other_seconds);
  357. }
  358. },
  359. [&](Percentage const& percentage) {
  360. if (other.m_value.has<Percentage>()) {
  361. if (op == SumOperation::Add)
  362. m_value = Percentage { percentage.value() + other.m_value.get<Percentage>().value() };
  363. else
  364. m_value = Percentage { percentage.value() - other.m_value.get<Percentage>().value() };
  365. return;
  366. }
  367. // 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`.
  368. CalculationResult new_value = other;
  369. if (op == SumOperation::Add) {
  370. new_value.add(*this, layout_node, percentage_basis);
  371. } else {
  372. // Turn 'this - other' into '-other + this', as 'A + B == B + A', but 'A - B != B - A'
  373. new_value.multiply_by({ Number { Number::Type::Integer, -1.0f } }, layout_node);
  374. new_value.add(*this, layout_node, percentage_basis);
  375. }
  376. *this = new_value;
  377. });
  378. }
  379. void CalculatedStyleValue::CalculationResult::multiply_by(CalculationResult const& other, Layout::Node const* layout_node)
  380. {
  381. // We know from validation when resolving the type, that at least one side must be a <number> or <integer>.
  382. // Both of these are represented as a float.
  383. VERIFY(m_value.has<Number>() || other.m_value.has<Number>());
  384. bool other_is_number = other.m_value.has<Number>();
  385. m_value.visit(
  386. [&](Number const& number) {
  387. if (other_is_number) {
  388. m_value = number * other.m_value.get<Number>();
  389. } else {
  390. // Avoid duplicating all the logic by swapping `this` and `other`.
  391. CalculationResult new_value = other;
  392. new_value.multiply_by(*this, layout_node);
  393. *this = new_value;
  394. }
  395. },
  396. [&](Angle const& angle) {
  397. m_value = Angle::make_degrees(angle.to_degrees() * other.m_value.get<Number>().value());
  398. },
  399. [&](Frequency const& frequency) {
  400. m_value = Frequency::make_hertz(frequency.to_hertz() * other.m_value.get<Number>().value());
  401. },
  402. [&](Length const& length) {
  403. VERIFY(layout_node);
  404. m_value = Length::make_px(length.to_px(*layout_node) * other.m_value.get<Number>().value());
  405. },
  406. [&](Time const& time) {
  407. m_value = Time::make_seconds(time.to_seconds() * other.m_value.get<Number>().value());
  408. },
  409. [&](Percentage const& percentage) {
  410. m_value = Percentage { percentage.value() * other.m_value.get<Number>().value() };
  411. });
  412. }
  413. void CalculatedStyleValue::CalculationResult::divide_by(CalculationResult const& other, Layout::Node const* layout_node)
  414. {
  415. // We know from validation when resolving the type, that `other` must be a <number> or <integer>.
  416. // Both of these are represented as a Number.
  417. auto denominator = other.m_value.get<Number>().value();
  418. // FIXME: Dividing by 0 is invalid, and should be caught during parsing.
  419. VERIFY(denominator != 0.0f);
  420. m_value.visit(
  421. [&](Number const& number) {
  422. m_value = Number {
  423. Number::Type::Number,
  424. number.value() / denominator
  425. };
  426. },
  427. [&](Angle const& angle) {
  428. m_value = Angle::make_degrees(angle.to_degrees() / denominator);
  429. },
  430. [&](Frequency const& frequency) {
  431. m_value = Frequency::make_hertz(frequency.to_hertz() / denominator);
  432. },
  433. [&](Length const& length) {
  434. VERIFY(layout_node);
  435. m_value = Length::make_px(length.to_px(*layout_node) / denominator);
  436. },
  437. [&](Time const& time) {
  438. m_value = Time::make_seconds(time.to_seconds() / denominator);
  439. },
  440. [&](Percentage const& percentage) {
  441. m_value = Percentage { percentage.value() / denominator };
  442. });
  443. }
  444. ErrorOr<String> CalculatedStyleValue::to_string() const
  445. {
  446. return String::formatted("calc({})", TRY(m_expression->to_string()));
  447. }
  448. bool CalculatedStyleValue::equals(StyleValue const& other) const
  449. {
  450. if (type() != other.type())
  451. return false;
  452. // This is a case where comparing the strings actually makes sense.
  453. return to_string().release_value_but_fixme_should_propagate_errors() == other.to_string().release_value_but_fixme_should_propagate_errors();
  454. }
  455. ErrorOr<String> CalculatedStyleValue::CalcNumberValue::to_string() const
  456. {
  457. return value.visit(
  458. [](Number const& number) -> ErrorOr<String> { return String::number(number.value()); },
  459. [](NonnullOwnPtr<CalcNumberSum> const& sum) -> ErrorOr<String> { return String::formatted("({})", TRY(sum->to_string())); });
  460. }
  461. ErrorOr<String> CalculatedStyleValue::CalcValue::to_string() const
  462. {
  463. return value.visit(
  464. [](Number const& number) -> ErrorOr<String> { return String::number(number.value()); },
  465. [](NonnullOwnPtr<CalcSum> const& sum) -> ErrorOr<String> { return String::formatted("({})", TRY(sum->to_string())); },
  466. [](auto const& v) -> ErrorOr<String> { return v.to_string(); });
  467. }
  468. ErrorOr<String> CalculatedStyleValue::CalcSum::to_string() const
  469. {
  470. StringBuilder builder;
  471. TRY(builder.try_append(TRY(first_calc_product->to_string())));
  472. for (auto const& item : zero_or_more_additional_calc_products)
  473. TRY(builder.try_append(TRY(item->to_string())));
  474. return builder.to_string();
  475. }
  476. ErrorOr<String> CalculatedStyleValue::CalcNumberSum::to_string() const
  477. {
  478. StringBuilder builder;
  479. TRY(builder.try_append(TRY(first_calc_number_product->to_string())));
  480. for (auto const& item : zero_or_more_additional_calc_number_products)
  481. TRY(builder.try_append(TRY(item->to_string())));
  482. return builder.to_string();
  483. }
  484. ErrorOr<String> CalculatedStyleValue::CalcProduct::to_string() const
  485. {
  486. StringBuilder builder;
  487. TRY(builder.try_append(TRY(first_calc_value.to_string())));
  488. for (auto const& item : zero_or_more_additional_calc_values)
  489. TRY(builder.try_append(TRY(item->to_string())));
  490. return builder.to_string();
  491. }
  492. ErrorOr<String> CalculatedStyleValue::CalcSumPartWithOperator::to_string() const
  493. {
  494. return String::formatted(" {} {}", op == SumOperation::Add ? "+"sv : "-"sv, TRY(value->to_string()));
  495. }
  496. ErrorOr<String> CalculatedStyleValue::CalcProductPartWithOperator::to_string() const
  497. {
  498. auto value_string = TRY(value.visit(
  499. [](CalcValue const& v) { return v.to_string(); },
  500. [](CalcNumberValue const& v) { return v.to_string(); }));
  501. return String::formatted(" {} {}", op == ProductOperation::Multiply ? "*"sv : "/"sv, value_string);
  502. }
  503. ErrorOr<String> CalculatedStyleValue::CalcNumberProduct::to_string() const
  504. {
  505. StringBuilder builder;
  506. TRY(builder.try_append(TRY(first_calc_number_value.to_string())));
  507. for (auto const& item : zero_or_more_additional_calc_number_values)
  508. TRY(builder.try_append(TRY(item->to_string())));
  509. return builder.to_string();
  510. }
  511. ErrorOr<String> CalculatedStyleValue::CalcNumberProductPartWithOperator::to_string() const
  512. {
  513. return String::formatted(" {} {}", op == ProductOperation::Multiply ? "*"sv : "/"sv, TRY(value.to_string()));
  514. }
  515. ErrorOr<String> CalculatedStyleValue::CalcNumberSumPartWithOperator::to_string() const
  516. {
  517. return String::formatted(" {} {}", op == SumOperation::Add ? "+"sv : "-"sv, TRY(value->to_string()));
  518. }
  519. Optional<Angle> CalculatedStyleValue::resolve_angle() const
  520. {
  521. auto result = m_expression->resolve(nullptr, {});
  522. if (result.value().has<Angle>())
  523. return result.value().get<Angle>();
  524. return {};
  525. }
  526. Optional<Angle> CalculatedStyleValue::resolve_angle_percentage(Angle const& percentage_basis) const
  527. {
  528. auto result = m_expression->resolve(nullptr, percentage_basis);
  529. return result.value().visit(
  530. [&](Angle const& angle) -> Optional<Angle> {
  531. return angle;
  532. },
  533. [&](Percentage const& percentage) -> Optional<Angle> {
  534. return percentage_basis.percentage_of(percentage);
  535. },
  536. [&](auto const&) -> Optional<Angle> {
  537. return {};
  538. });
  539. }
  540. Optional<Frequency> CalculatedStyleValue::resolve_frequency() const
  541. {
  542. auto result = m_expression->resolve(nullptr, {});
  543. if (result.value().has<Frequency>())
  544. return result.value().get<Frequency>();
  545. return {};
  546. }
  547. Optional<Frequency> CalculatedStyleValue::resolve_frequency_percentage(Frequency const& percentage_basis) const
  548. {
  549. auto result = m_expression->resolve(nullptr, percentage_basis);
  550. return result.value().visit(
  551. [&](Frequency const& frequency) -> Optional<Frequency> {
  552. return frequency;
  553. },
  554. [&](Percentage const& percentage) -> Optional<Frequency> {
  555. return percentage_basis.percentage_of(percentage);
  556. },
  557. [&](auto const&) -> Optional<Frequency> {
  558. return {};
  559. });
  560. }
  561. Optional<Length> CalculatedStyleValue::resolve_length(Layout::Node const& layout_node) const
  562. {
  563. auto result = m_expression->resolve(&layout_node, {});
  564. if (result.value().has<Length>())
  565. return result.value().get<Length>();
  566. return {};
  567. }
  568. Optional<Length> CalculatedStyleValue::resolve_length_percentage(Layout::Node const& layout_node, Length const& percentage_basis) const
  569. {
  570. auto result = m_expression->resolve(&layout_node, percentage_basis);
  571. return result.value().visit(
  572. [&](Length const& length) -> Optional<Length> {
  573. return length;
  574. },
  575. [&](Percentage const& percentage) -> Optional<Length> {
  576. return percentage_basis.percentage_of(percentage);
  577. },
  578. [&](auto const&) -> Optional<Length> {
  579. return {};
  580. });
  581. }
  582. Optional<Percentage> CalculatedStyleValue::resolve_percentage() const
  583. {
  584. auto result = m_expression->resolve(nullptr, {});
  585. if (result.value().has<Percentage>())
  586. return result.value().get<Percentage>();
  587. return {};
  588. }
  589. Optional<Time> CalculatedStyleValue::resolve_time() const
  590. {
  591. auto result = m_expression->resolve(nullptr, {});
  592. if (result.value().has<Time>())
  593. return result.value().get<Time>();
  594. return {};
  595. }
  596. Optional<Time> CalculatedStyleValue::resolve_time_percentage(Time const& percentage_basis) const
  597. {
  598. auto result = m_expression->resolve(nullptr, percentage_basis);
  599. return result.value().visit(
  600. [&](Time const& time) -> Optional<Time> {
  601. return time;
  602. },
  603. [&](auto const&) -> Optional<Time> {
  604. return {};
  605. });
  606. }
  607. Optional<float> CalculatedStyleValue::resolve_number()
  608. {
  609. auto result = m_expression->resolve(nullptr, {});
  610. if (result.value().has<Number>())
  611. return result.value().get<Number>().value();
  612. return {};
  613. }
  614. Optional<i64> CalculatedStyleValue::resolve_integer()
  615. {
  616. auto result = m_expression->resolve(nullptr, {});
  617. if (result.value().has<Number>())
  618. return result.value().get<Number>().integer_value();
  619. return {};
  620. }
  621. static bool is_number(CalculatedStyleValue::ResolvedType type)
  622. {
  623. return type == CalculatedStyleValue::ResolvedType::Number || type == CalculatedStyleValue::ResolvedType::Integer;
  624. }
  625. static bool is_dimension(CalculatedStyleValue::ResolvedType type)
  626. {
  627. return type != CalculatedStyleValue::ResolvedType::Number
  628. && type != CalculatedStyleValue::ResolvedType::Integer
  629. && type != CalculatedStyleValue::ResolvedType::Percentage;
  630. }
  631. template<typename SumWithOperator>
  632. static Optional<CalculatedStyleValue::ResolvedType> resolve_sum_type(CalculatedStyleValue::ResolvedType first_type, Vector<NonnullOwnPtr<SumWithOperator>> const& zero_or_more_additional_products)
  633. {
  634. auto type = first_type;
  635. for (auto const& product : zero_or_more_additional_products) {
  636. auto maybe_product_type = product->resolved_type();
  637. if (!maybe_product_type.has_value())
  638. return {};
  639. auto product_type = maybe_product_type.value();
  640. // At + or -, check that both sides have the same type, or that one side is a <number> and the other is an <integer>.
  641. // If both sides are the same type, resolve to that type.
  642. if (product_type == type)
  643. continue;
  644. // If one side is a <number> and the other is an <integer>, resolve to <number>.
  645. if (is_number(type) && is_number(product_type)) {
  646. type = CalculatedStyleValue::ResolvedType::Number;
  647. continue;
  648. }
  649. // FIXME: calc() handles <percentage> by allowing them to pretend to be whatever <dimension> type is allowed at this location.
  650. // Since we can't easily check what that type is, we just allow <percentage> to combine with any other <dimension> type.
  651. if (type == CalculatedStyleValue::ResolvedType::Percentage && is_dimension(product_type)) {
  652. type = product_type;
  653. continue;
  654. }
  655. if (is_dimension(type) && product_type == CalculatedStyleValue::ResolvedType::Percentage)
  656. continue;
  657. return {};
  658. }
  659. return type;
  660. }
  661. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcSum::resolved_type() const
  662. {
  663. auto maybe_type = first_calc_product->resolved_type();
  664. if (!maybe_type.has_value())
  665. return {};
  666. auto type = maybe_type.value();
  667. return resolve_sum_type(type, zero_or_more_additional_calc_products);
  668. }
  669. // https://www.w3.org/TR/CSS2/visufx.html#value-def-shape
  670. Gfx::FloatRect EdgeRect::resolved(Layout::Node const& layout_node, Gfx::FloatRect border_box) const
  671. {
  672. // In CSS 2.1, the only valid <shape> value is: rect(<top>, <right>, <bottom>, <left>) where
  673. // <top> and <bottom> specify offsets from the top border edge of the box, and <right>, and
  674. // <left> specify offsets from the left border edge of the box.
  675. // The value 'auto' means that a given edge of the clipping region will be the same as the edge
  676. // of the element's generated border box (i.e., 'auto' means the same as '0' for <top> and
  677. // <left>, the same as the used value of the height plus the sum of vertical padding and border
  678. // widths for <bottom>, and the same as the used value of the width plus the sum of the
  679. // horizontal padding and border widths for <right>, such that four 'auto' values result in the
  680. // clipping region being the same as the element's border box).
  681. auto left = border_box.left() + (left_edge.is_auto() ? 0 : left_edge.to_px(layout_node)).value();
  682. auto top = border_box.top() + (top_edge.is_auto() ? 0 : top_edge.to_px(layout_node)).value();
  683. auto right = border_box.left() + (right_edge.is_auto() ? border_box.width() : right_edge.to_px(layout_node)).value();
  684. auto bottom = border_box.top() + (bottom_edge.is_auto() ? border_box.height() : bottom_edge.to_px(layout_node)).value();
  685. return Gfx::FloatRect {
  686. left,
  687. top,
  688. right - left,
  689. bottom - top
  690. };
  691. }
  692. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcNumberSum::resolved_type() const
  693. {
  694. auto maybe_type = first_calc_number_product->resolved_type();
  695. if (!maybe_type.has_value())
  696. return {};
  697. auto type = maybe_type.value();
  698. return resolve_sum_type(type, zero_or_more_additional_calc_number_products);
  699. }
  700. template<typename ProductWithOperator>
  701. static Optional<CalculatedStyleValue::ResolvedType> resolve_product_type(CalculatedStyleValue::ResolvedType first_type, Vector<NonnullOwnPtr<ProductWithOperator>> const& zero_or_more_additional_values)
  702. {
  703. auto type = first_type;
  704. for (auto const& value : zero_or_more_additional_values) {
  705. auto maybe_value_type = value->resolved_type();
  706. if (!maybe_value_type.has_value())
  707. return {};
  708. auto value_type = maybe_value_type.value();
  709. if (value->op == CalculatedStyleValue::ProductOperation::Multiply) {
  710. // At *, check that at least one side is <number>.
  711. if (!(is_number(type) || is_number(value_type)))
  712. return {};
  713. // If both sides are <integer>, resolve to <integer>.
  714. if (type == CalculatedStyleValue::ResolvedType::Integer && value_type == CalculatedStyleValue::ResolvedType::Integer) {
  715. type = CalculatedStyleValue::ResolvedType::Integer;
  716. } else {
  717. // Otherwise, resolve to the type of the other side.
  718. if (is_number(type))
  719. type = value_type;
  720. }
  721. continue;
  722. } else {
  723. VERIFY(value->op == CalculatedStyleValue::ProductOperation::Divide);
  724. // At /, check that the right side is <number>.
  725. if (!is_number(value_type))
  726. return {};
  727. // If the left side is <integer>, resolve to <number>.
  728. if (type == CalculatedStyleValue::ResolvedType::Integer) {
  729. type = CalculatedStyleValue::ResolvedType::Number;
  730. } else {
  731. // Otherwise, resolve to the type of the left side.
  732. }
  733. // FIXME: Division by zero makes the whole calc() expression invalid.
  734. }
  735. }
  736. return type;
  737. }
  738. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcProduct::resolved_type() const
  739. {
  740. auto maybe_type = first_calc_value.resolved_type();
  741. if (!maybe_type.has_value())
  742. return {};
  743. auto type = maybe_type.value();
  744. return resolve_product_type(type, zero_or_more_additional_calc_values);
  745. }
  746. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcSumPartWithOperator::resolved_type() const
  747. {
  748. return value->resolved_type();
  749. }
  750. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcNumberProduct::resolved_type() const
  751. {
  752. auto maybe_type = first_calc_number_value.resolved_type();
  753. if (!maybe_type.has_value())
  754. return {};
  755. auto type = maybe_type.value();
  756. return resolve_product_type(type, zero_or_more_additional_calc_number_values);
  757. }
  758. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcNumberProductPartWithOperator::resolved_type() const
  759. {
  760. return value.resolved_type();
  761. }
  762. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcNumberSumPartWithOperator::resolved_type() const
  763. {
  764. return value->resolved_type();
  765. }
  766. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcProductPartWithOperator::resolved_type() const
  767. {
  768. return value.visit(
  769. [](CalcValue const& calc_value) {
  770. return calc_value.resolved_type();
  771. },
  772. [](CalcNumberValue const& calc_number_value) {
  773. return calc_number_value.resolved_type();
  774. });
  775. }
  776. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcValue::resolved_type() const
  777. {
  778. return value.visit(
  779. [](Number const& number) -> Optional<CalculatedStyleValue::ResolvedType> {
  780. return { number.is_integer() ? ResolvedType::Integer : ResolvedType::Number };
  781. },
  782. [](Angle const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Angle }; },
  783. [](Frequency const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Frequency }; },
  784. [](Length const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Length }; },
  785. [](Percentage const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Percentage }; },
  786. [](Time const&) -> Optional<CalculatedStyleValue::ResolvedType> { return { ResolvedType::Time }; },
  787. [](NonnullOwnPtr<CalcSum> const& sum) { return sum->resolved_type(); });
  788. }
  789. Optional<CalculatedStyleValue::ResolvedType> CalculatedStyleValue::CalcNumberValue::resolved_type() const
  790. {
  791. return value.visit(
  792. [](Number const& number) -> Optional<CalculatedStyleValue::ResolvedType> {
  793. return { number.is_integer() ? ResolvedType::Integer : ResolvedType::Number };
  794. },
  795. [](NonnullOwnPtr<CalcNumberSum> const& sum) { return sum->resolved_type(); });
  796. }
  797. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberValue::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  798. {
  799. return value.visit(
  800. [&](Number const& number) -> CalculatedStyleValue::CalculationResult {
  801. return CalculatedStyleValue::CalculationResult { number };
  802. },
  803. [&](NonnullOwnPtr<CalcNumberSum> const& sum) -> CalculatedStyleValue::CalculationResult {
  804. return sum->resolve(layout_node, percentage_basis);
  805. });
  806. }
  807. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcValue::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  808. {
  809. return value.visit(
  810. [&](NonnullOwnPtr<CalcSum> const& sum) -> CalculatedStyleValue::CalculationResult {
  811. return sum->resolve(layout_node, percentage_basis);
  812. },
  813. [&](auto const& v) -> CalculatedStyleValue::CalculationResult {
  814. return CalculatedStyleValue::CalculationResult { v };
  815. });
  816. }
  817. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcSum::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  818. {
  819. auto value = first_calc_product->resolve(layout_node, percentage_basis);
  820. for (auto& additional_product : zero_or_more_additional_calc_products) {
  821. auto additional_value = additional_product->resolve(layout_node, percentage_basis);
  822. if (additional_product->op == CalculatedStyleValue::SumOperation::Add)
  823. value.add(additional_value, layout_node, percentage_basis);
  824. else if (additional_product->op == CalculatedStyleValue::SumOperation::Subtract)
  825. value.subtract(additional_value, layout_node, percentage_basis);
  826. else
  827. VERIFY_NOT_REACHED();
  828. }
  829. return value;
  830. }
  831. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberSum::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  832. {
  833. auto value = first_calc_number_product->resolve(layout_node, percentage_basis);
  834. for (auto& additional_product : zero_or_more_additional_calc_number_products) {
  835. auto additional_value = additional_product->resolve(layout_node, percentage_basis);
  836. if (additional_product->op == CSS::CalculatedStyleValue::SumOperation::Add)
  837. value.add(additional_value, layout_node, percentage_basis);
  838. else if (additional_product->op == CalculatedStyleValue::SumOperation::Subtract)
  839. value.subtract(additional_value, layout_node, percentage_basis);
  840. else
  841. VERIFY_NOT_REACHED();
  842. }
  843. return value;
  844. }
  845. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcProduct::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  846. {
  847. auto value = first_calc_value.resolve(layout_node, percentage_basis);
  848. for (auto& additional_value : zero_or_more_additional_calc_values) {
  849. additional_value->value.visit(
  850. [&](CalculatedStyleValue::CalcValue const& calc_value) {
  851. VERIFY(additional_value->op == CalculatedStyleValue::ProductOperation::Multiply);
  852. auto resolved_value = calc_value.resolve(layout_node, percentage_basis);
  853. value.multiply_by(resolved_value, layout_node);
  854. },
  855. [&](CalculatedStyleValue::CalcNumberValue const& calc_number_value) {
  856. VERIFY(additional_value->op == CalculatedStyleValue::ProductOperation::Divide);
  857. auto resolved_calc_number_value = calc_number_value.resolve(layout_node, percentage_basis);
  858. // FIXME: Checking for division by 0 should happen during parsing.
  859. VERIFY(resolved_calc_number_value.value().get<Number>().value() != 0.0f);
  860. value.divide_by(resolved_calc_number_value, layout_node);
  861. });
  862. }
  863. return value;
  864. }
  865. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberProduct::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  866. {
  867. auto value = first_calc_number_value.resolve(layout_node, percentage_basis);
  868. for (auto& additional_number_value : zero_or_more_additional_calc_number_values) {
  869. auto additional_value = additional_number_value->resolve(layout_node, percentage_basis);
  870. if (additional_number_value->op == CalculatedStyleValue::ProductOperation::Multiply)
  871. value.multiply_by(additional_value, layout_node);
  872. else if (additional_number_value->op == CalculatedStyleValue::ProductOperation::Divide)
  873. value.divide_by(additional_value, layout_node);
  874. else
  875. VERIFY_NOT_REACHED();
  876. }
  877. return value;
  878. }
  879. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcProductPartWithOperator::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  880. {
  881. return value.visit(
  882. [&](CalcValue const& calc_value) {
  883. return calc_value.resolve(layout_node, percentage_basis);
  884. },
  885. [&](CalcNumberValue const& calc_number_value) {
  886. return calc_number_value.resolve(layout_node, percentage_basis);
  887. });
  888. }
  889. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcSumPartWithOperator::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  890. {
  891. return value->resolve(layout_node, percentage_basis);
  892. }
  893. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberProductPartWithOperator::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  894. {
  895. return value.resolve(layout_node, percentage_basis);
  896. }
  897. CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalcNumberSumPartWithOperator::resolve(Layout::Node const* layout_node, PercentageBasis const& percentage_basis) const
  898. {
  899. return value->resolve(layout_node, percentage_basis);
  900. }
  901. static ErrorOr<void> serialize_color_stop_list(StringBuilder& builder, auto const& color_stop_list)
  902. {
  903. bool first = true;
  904. for (auto const& element : color_stop_list) {
  905. if (!first)
  906. TRY(builder.try_append(", "sv));
  907. if (element.transition_hint.has_value())
  908. TRY(builder.try_appendff("{}, "sv, TRY(element.transition_hint->value.to_string())));
  909. TRY(serialize_a_srgb_value(builder, element.color_stop.color));
  910. for (auto position : Array { &element.color_stop.position, &element.color_stop.second_position }) {
  911. if (position->has_value())
  912. TRY(builder.try_appendff(" {}"sv, TRY((*position)->to_string())));
  913. }
  914. first = false;
  915. }
  916. return {};
  917. }
  918. CSSPixelPoint PositionValue::resolved(Layout::Node const& node, CSSPixelRect const& rect) const
  919. {
  920. // Note: A preset + a none default x/y_relative_to is impossible in the syntax (and makes little sense)
  921. CSSPixels x = horizontal_position.visit(
  922. [&](HorizontalPreset preset) -> CSSPixels {
  923. return rect.width() * [&] {
  924. switch (preset) {
  925. case HorizontalPreset::Left:
  926. return 0.0f;
  927. case HorizontalPreset::Center:
  928. return 0.5f;
  929. case HorizontalPreset::Right:
  930. return 1.0f;
  931. default:
  932. VERIFY_NOT_REACHED();
  933. }
  934. }();
  935. },
  936. [&](LengthPercentage length_percentage) -> CSSPixels {
  937. return length_percentage.resolved(node, Length::make_px(rect.width())).to_px(node);
  938. });
  939. CSSPixels y = vertical_position.visit(
  940. [&](VerticalPreset preset) -> CSSPixels {
  941. return rect.height() * [&] {
  942. switch (preset) {
  943. case VerticalPreset::Top:
  944. return 0.0f;
  945. case VerticalPreset::Center:
  946. return 0.5f;
  947. case VerticalPreset::Bottom:
  948. return 1.0f;
  949. default:
  950. VERIFY_NOT_REACHED();
  951. }
  952. }();
  953. },
  954. [&](LengthPercentage length_percentage) -> CSSPixels {
  955. return length_percentage.resolved(node, Length::make_px(rect.height())).to_px(node);
  956. });
  957. if (x_relative_to == HorizontalEdge::Right)
  958. x = rect.width() - x;
  959. if (y_relative_to == VerticalEdge::Bottom)
  960. y = rect.height() - y;
  961. return CSSPixelPoint { rect.x() + x, rect.y() + y };
  962. }
  963. ErrorOr<void> PositionValue::serialize(StringBuilder& builder) const
  964. {
  965. // Note: This means our serialization with simplify any with explicit edges that are just `top left`.
  966. bool has_relative_edges = x_relative_to == HorizontalEdge::Right || y_relative_to == VerticalEdge::Bottom;
  967. if (has_relative_edges)
  968. TRY(builder.try_append(x_relative_to == HorizontalEdge::Left ? "left "sv : "right "sv));
  969. TRY(horizontal_position.visit(
  970. [&](HorizontalPreset preset) -> ErrorOr<void> {
  971. return builder.try_append([&] {
  972. switch (preset) {
  973. case HorizontalPreset::Left:
  974. return "left"sv;
  975. case HorizontalPreset::Center:
  976. return "center"sv;
  977. case HorizontalPreset::Right:
  978. return "right"sv;
  979. default:
  980. VERIFY_NOT_REACHED();
  981. }
  982. }());
  983. },
  984. [&](LengthPercentage length_percentage) -> ErrorOr<void> {
  985. return builder.try_appendff(TRY(length_percentage.to_string()));
  986. }));
  987. TRY(builder.try_append(' '));
  988. if (has_relative_edges)
  989. TRY(builder.try_append(y_relative_to == VerticalEdge::Top ? "top "sv : "bottom "sv));
  990. TRY(vertical_position.visit(
  991. [&](VerticalPreset preset) -> ErrorOr<void> {
  992. return builder.try_append([&] {
  993. switch (preset) {
  994. case VerticalPreset::Top:
  995. return "top"sv;
  996. case VerticalPreset::Center:
  997. return "center"sv;
  998. case VerticalPreset::Bottom:
  999. return "bottom"sv;
  1000. default:
  1001. VERIFY_NOT_REACHED();
  1002. }
  1003. }());
  1004. },
  1005. [&](LengthPercentage length_percentage) -> ErrorOr<void> {
  1006. return builder.try_append(TRY(length_percentage.to_string()));
  1007. }));
  1008. return {};
  1009. }
  1010. ErrorOr<String> ListStyleStyleValue::to_string() const
  1011. {
  1012. return String::formatted("{} {} {}", TRY(m_properties.position->to_string()), TRY(m_properties.image->to_string()), TRY(m_properties.style_type->to_string()));
  1013. }
  1014. ErrorOr<String> NumericStyleValue::to_string() const
  1015. {
  1016. return m_value.visit(
  1017. [](auto value) {
  1018. return String::formatted("{}", value);
  1019. });
  1020. }
  1021. ErrorOr<String> OverflowStyleValue::to_string() const
  1022. {
  1023. return String::formatted("{} {}", TRY(m_properties.overflow_x->to_string()), TRY(m_properties.overflow_y->to_string()));
  1024. }
  1025. ErrorOr<String> PercentageStyleValue::to_string() const
  1026. {
  1027. return m_percentage.to_string();
  1028. }
  1029. ErrorOr<String> PositionStyleValue::to_string() const
  1030. {
  1031. auto to_string = [](PositionEdge edge) {
  1032. switch (edge) {
  1033. case PositionEdge::Left:
  1034. return "left";
  1035. case PositionEdge::Right:
  1036. return "right";
  1037. case PositionEdge::Top:
  1038. return "top";
  1039. case PositionEdge::Bottom:
  1040. return "bottom";
  1041. }
  1042. VERIFY_NOT_REACHED();
  1043. };
  1044. return String::formatted("{} {} {} {}", to_string(m_properties.edge_x), TRY(m_properties.offset_x.to_string()), to_string(m_properties.edge_y), TRY(m_properties.offset_y.to_string()));
  1045. }
  1046. ErrorOr<String> RectStyleValue::to_string() const
  1047. {
  1048. return String::formatted("rect({} {} {} {})", m_rect.top_edge, m_rect.right_edge, m_rect.bottom_edge, m_rect.left_edge);
  1049. }
  1050. ErrorOr<String> ShadowStyleValue::to_string() const
  1051. {
  1052. StringBuilder builder;
  1053. TRY(builder.try_appendff("{} {} {} {} {}", m_properties.color.to_deprecated_string(), TRY(m_properties.offset_x.to_string()), TRY(m_properties.offset_y.to_string()), TRY(m_properties.blur_radius.to_string()), TRY(m_properties.spread_distance.to_string())));
  1054. if (m_properties.placement == ShadowPlacement::Inner)
  1055. TRY(builder.try_append(" inset"sv));
  1056. return builder.to_string();
  1057. }
  1058. ErrorOr<String> TextDecorationStyleValue::to_string() const
  1059. {
  1060. return String::formatted("{} {} {} {}", TRY(m_properties.line->to_string()), TRY(m_properties.thickness->to_string()), TRY(m_properties.style->to_string()), TRY(m_properties.color->to_string()));
  1061. }
  1062. ErrorOr<String> TransformationStyleValue::to_string() const
  1063. {
  1064. StringBuilder builder;
  1065. TRY(builder.try_append(CSS::to_string(m_properties.transform_function)));
  1066. TRY(builder.try_append('('));
  1067. for (size_t i = 0; i < m_properties.values.size(); ++i) {
  1068. TRY(builder.try_append(TRY(m_properties.values[i]->to_string())));
  1069. if (i != m_properties.values.size() - 1)
  1070. TRY(builder.try_append(", "sv));
  1071. }
  1072. TRY(builder.try_append(')'));
  1073. return builder.to_string();
  1074. }
  1075. bool TransformationStyleValue::Properties::operator==(Properties const& other) const
  1076. {
  1077. return transform_function == other.transform_function && values.span() == other.values.span();
  1078. }
  1079. ErrorOr<String> UnresolvedStyleValue::to_string() const
  1080. {
  1081. StringBuilder builder;
  1082. for (auto& value : m_values)
  1083. TRY(builder.try_append(TRY(value.to_string())));
  1084. return builder.to_string();
  1085. }
  1086. bool UnresolvedStyleValue::equals(StyleValue const& other) const
  1087. {
  1088. if (type() != other.type())
  1089. return false;
  1090. // This is a case where comparing the strings actually makes sense.
  1091. return to_string().release_value_but_fixme_should_propagate_errors() == other.to_string().release_value_but_fixme_should_propagate_errors();
  1092. }
  1093. bool StyleValueList::Properties::operator==(Properties const& other) const
  1094. {
  1095. return separator == other.separator && values.span() == other.values.span();
  1096. }
  1097. ErrorOr<String> StyleValueList::to_string() const
  1098. {
  1099. auto separator = ""sv;
  1100. switch (m_properties.separator) {
  1101. case Separator::Space:
  1102. separator = " "sv;
  1103. break;
  1104. case Separator::Comma:
  1105. separator = ", "sv;
  1106. break;
  1107. default:
  1108. VERIFY_NOT_REACHED();
  1109. }
  1110. StringBuilder builder;
  1111. for (size_t i = 0; i < m_properties.values.size(); ++i) {
  1112. TRY(builder.try_append(TRY(m_properties.values[i]->to_string())));
  1113. if (i != m_properties.values.size() - 1)
  1114. TRY(builder.try_append(separator));
  1115. }
  1116. return builder.to_string();
  1117. }
  1118. ValueComparingNonnullRefPtr<RectStyleValue> RectStyleValue::create(EdgeRect rect)
  1119. {
  1120. return adopt_ref(*new RectStyleValue(rect));
  1121. }
  1122. ValueComparingNonnullRefPtr<LengthStyleValue> LengthStyleValue::create(Length const& length)
  1123. {
  1124. if (length.is_auto()) {
  1125. static auto value = adopt_ref(*new LengthStyleValue(CSS::Length::make_auto()));
  1126. return value;
  1127. }
  1128. if (length.is_px()) {
  1129. if (length.raw_value() == 0) {
  1130. static auto value = adopt_ref(*new LengthStyleValue(CSS::Length::make_px(0)));
  1131. return value;
  1132. }
  1133. if (length.raw_value() == 1) {
  1134. static auto value = adopt_ref(*new LengthStyleValue(CSS::Length::make_px(1)));
  1135. return value;
  1136. }
  1137. }
  1138. return adopt_ref(*new LengthStyleValue(length));
  1139. }
  1140. Optional<CSS::Length> absolutized_length(CSS::Length const& length, CSSPixelRect const& viewport_rect, Gfx::FontPixelMetrics const& font_metrics, CSSPixels font_size, CSSPixels root_font_size, CSSPixels line_height, CSSPixels root_line_height)
  1141. {
  1142. if (length.is_px())
  1143. return {};
  1144. if (length.is_absolute() || length.is_relative()) {
  1145. auto px = length.to_px(viewport_rect, font_metrics, font_size, root_font_size, line_height, root_line_height);
  1146. return CSS::Length::make_px(px);
  1147. }
  1148. return {};
  1149. }
  1150. ValueComparingNonnullRefPtr<StyleValue const> StyleValue::absolutized(CSSPixelRect const&, Gfx::FontPixelMetrics const&, CSSPixels, CSSPixels, CSSPixels, CSSPixels) const
  1151. {
  1152. return *this;
  1153. }
  1154. ValueComparingNonnullRefPtr<StyleValue const> LengthStyleValue::absolutized(CSSPixelRect const& viewport_rect, Gfx::FontPixelMetrics const& font_metrics, CSSPixels font_size, CSSPixels root_font_size, CSSPixels line_height, CSSPixels root_line_height) const
  1155. {
  1156. if (auto length = absolutized_length(m_length, viewport_rect, font_metrics, font_size, root_font_size, line_height, root_line_height); length.has_value())
  1157. return LengthStyleValue::create(length.release_value());
  1158. return *this;
  1159. }
  1160. ValueComparingNonnullRefPtr<StyleValue const> ShadowStyleValue::absolutized(CSSPixelRect const& viewport_rect, Gfx::FontPixelMetrics const& font_metrics, CSSPixels font_size, CSSPixels root_font_size, CSSPixels line_height, CSSPixels root_line_height) const
  1161. {
  1162. auto absolutized_offset_x = absolutized_length(m_properties.offset_x, viewport_rect, font_metrics, font_size, root_font_size, line_height, root_line_height).value_or(m_properties.offset_x);
  1163. auto absolutized_offset_y = absolutized_length(m_properties.offset_y, viewport_rect, font_metrics, font_size, root_font_size, line_height, root_line_height).value_or(m_properties.offset_y);
  1164. auto absolutized_blur_radius = absolutized_length(m_properties.blur_radius, viewport_rect, font_metrics, font_size, root_font_size, line_height, root_line_height).value_or(m_properties.blur_radius);
  1165. auto absolutized_spread_distance = absolutized_length(m_properties.spread_distance, viewport_rect, font_metrics, font_size, root_font_size, line_height, root_line_height).value_or(m_properties.spread_distance);
  1166. return ShadowStyleValue::create(m_properties.color, absolutized_offset_x, absolutized_offset_y, absolutized_blur_radius, absolutized_spread_distance, m_properties.placement);
  1167. }
  1168. bool CalculatedStyleValue::contains_percentage() const
  1169. {
  1170. return m_expression->contains_percentage();
  1171. }
  1172. bool CalculatedStyleValue::CalcSum::contains_percentage() const
  1173. {
  1174. if (first_calc_product->contains_percentage())
  1175. return true;
  1176. for (auto& part : zero_or_more_additional_calc_products) {
  1177. if (part->contains_percentage())
  1178. return true;
  1179. }
  1180. return false;
  1181. }
  1182. bool CalculatedStyleValue::CalcSumPartWithOperator::contains_percentage() const
  1183. {
  1184. return value->contains_percentage();
  1185. }
  1186. bool CalculatedStyleValue::CalcProduct::contains_percentage() const
  1187. {
  1188. if (first_calc_value.contains_percentage())
  1189. return true;
  1190. for (auto& part : zero_or_more_additional_calc_values) {
  1191. if (part->contains_percentage())
  1192. return true;
  1193. }
  1194. return false;
  1195. }
  1196. bool CalculatedStyleValue::CalcProductPartWithOperator::contains_percentage() const
  1197. {
  1198. return value.visit(
  1199. [](CalcValue const& value) { return value.contains_percentage(); },
  1200. [](CalcNumberValue const&) { return false; });
  1201. }
  1202. bool CalculatedStyleValue::CalcValue::contains_percentage() const
  1203. {
  1204. return value.visit(
  1205. [](Percentage const&) { return true; },
  1206. [](NonnullOwnPtr<CalcSum> const& sum) { return sum->contains_percentage(); },
  1207. [](auto const&) { return false; });
  1208. }
  1209. bool calculated_style_value_contains_percentage(CalculatedStyleValue const& value)
  1210. {
  1211. return value.contains_percentage();
  1212. }
  1213. }