ElementStyle.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315
  1. /*
  2. * This source file is part of libRocket, the HTML/CSS Interface Middleware
  3. *
  4. * For the latest information, see http://www.librocket.com
  5. *
  6. * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. *
  26. */
  27. #include "precompiled.h"
  28. #include "ElementStyle.h"
  29. #include <algorithm>
  30. #include "../../Include/Rocket/Core/ElementDocument.h"
  31. #include "../../Include/Rocket/Core/ElementUtilities.h"
  32. #include "../../Include/Rocket/Core/Log.h"
  33. #include "../../Include/Rocket/Core/Math.h"
  34. #include "../../Include/Rocket/Core/Property.h"
  35. #include "../../Include/Rocket/Core/PropertyDefinition.h"
  36. #include "../../Include/Rocket/Core/PropertyDictionary.h"
  37. #include "../../Include/Rocket/Core/StyleSheetSpecification.h"
  38. #include "../../Include/Rocket/Core/TransformPrimitive.h"
  39. #include "ElementBackground.h"
  40. #include "ElementBorder.h"
  41. #include "ElementDecoration.h"
  42. #include "ElementDefinition.h"
  43. #include "FontFaceHandle.h"
  44. namespace Rocket {
  45. namespace Core {
  46. static const Style::ComputedValues DefaultComputedValues;
  47. ElementStyle::ElementStyle(Element* _element)
  48. {
  49. local_properties = NULL;
  50. em_properties = NULL;
  51. definition = NULL;
  52. element = _element;
  53. definition_dirty = true;
  54. }
  55. ElementStyle::~ElementStyle()
  56. {
  57. if (local_properties != NULL)
  58. delete local_properties;
  59. if (em_properties != NULL)
  60. delete em_properties;
  61. if (definition != NULL)
  62. definition->RemoveReference();
  63. }
  64. // Returns the element's definition, updating if necessary.
  65. const ElementDefinition* ElementStyle::GetDefinition()
  66. {
  67. return definition;
  68. }
  69. // Returns one of this element's properties.
  70. const Property* ElementStyle::GetLocalProperty(const String& name, PropertyDictionary* local_properties, ElementDefinition* definition, const PseudoClassList& pseudo_classes)
  71. {
  72. // Check for overriding local properties.
  73. if (local_properties != NULL)
  74. {
  75. const Property* property = local_properties->GetProperty(name);
  76. if (property != NULL)
  77. return property;
  78. }
  79. // Check for a property defined in an RCSS rule.
  80. if (definition != NULL)
  81. return definition->GetProperty(name, pseudo_classes);
  82. return NULL;
  83. }
  84. // Returns one of this element's properties.
  85. const Property* ElementStyle::GetProperty(const String& name, Element* element, PropertyDictionary* local_properties, ElementDefinition* definition, const PseudoClassList& pseudo_classes)
  86. {
  87. const Property* local_property = GetLocalProperty(name, local_properties, definition, pseudo_classes);
  88. if (local_property != NULL)
  89. return local_property;
  90. // Fetch the property specification.
  91. const PropertyDefinition* property = StyleSheetSpecification::GetProperty(name);
  92. if (property == NULL)
  93. return NULL;
  94. // If we can inherit this property, return our parent's property.
  95. if (property->IsInherited())
  96. {
  97. Element* parent = element->GetParentNode();
  98. while (parent != NULL)
  99. {
  100. const Property* parent_property = parent->GetStyle()->GetLocalProperty(name);
  101. if (parent_property)
  102. return parent_property;
  103. parent = parent->GetParentNode();
  104. }
  105. }
  106. // No property available! Return the default value.
  107. return property->GetDefaultValue();
  108. }
  109. // Apply transition to relevant properties if a transition is defined on element.
  110. // Properties that are part of a transition are removed from the properties list.
  111. void ElementStyle::TransitionPropertyChanges(Element* element, PropertyNameList& properties, PropertyDictionary* local_properties, ElementDefinition* old_definition, ElementDefinition* new_definition,
  112. const PseudoClassList& pseudo_classes_before, const PseudoClassList& pseudo_classes_after)
  113. {
  114. ROCKET_ASSERT(element);
  115. if (!old_definition || !new_definition || properties.empty())
  116. return;
  117. if (const Property* transition_property = GetLocalProperty(TRANSITION, local_properties, new_definition, pseudo_classes_after))
  118. {
  119. auto transition_list = transition_property->Get<TransitionList>();
  120. if (!transition_list.none)
  121. {
  122. auto add_transition = [&](const Transition& transition) {
  123. bool transition_added = false;
  124. const Property* start_value = GetProperty(transition.name, element, local_properties, old_definition, pseudo_classes_before);
  125. const Property* target_value = GetProperty(transition.name, element, nullptr, new_definition, pseudo_classes_after);
  126. if (start_value && target_value && (*start_value != *target_value))
  127. transition_added = element->StartTransition(transition, *start_value, *target_value);
  128. return transition_added;
  129. };
  130. if (transition_list.all)
  131. {
  132. Transition transition = transition_list.transitions[0];
  133. for (auto it = properties.begin(); it != properties.end(); )
  134. {
  135. transition.name = *it;
  136. if (add_transition(transition))
  137. it = properties.erase(it);
  138. else
  139. ++it;
  140. }
  141. }
  142. else
  143. {
  144. for (auto& transition : transition_list.transitions)
  145. {
  146. if (auto it = properties.find(transition.name); it != properties.end())
  147. {
  148. if (add_transition(transition))
  149. properties.erase(it);
  150. }
  151. }
  152. }
  153. }
  154. }
  155. }
  156. void ElementStyle::UpdateDefinition()
  157. {
  158. if (definition_dirty)
  159. {
  160. definition_dirty = false;
  161. ElementDefinition* new_definition = NULL;
  162. const StyleSheet* style_sheet = GetStyleSheet();
  163. if (style_sheet != NULL)
  164. {
  165. new_definition = style_sheet->GetElementDefinition(element);
  166. }
  167. // Switch the property definitions if the definition has changed.
  168. if (new_definition != definition || new_definition == NULL)
  169. {
  170. PropertyNameList properties;
  171. if (definition != NULL)
  172. definition->GetDefinedProperties(properties, pseudo_classes);
  173. if (new_definition != NULL)
  174. new_definition->GetDefinedProperties(properties, pseudo_classes);
  175. TransitionPropertyChanges(element, properties, local_properties, definition, new_definition, pseudo_classes, pseudo_classes);
  176. if (definition != NULL)
  177. definition->RemoveReference();
  178. definition = new_definition;
  179. DirtyProperties(properties);
  180. element->GetElementDecoration()->DirtyDecorators(true);
  181. }
  182. else if (new_definition != NULL)
  183. {
  184. new_definition->RemoveReference();
  185. }
  186. }
  187. }
  188. // Sets or removes a pseudo-class on the element.
  189. void ElementStyle::SetPseudoClass(const String& pseudo_class, bool activate)
  190. {
  191. size_t num_pseudo_classes = pseudo_classes.size();
  192. auto pseudo_classes_before = pseudo_classes;
  193. if (activate)
  194. pseudo_classes.push_back(pseudo_class);
  195. else
  196. {
  197. // In case of duplicates, we do a loop here. We could do a sort and unique instead,
  198. // but that might even be slower for a small list with few duplicates, which
  199. // is probably the most common case.
  200. auto it = std::find(pseudo_classes.begin(), pseudo_classes.end(), pseudo_class);
  201. while(it != pseudo_classes.end())
  202. {
  203. pseudo_classes.erase(it);
  204. it = std::find(pseudo_classes.begin(), pseudo_classes.end(), pseudo_class);
  205. }
  206. }
  207. if (pseudo_classes.size() != num_pseudo_classes)
  208. {
  209. element->GetElementDecoration()->DirtyDecorators(false);
  210. if (definition != NULL)
  211. {
  212. PropertyNameList properties;
  213. definition->GetDefinedProperties(properties, pseudo_classes, pseudo_class);
  214. TransitionPropertyChanges(element, properties, local_properties, definition, definition, pseudo_classes_before, pseudo_classes);
  215. DirtyProperties(properties);
  216. switch (definition->GetPseudoClassVolatility(pseudo_class))
  217. {
  218. case ElementDefinition::FONT_VOLATILE:
  219. element->DirtyFont();
  220. break;
  221. case ElementDefinition::STRUCTURE_VOLATILE:
  222. DirtyChildDefinitions();
  223. break;
  224. default:
  225. break;
  226. }
  227. }
  228. }
  229. }
  230. // Checks if a specific pseudo-class has been set on the element.
  231. bool ElementStyle::IsPseudoClassSet(const String& pseudo_class) const
  232. {
  233. return (std::find(pseudo_classes.begin(), pseudo_classes.end(), pseudo_class) != pseudo_classes.end());
  234. }
  235. const PseudoClassList& ElementStyle::GetActivePseudoClasses() const
  236. {
  237. return pseudo_classes;
  238. }
  239. // Sets or removes a class on the element.
  240. void ElementStyle::SetClass(const String& class_name, bool activate)
  241. {
  242. StringList::iterator class_location = std::find(classes.begin(), classes.end(), class_name);
  243. if (activate)
  244. {
  245. if (class_location == classes.end())
  246. {
  247. classes.push_back(class_name);
  248. DirtyDefinition();
  249. }
  250. }
  251. else
  252. {
  253. if (class_location != classes.end())
  254. {
  255. classes.erase(class_location);
  256. DirtyDefinition();
  257. }
  258. }
  259. }
  260. // Checks if a class is set on the element.
  261. bool ElementStyle::IsClassSet(const String& class_name) const
  262. {
  263. return std::find(classes.begin(), classes.end(), class_name) != classes.end();
  264. }
  265. // Specifies the entire list of classes for this element. This will replace any others specified.
  266. void ElementStyle::SetClassNames(const String& class_names)
  267. {
  268. classes.clear();
  269. StringUtilities::ExpandString(classes, class_names, ' ');
  270. DirtyDefinition();
  271. }
  272. // Returns the list of classes specified for this element.
  273. String ElementStyle::GetClassNames() const
  274. {
  275. String class_names;
  276. for (size_t i = 0; i < classes.size(); i++)
  277. {
  278. if (i != 0)
  279. {
  280. class_names += " ";
  281. }
  282. class_names += classes[i];
  283. }
  284. return class_names;
  285. }
  286. // Sets a local property override on the element.
  287. bool ElementStyle::SetProperty(const String& name, const String& value)
  288. {
  289. if (local_properties == NULL)
  290. local_properties = new PropertyDictionary();
  291. if (StyleSheetSpecification::ParsePropertyDeclaration(*local_properties, name, value))
  292. {
  293. DirtyProperty(name);
  294. return true;
  295. }
  296. else
  297. {
  298. Log::Message(Log::LT_WARNING, "Syntax error parsing inline property declaration '%s: %s;'.", name.c_str(), value.c_str());
  299. return false;
  300. }
  301. }
  302. // Sets a local property override on the element to a pre-parsed value.
  303. bool ElementStyle::SetProperty(const String& name, const Property& property)
  304. {
  305. Property new_property = property;
  306. new_property.definition = StyleSheetSpecification::GetProperty(name);
  307. if (new_property.definition == NULL)
  308. return false;
  309. if (local_properties == NULL)
  310. local_properties = new PropertyDictionary();
  311. local_properties->SetProperty(name, new_property);
  312. DirtyProperty(name);
  313. return true;
  314. }
  315. // Removes a local property override on the element.
  316. void ElementStyle::RemoveProperty(const String& name)
  317. {
  318. if (local_properties == NULL)
  319. return;
  320. if (local_properties->GetProperty(name) != NULL)
  321. {
  322. local_properties->RemoveProperty(name);
  323. DirtyProperty(name);
  324. }
  325. }
  326. // Returns one of this element's properties.
  327. const Property* ElementStyle::GetProperty(const String& name)
  328. {
  329. return GetProperty(name, element, local_properties, definition, pseudo_classes);
  330. }
  331. // Returns one of this element's properties.
  332. const Property* ElementStyle::GetLocalProperty(const String& name)
  333. {
  334. return GetLocalProperty(name, local_properties, definition, pseudo_classes);
  335. }
  336. const PropertyMap * ElementStyle::GetLocalProperties() const
  337. {
  338. if (local_properties)
  339. return &local_properties->GetProperties();
  340. return NULL;
  341. }
  342. float ElementStyle::ResolveLength(const Property * property)
  343. {
  344. if (!property)
  345. {
  346. ROCKET_ERROR;
  347. return 0.0f;
  348. }
  349. if (!(property->unit & Property::LENGTH))
  350. {
  351. ROCKET_ERRORMSG("Trying to resolve length on a non-length property.");
  352. return 0.0f;
  353. }
  354. switch (property->unit)
  355. {
  356. case Property::NUMBER:
  357. case Property::PX:
  358. return property->value.Get< float >();
  359. case Property::EM:
  360. return property->value.Get< float >()* element->GetComputedValues().font_size;
  361. case Property::REM:
  362. return property->value.Get< float >()* element->GetOwnerDocument()->GetComputedValues().font_size;
  363. case Property::DP:
  364. return property->value.Get< float >() * ElementUtilities::GetDensityIndependentPixelRatio(element);
  365. }
  366. // Values based on pixels-per-inch.
  367. if (property->unit & Property::PPI_UNIT)
  368. {
  369. float inch = property->value.Get< float >() * element->GetRenderInterface()->GetPixelsPerInch();
  370. switch (property->unit)
  371. {
  372. case Property::INCH: // inch
  373. return inch;
  374. case Property::CM: // centimeter
  375. return inch * (1.0f / 2.54f);
  376. case Property::MM: // millimeter
  377. return inch * (1.0f / 25.4f);
  378. case Property::PT: // point
  379. return inch * (1.0f / 72.0f);
  380. case Property::PC: // pica
  381. return inch * (1.0f / 6.0f);
  382. }
  383. }
  384. // We're not a numeric property; return 0.
  385. return 0.0f;
  386. }
  387. float ElementStyle::ResolveAngle(const Property * property)
  388. {
  389. switch (property->unit)
  390. {
  391. case Property::NUMBER:
  392. case Property::DEG:
  393. return Math::DegreesToRadians(property->value.Get< float >());
  394. case Property::RAD:
  395. return property->value.Get< float >();
  396. case Property::PERCENT:
  397. return property->value.Get< float >() * 0.01f * 2.0f * Math::ROCKET_PI;
  398. }
  399. ROCKET_ERRORMSG("Trying to resolve angle on a non-angle property.");
  400. return 0.0f;
  401. }
  402. float ElementStyle::ResolveNumericProperty(const Property * property, RelativeTarget relative_target)
  403. {
  404. // There is an exception on font-size properties, as 'em' units here refer to parent font size instead
  405. if ((property->unit & Property::LENGTH) && !(property->unit == Property::EM && relative_target == RelativeTarget::ParentFontSize))
  406. {
  407. return ResolveLength(property);
  408. }
  409. float base_value = 0.0f;
  410. switch (relative_target)
  411. {
  412. case RelativeTarget::None:
  413. base_value = 1.0f;
  414. break;
  415. case RelativeTarget::ContainingBlockWidth:
  416. base_value = element->GetContainingBlock().x;
  417. break;
  418. case RelativeTarget::ContainingBlockHeight:
  419. base_value = element->GetContainingBlock().y;
  420. break;
  421. case RelativeTarget::FontSize:
  422. base_value = element->GetComputedValues().font_size;
  423. break;
  424. case RelativeTarget::ParentFontSize:
  425. base_value = element->GetParentNode()->GetComputedValues().font_size;
  426. break;
  427. case RelativeTarget::LineHeight:
  428. base_value = element->GetLineHeight();
  429. break;
  430. default:
  431. break;
  432. }
  433. float scale_value = 0.0f;
  434. switch (property->unit)
  435. {
  436. case Property::EM:
  437. case Property::NUMBER:
  438. scale_value = property->value.Get< float >();
  439. break;
  440. case Property::PERCENT:
  441. scale_value = property->value.Get< float >() * 0.01f;
  442. break;
  443. }
  444. return base_value * scale_value;
  445. }
  446. // Resolves one of this element's properties.
  447. float ElementStyle::ResolveProperty(const Property* property, float base_value)
  448. {
  449. if (!property)
  450. {
  451. ROCKET_ERROR;
  452. return 0.0f;
  453. }
  454. switch (property->unit)
  455. {
  456. case Property::NUMBER:
  457. case Property::PX:
  458. case Property::RAD:
  459. return property->value.Get< float >();
  460. case Property::PERCENT:
  461. return base_value * property->value.Get< float >() * 0.01f;
  462. case Property::EM:
  463. return property->value.Get< float >() * element->GetComputedValues().font_size;
  464. case Property::REM:
  465. return property->value.Get< float >() * element->GetOwnerDocument()->GetComputedValues().font_size;
  466. case Property::DP:
  467. return property->value.Get< float >() * ElementUtilities::GetDensityIndependentPixelRatio(element);
  468. case Property::DEG:
  469. return Math::DegreesToRadians(property->value.Get< float >());
  470. }
  471. // Values based on pixels-per-inch.
  472. if (property->unit & Property::PPI_UNIT)
  473. {
  474. float inch = property->value.Get< float >() * element->GetRenderInterface()->GetPixelsPerInch();
  475. switch (property->unit)
  476. {
  477. case Property::INCH: // inch
  478. return inch;
  479. case Property::CM: // centimeter
  480. return inch * (1.0f / 2.54f);
  481. case Property::MM: // millimeter
  482. return inch * (1.0f / 25.4f);
  483. case Property::PT: // point
  484. return inch * (1.0f / 72.0f);
  485. case Property::PC: // pica
  486. return inch * (1.0f / 6.0f);
  487. }
  488. }
  489. // We're not a numeric property; return 0.
  490. return 0.0f;
  491. }
  492. // Iterates over the properties defined on the element.
  493. bool ElementStyle::IterateProperties(int& index, String& name, const Property*& property, const PseudoClassList** property_pseudo_classes)
  494. {
  495. // First check for locally defined properties.
  496. if (local_properties != NULL)
  497. {
  498. if (index < local_properties->GetNumProperties())
  499. {
  500. PropertyMap::const_iterator i = local_properties->GetProperties().begin();
  501. for (int count = 0; count < index; ++count)
  502. ++i;
  503. name = (*i).first;
  504. property = &((*i).second);
  505. if (property_pseudo_classes)
  506. * property_pseudo_classes = nullptr;
  507. ++index;
  508. return true;
  509. }
  510. }
  511. const ElementDefinition* definition = GetDefinition();
  512. if (definition != NULL)
  513. {
  514. int index_offset = 0;
  515. if (local_properties != NULL)
  516. index_offset = local_properties->GetNumProperties();
  517. // Offset the index to be relative to the definition before we start indexing. When we do get a property back,
  518. // check that it hasn't been overridden by the element's local properties; if so, continue on to the next one.
  519. index -= index_offset;
  520. while (definition->IterateProperties(index, pseudo_classes, name, property, property_pseudo_classes))
  521. {
  522. if (local_properties == NULL ||
  523. local_properties->GetProperty(name) == NULL)
  524. {
  525. index += index_offset;
  526. return true;
  527. }
  528. }
  529. return false;
  530. }
  531. return false;
  532. }
  533. // Returns the active style sheet for this element. This may be NULL.
  534. StyleSheet* ElementStyle::GetStyleSheet() const
  535. {
  536. ElementDocument* document = element->GetOwnerDocument();
  537. if (document != NULL)
  538. return document->GetStyleSheet();
  539. return NULL;
  540. }
  541. void ElementStyle::DirtyDefinition()
  542. {
  543. definition_dirty = true;
  544. DirtyChildDefinitions();
  545. }
  546. void ElementStyle::DirtyChildDefinitions()
  547. {
  548. for (int i = 0; i < element->GetNumChildren(true); i++)
  549. element->GetChild(i)->GetStyle()->DirtyDefinition();
  550. }
  551. // Dirties every property.
  552. void ElementStyle::DirtyProperties()
  553. {
  554. const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
  555. DirtyProperties(properties);
  556. }
  557. // Dirties em-relative properties.
  558. void ElementStyle::DirtyEmProperties()
  559. {
  560. if (!em_properties)
  561. {
  562. // Check if any of these are currently em-relative. If so, dirty them.
  563. em_properties = new PropertyNameList;
  564. for (auto& property : StyleSheetSpecification::GetRegisteredProperties())
  565. {
  566. // Skip font-size; this is relative to our parent's em, not ours.
  567. if (property == FONT_SIZE)
  568. continue;
  569. // Get this property from this element. If this is em-relative, then add it to the list to
  570. // dirty.
  571. if (element->GetProperty(property)->unit == Property::EM)
  572. em_properties->insert(property);
  573. }
  574. }
  575. if (!em_properties->empty())
  576. DirtyProperties(*em_properties, false);
  577. // Now dirty all of our descendant's font-size properties that are relative to ems.
  578. int num_children = element->GetNumChildren(true);
  579. for (int i = 0; i < num_children; ++i)
  580. element->GetChild(i)->GetStyle()->DirtyInheritedEmProperties();
  581. }
  582. // Dirties font-size on child elements if appropriate.
  583. void ElementStyle::DirtyInheritedEmProperties()
  584. {
  585. const Property* font_size = element->GetLocalProperty(FONT_SIZE);
  586. if (font_size == NULL)
  587. {
  588. int num_children = element->GetNumChildren(true);
  589. for (int i = 0; i < num_children; ++i)
  590. element->GetChild(i)->GetStyle()->DirtyInheritedEmProperties();
  591. }
  592. else
  593. {
  594. if (font_size->unit & Property::RELATIVE_UNIT)
  595. DirtyProperty(FONT_SIZE);
  596. }
  597. }
  598. // Dirties rem properties.
  599. void ElementStyle::DirtyRemProperties()
  600. {
  601. const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
  602. PropertyNameList rem_properties;
  603. // Dirty all the properties of this element that use the rem unit.
  604. for (PropertyNameList::const_iterator list_iterator = properties.begin(); list_iterator != properties.end(); ++list_iterator)
  605. {
  606. if (element->GetProperty(*list_iterator)->unit == Property::REM)
  607. rem_properties.insert(*list_iterator);
  608. }
  609. if (!rem_properties.empty())
  610. DirtyProperties(rem_properties, false);
  611. // Now dirty all of our descendant's properties that use the rem unit.
  612. int num_children = element->GetNumChildren(true);
  613. for (int i = 0; i < num_children; ++i)
  614. element->GetChild(i)->GetStyle()->DirtyRemProperties();
  615. }
  616. void ElementStyle::DirtyDpProperties()
  617. {
  618. const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
  619. PropertyNameList dp_properties;
  620. // Dirty all the properties of this element that use the dp unit.
  621. for (PropertyNameList::const_iterator list_iterator = properties.begin(); list_iterator != properties.end(); ++list_iterator)
  622. {
  623. if (element->GetProperty(*list_iterator)->unit == Property::DP)
  624. dp_properties.insert(*list_iterator);
  625. }
  626. if (!dp_properties.empty())
  627. DirtyProperties(dp_properties, false);
  628. // Now dirty all of our descendant's properties that use the dp unit.
  629. int num_children = element->GetNumChildren(true);
  630. for (int i = 0; i < num_children; ++i)
  631. element->GetChild(i)->GetStyle()->DirtyDpProperties();
  632. }
  633. // Sets a single property as dirty.
  634. void ElementStyle::DirtyProperty(const String& property)
  635. {
  636. PropertyNameList properties;
  637. properties.insert(String(property));
  638. DirtyProperties(properties);
  639. }
  640. // Sets a list of properties as dirty.
  641. void ElementStyle::DirtyProperties(const PropertyNameList& properties, bool clear_em_properties)
  642. {
  643. if (properties.empty())
  644. return;
  645. bool all_inherited_dirty =
  646. &properties == &StyleSheetSpecification::GetRegisteredProperties() ||
  647. StyleSheetSpecification::GetRegisteredProperties() == properties ||
  648. StyleSheetSpecification::GetRegisteredInheritedProperties() == properties;
  649. if (all_inherited_dirty)
  650. {
  651. const PropertyNameList &all_inherited_properties = StyleSheetSpecification::GetRegisteredInheritedProperties();
  652. for (int i = 0; i < element->GetNumChildren(true); i++)
  653. element->GetChild(i)->GetStyle()->DirtyInheritedProperties(all_inherited_properties);
  654. }
  655. else
  656. {
  657. PropertyNameList inherited_properties;
  658. for (PropertyNameList::const_iterator i = properties.begin(); i != properties.end(); ++i)
  659. {
  660. // If this property is an inherited property, then push it into the list to be passed onto our children.
  661. const PropertyDefinition* property = StyleSheetSpecification::GetProperty(*i);
  662. if (property != NULL &&
  663. property->IsInherited())
  664. inherited_properties.insert(*i);
  665. }
  666. // Pass the list of those properties that are inherited onto our children.
  667. if (!inherited_properties.empty())
  668. {
  669. for (int i = 0; i < element->GetNumChildren(true); i++)
  670. element->GetChild(i)->GetStyle()->DirtyInheritedProperties(inherited_properties);
  671. }
  672. }
  673. // clear the list of EM-properties, we will refill it in DirtyEmProperties
  674. if (clear_em_properties && em_properties != NULL)
  675. {
  676. delete em_properties;
  677. em_properties = NULL;
  678. }
  679. // And send the event.
  680. element->DirtyProperties(properties);
  681. }
  682. // Sets a list of our potentially inherited properties as dirtied by an ancestor.
  683. void ElementStyle::DirtyInheritedProperties(const PropertyNameList& properties)
  684. {
  685. bool clear_em_properties = em_properties != NULL;
  686. PropertyNameList inherited_properties;
  687. for (PropertyNameList::const_iterator i = properties.begin(); i != properties.end(); ++i)
  688. {
  689. const Property *property = GetLocalProperty((*i));
  690. if (property == NULL)
  691. {
  692. inherited_properties.insert(*i);
  693. if (!clear_em_properties && em_properties != NULL && em_properties->find((*i)) != em_properties->end()) {
  694. clear_em_properties = true;
  695. }
  696. }
  697. }
  698. if (inherited_properties.empty())
  699. return;
  700. // clear the list of EM-properties, we will refill it in DirtyEmProperties
  701. if (clear_em_properties && em_properties != NULL)
  702. {
  703. delete em_properties;
  704. em_properties = NULL;
  705. }
  706. // Pass the list of those properties that this element doesn't override onto our children.
  707. for (int i = 0; i < element->GetNumChildren(true); i++)
  708. element->GetChild(i)->GetStyle()->DirtyInheritedProperties(inherited_properties);
  709. element->DirtyProperties(properties);
  710. }
  711. static float ComputeLength(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  712. {
  713. // Note that percentages are not lengths! They have to be resolved elsewhere.
  714. if (!property)
  715. {
  716. ROCKET_ERROR;
  717. return 0.0f;
  718. }
  719. float value = property->value.Get<float>();
  720. switch (property->unit)
  721. {
  722. case Property::NUMBER:
  723. case Property::PX:
  724. case Property::RAD:
  725. return value;
  726. case Property::EM:
  727. return value * font_size;
  728. case Property::REM:
  729. return value * document_font_size;
  730. case Property::DP:
  731. return value * dp_ratio;
  732. case Property::DEG:
  733. return Math::DegreesToRadians(value);
  734. default:
  735. break;
  736. }
  737. // Values based on pixels-per-inch.
  738. if (property->unit & Property::PPI_UNIT)
  739. {
  740. float inch = value * pixels_per_inch;
  741. switch (property->unit)
  742. {
  743. case Property::INCH: // inch
  744. return inch;
  745. case Property::CM: // centimeter
  746. return inch * (1.0f / 2.54f);
  747. case Property::MM: // millimeter
  748. return inch * (1.0f / 25.4f);
  749. case Property::PT: // point
  750. return inch * (1.0f / 72.0f);
  751. case Property::PC: // pica
  752. return inch * (1.0f / 6.0f);
  753. default:
  754. break;
  755. }
  756. }
  757. // We're not a numeric property; return 0.
  758. return 0.0f;
  759. }
  760. static float ComputeAbsoluteLength(const Property& property, float dp_ratio, float pixels_per_inch)
  761. {
  762. ROCKET_ASSERT(property.unit & Property::ABSOLUTE_LENGTH);
  763. switch (property.unit)
  764. {
  765. case Property::PX:
  766. return property.value.Get< float >();
  767. case Property::DP:
  768. return property.value.Get< float >()* dp_ratio;
  769. default:
  770. // Values based on pixels-per-inch.
  771. if (property.unit & Property::PPI_UNIT)
  772. {
  773. float inch = property.value.Get< float >() * pixels_per_inch;
  774. switch (property.unit)
  775. {
  776. case Property::INCH: // inch
  777. return inch;
  778. case Property::CM: // centimeter
  779. return inch * (1.0f / 2.54f);
  780. case Property::MM: // millimeter
  781. return inch * (1.0f / 25.4f);
  782. case Property::PT: // point
  783. return inch * (1.0f / 72.0f);
  784. case Property::PC: // pica
  785. return inch * (1.0f / 6.0f);
  786. }
  787. }
  788. }
  789. ROCKET_ERROR;
  790. return 0.0f;
  791. }
  792. // Resolves one of this element's properties.
  793. static float ComputeFontsize(const Property& property, const Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, float dp_ratio, float pixels_per_inch)
  794. {
  795. // The calculated value of the font-size property is inherited, so we need to check if this
  796. // is an inherited property. If so, then we return our parent's font size instead.
  797. if (property.unit & Property::RELATIVE_UNIT)
  798. {
  799. float multiplier = 1.0f;
  800. switch (property.unit)
  801. {
  802. case Property::PERCENT:
  803. multiplier = 0.01f;
  804. [[fallthrough]];
  805. case Property::EM:
  806. if (!parent_values)
  807. return 0;
  808. return property.value.Get< float >() * multiplier * parent_values->font_size;
  809. case Property::REM:
  810. if (!document_values)
  811. return 0;
  812. // If the current element is a document, the rem unit is relative to the default size
  813. if(&values == document_values)
  814. return property.value.Get< float >() * DefaultComputedValues.font_size;
  815. // Otherwise it is relative to the document font size
  816. return property.value.Get< float >() * document_values->font_size;
  817. default:
  818. ROCKET_ERRORMSG("A relative unit must be percentage, em or rem.");
  819. }
  820. }
  821. return ComputeAbsoluteLength(property, dp_ratio, pixels_per_inch);
  822. }
  823. static inline Style::Clip ComputeClip(const Property* property)
  824. {
  825. int value = property->Get<int>();
  826. if (property->unit == Property::KEYWORD)
  827. return Style::Clip(value == CLIP_NONE ? Style::Clip::None : Style::Clip::Auto);
  828. else if (property->unit == Property::NUMBER)
  829. return Style::Clip(Style::Clip::Number, value);
  830. ROCKET_ERRORMSG("Invalid clip type");
  831. return Style::Clip();
  832. }
  833. static inline Style::LineHeight ComputeLineHeight(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  834. {
  835. if (property->unit & Property::LENGTH)
  836. {
  837. float value = ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch);
  838. return Style::LineHeight(value, Style::LineHeight::Length, value);
  839. }
  840. float scale_factor = 1.0f;
  841. switch (property->unit)
  842. {
  843. case Property::NUMBER:
  844. scale_factor = property->value.Get< float >();
  845. break;
  846. case Property::PERCENT:
  847. scale_factor = property->value.Get< float >() * 0.01f;
  848. break;
  849. default:
  850. ROCKET_ERRORMSG("Invalid unit for line-height");
  851. }
  852. float value = font_size * scale_factor;
  853. return Style::LineHeight(value, Style::LineHeight::Number, scale_factor);
  854. }
  855. static inline Style::VerticalAlign ComputeVerticalAlign(const Property* property, float line_height, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  856. {
  857. if (property->unit & Property::LENGTH)
  858. {
  859. float value = ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch);
  860. return Style::VerticalAlign(value);
  861. }
  862. else if (property->unit & Property::PERCENT)
  863. {
  864. return Style::VerticalAlign(property->Get<float>() * line_height);
  865. }
  866. ROCKET_ASSERT(property->unit & Property::KEYWORD);
  867. return Style::VerticalAlign((Style::VerticalAlign::Type)property->Get<int>());
  868. }
  869. static inline Style::LengthPercentage ComputeLengthPercentage(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  870. {
  871. using namespace Style;
  872. if (property->unit & Property::PERCENT)
  873. return LengthPercentage(LengthPercentage::Percentage, property->Get<float>());
  874. return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch));
  875. }
  876. static inline Style::LengthPercentageAuto ComputeLengthPercentageAuto(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  877. {
  878. using namespace Style;
  879. // Assuming here that 'auto' is the only possible keyword
  880. if (property->unit & Property::PERCENT)
  881. return LengthPercentageAuto(LengthPercentageAuto::Percentage, property->Get<float>());
  882. else if (property->unit & Property::KEYWORD)
  883. return LengthPercentageAuto(LengthPercentageAuto::Auto);
  884. return LengthPercentageAuto(LengthPercentageAuto::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch));
  885. }
  886. static inline Style::LengthPercentage ComputeOrigin(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  887. {
  888. using namespace Style;
  889. static_assert((int)OriginX::Left == (int)OriginY::Top && (int)OriginX::Center == (int)OriginY::Center && (int)OriginX::Right == (int)OriginY::Bottom, "");
  890. if (property->unit & Property::KEYWORD)
  891. {
  892. float percent = 0.0f;
  893. OriginX origin = (OriginX)property->Get<int>();
  894. switch (origin)
  895. {
  896. case OriginX::Left: percent = 0.0f; break;
  897. case OriginX::Center: percent = 50.0f; break;
  898. case OriginX::Right: percent = 100.f; break;
  899. }
  900. return LengthPercentage(LengthPercentage::Percentage, percent);
  901. }
  902. else if (property->unit & Property::PERCENT)
  903. return LengthPercentage(LengthPercentage::Percentage, property->Get<float>());
  904. return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch));
  905. }
  906. // Must be called in correct order, from document root to children elements.
  907. void ElementStyle::ComputeValues(Style::ComputedValues& values, const Style::ComputedValues* parent_values, const Style::ComputedValues* document_values, bool values_are_defaulted, float dp_ratio, float pixels_per_inch)
  908. {
  909. // Generally, this is how it works (for now, we can probably be smarter about this):
  910. // 1. Assign default values (clears any newly dirtied properties)
  911. // 2. Inherit inheritable values from parent
  912. // 3. Assign any local properties (from inline style or stylesheet)
  913. // The next flag is just a small optimization, if the element was just created we don't need to copy all the default values.
  914. if (!values_are_defaulted)
  915. {
  916. values = DefaultComputedValues;
  917. }
  918. // Always do font-size first if dirty, because of em-relative values
  919. if (auto p = GetLocalProperty(FONT_SIZE))
  920. values.font_size = ComputeFontsize(*p, values, parent_values, document_values, dp_ratio, pixels_per_inch);
  921. else if (parent_values)
  922. values.font_size = parent_values->font_size;
  923. const float font_size = values.font_size;
  924. const float document_font_size = (document_values ? document_values->font_size : DefaultComputedValues.font_size);
  925. // Since vertical-align depends on line-height we compute this before iteration
  926. if (auto p = GetLocalProperty(LINE_HEIGHT))
  927. {
  928. values.line_height = ComputeLineHeight(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  929. }
  930. else if (parent_values)
  931. {
  932. // Line height has a special inheritance case for numbers/percent: they inherit them directly instead of computed length, but for lengths, they inherit the length.
  933. // See CSS specs for details. Percent is already converted to number.
  934. if (parent_values->line_height.inherit_type == Style::LineHeight::Number)
  935. values.line_height = Style::LineHeight(font_size * parent_values->line_height.inherit_value, Style::LineHeight::Number, parent_values->line_height.inherit_value);
  936. else
  937. values.line_height = parent_values->line_height;
  938. }
  939. if (parent_values)
  940. {
  941. // Inherited properties are copied here, but may be overwritten below by locally defined properties
  942. // Line-height and font-size are computed above
  943. values.clip = parent_values->clip;
  944. values.color = parent_values->color;
  945. values.opacity = parent_values->opacity;
  946. values.font_family = parent_values->font_family;
  947. values.font_charset = parent_values->font_charset;
  948. values.font_style = parent_values->font_style;
  949. values.font_weight = parent_values->font_weight;
  950. values.text_align = parent_values->text_align;
  951. values.text_decoration = parent_values->text_decoration;
  952. values.text_transform = parent_values->text_transform;
  953. values.white_space = parent_values->white_space;
  954. values.cursor = parent_values->cursor;
  955. values.focus = parent_values->focus;
  956. values.pointer_events = parent_values->pointer_events;
  957. }
  958. int index = 0;
  959. String name;
  960. const Property* p = nullptr;
  961. while (IterateProperties(index, name, p))
  962. {
  963. using namespace Style;
  964. // @performance: Can use a switch-case with constexpr hashing function
  965. // Or even better: a PropertyId enum, but the problem is custom properties such as decorators. We may want to redo the decleration of these perhaps...
  966. // @performance: Compare to the list of actually changed properties, skip if not inside it
  967. if (name == MARGIN_TOP)
  968. values.margin_top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  969. else if (name == MARGIN_RIGHT)
  970. values.margin_right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  971. else if (name == MARGIN_BOTTOM)
  972. values.margin_bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  973. else if (name == MARGIN_LEFT)
  974. values.margin_left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  975. else if (name == PADDING_TOP)
  976. values.padding_top = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  977. else if (name == PADDING_RIGHT)
  978. values.padding_right = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  979. else if (name == PADDING_BOTTOM)
  980. values.padding_bottom = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  981. else if (name == PADDING_LEFT)
  982. values.padding_left = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  983. else if (name == BORDER_TOP_WIDTH)
  984. values.border_top_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  985. else if (name == BORDER_RIGHT_WIDTH)
  986. values.border_right_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  987. else if (name == BORDER_BOTTOM_WIDTH)
  988. values.border_bottom_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  989. else if (name == BORDER_LEFT_WIDTH)
  990. values.border_left_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  991. else if (name == BORDER_TOP_COLOR)
  992. values.border_top_color = p->Get<Colourb>();
  993. else if (name == BORDER_RIGHT_COLOR)
  994. values.border_right_color = p->Get<Colourb>();
  995. else if (name == BORDER_BOTTOM_COLOR)
  996. values.border_bottom_color = p->Get<Colourb>();
  997. else if (name == BORDER_LEFT_COLOR)
  998. values.border_left_color = p->Get<Colourb>();
  999. else if (name == DISPLAY)
  1000. values.display = (Display)p->Get<int>();
  1001. else if (name == POSITION)
  1002. values.position = (Position)p->Get<int>();
  1003. else if (name == TOP)
  1004. values.top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1005. else if (name == RIGHT)
  1006. values.right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1007. else if (name == BOTTOM)
  1008. values.bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1009. else if (name == LEFT)
  1010. values.left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1011. else if (name == FLOAT)
  1012. values.float_ = (Float)p->Get<int>();
  1013. else if (name == CLEAR)
  1014. values.clear = (Clear)p->Get<int>();
  1015. else if (name == Z_INDEX)
  1016. values.z_index = (p->unit == Property::KEYWORD ? ZIndex(ZIndex::Auto) : ZIndex(ZIndex::Number, p->Get<float>()));
  1017. else if (name == WIDTH)
  1018. values.width = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1019. else if (name == MIN_WIDTH)
  1020. values.min_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1021. else if (name == MAX_WIDTH)
  1022. values.max_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1023. else if (name == HEIGHT)
  1024. values.height = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1025. else if (name == MIN_HEIGHT)
  1026. values.min_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1027. else if (name == MAX_HEIGHT)
  1028. values.max_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1029. // (Line-height computed above)
  1030. else if (name == VERTICAL_ALIGN)
  1031. values.vertical_align = ComputeVerticalAlign(p, values.line_height.value, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1032. else if (name == OVERFLOW_X)
  1033. values.overflow_x = (Overflow)p->Get< int >();
  1034. else if (name == OVERFLOW_Y)
  1035. values.overflow_y = (Overflow)p->Get< int >();
  1036. else if (name == CLIP)
  1037. values.clip = ComputeClip(p);
  1038. else if (name == VISIBILITY)
  1039. values.visibility = (Visibility)p->Get< int >();
  1040. else if (name == BACKGROUND_COLOR)
  1041. values.background_color = p->Get<Colourb>();
  1042. else if (name == COLOR)
  1043. values.color = p->Get<Colourb>();
  1044. else if (name == IMAGE_COLOR)
  1045. values.image_color = p->Get<Colourb>();
  1046. else if (name == OPACITY)
  1047. values.opacity = p->Get<float>();
  1048. else if (name == FONT_FAMILY)
  1049. values.font_family = ToLower(p->Get<String>());
  1050. else if (name == FONT_CHARSET)
  1051. values.font_charset = p->Get<String>();
  1052. else if (name == FONT_STYLE)
  1053. values.font_style = (FontStyle)p->Get< int >();
  1054. else if (name == FONT_WEIGHT)
  1055. values.font_weight = (FontWeight)p->Get< int >();
  1056. // (font-size computed above)
  1057. else if (name == TEXT_ALIGN)
  1058. values.text_align = (TextAlign)p->Get< int >();
  1059. else if (name == TEXT_DECORATION)
  1060. values.text_decoration = (TextDecoration)p->Get< int >();
  1061. else if (name == TEXT_TRANSFORM)
  1062. values.text_transform = (TextTransform)p->Get< int >();
  1063. else if (name == WHITE_SPACE)
  1064. values.white_space = (WhiteSpace)p->Get< int >();
  1065. else if (name == CURSOR)
  1066. values.cursor = p->Get< String >();
  1067. else if (name == DRAG)
  1068. values.drag = (Drag)p->Get< int >();
  1069. else if (name == TAB_INDEX)
  1070. values.tab_index = (TabIndex)p->Get< int >();
  1071. else if (name == FOCUS)
  1072. values.focus = (Focus)p->Get<int>();
  1073. else if (name == SCROLLBAR_MARGIN)
  1074. values.scrollbar_margin = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1075. else if (name == POINTER_EVENTS)
  1076. values.pointer_events = (PointerEvents)p->Get<int>();
  1077. else if (name == PERSPECTIVE)
  1078. values.perspective = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1079. else if (name == PERSPECTIVE_ORIGIN_X)
  1080. values.perspective_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1081. else if (name == PERSPECTIVE_ORIGIN_Y)
  1082. values.perspective_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1083. else if (name == TRANSFORM)
  1084. values.transform = p->Get<TransformRef>();
  1085. else if(name == TRANSFORM_ORIGIN_X)
  1086. values.transform_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1087. else if (name == TRANSFORM_ORIGIN_Y)
  1088. values.transform_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1089. else if (name == TRANSFORM_ORIGIN_Z)
  1090. values.transform_origin_z = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1091. else if (name == TRANSITION)
  1092. values.transition = p->Get<TransitionList>();
  1093. else if (name == ANIMATION)
  1094. values.animation = p->Get<AnimationList>();
  1095. }
  1096. }
  1097. }
  1098. }