ElementStyle.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383
  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 String& property_name, const Property * property)
  403. {
  404. if ((property->unit & Property::LENGTH) && !(property->unit == Property::EM && property_name == FONT_SIZE))
  405. {
  406. return ResolveLength(property);
  407. }
  408. auto definition = property->definition;
  409. if (!definition) definition = StyleSheetSpecification::GetProperty(property_name);
  410. if (!definition) return 0.0f;
  411. auto relative_target = definition->GetRelativeTarget();
  412. return ResolveNumericProperty(property, relative_target);
  413. }
  414. float ElementStyle::ResolveNumericProperty(const Property * property, RelativeTarget relative_target)
  415. {
  416. // There is an exception on font-size properties, as 'em' units here refer to parent font size instead
  417. if ((property->unit & Property::LENGTH) && !(property->unit == Property::EM && relative_target == RelativeTarget::ParentFontSize))
  418. {
  419. return ResolveLength(property);
  420. }
  421. float base_value = 0.0f;
  422. switch (relative_target)
  423. {
  424. case RelativeTarget::None:
  425. base_value = 1.0f;
  426. break;
  427. case RelativeTarget::ContainingBlockWidth:
  428. base_value = element->GetContainingBlock().x;
  429. break;
  430. case RelativeTarget::ContainingBlockHeight:
  431. base_value = element->GetContainingBlock().y;
  432. break;
  433. case RelativeTarget::FontSize:
  434. base_value = element->GetComputedValues().font_size;
  435. break;
  436. case RelativeTarget::ParentFontSize:
  437. base_value = element->GetParentNode()->GetComputedValues().font_size;
  438. break;
  439. case RelativeTarget::LineHeight:
  440. base_value = element->GetLineHeight();
  441. break;
  442. default:
  443. break;
  444. }
  445. float scale_value = 0.0f;
  446. switch (property->unit)
  447. {
  448. case Property::EM:
  449. case Property::NUMBER:
  450. scale_value = property->value.Get< float >();
  451. break;
  452. case Property::PERCENT:
  453. scale_value = property->value.Get< float >() * 0.01f;
  454. break;
  455. }
  456. return base_value * scale_value;
  457. }
  458. // Resolves one of this element's properties.
  459. float ElementStyle::ResolveProperty(const Property* property, float base_value)
  460. {
  461. if (!property)
  462. {
  463. ROCKET_ERROR;
  464. return 0.0f;
  465. }
  466. switch (property->unit)
  467. {
  468. case Property::NUMBER:
  469. case Property::PX:
  470. case Property::RAD:
  471. return property->value.Get< float >();
  472. case Property::PERCENT:
  473. return base_value * property->value.Get< float >() * 0.01f;
  474. case Property::EM:
  475. return property->value.Get< float >() * element->GetComputedValues().font_size;
  476. case Property::REM:
  477. return property->value.Get< float >() * element->GetOwnerDocument()->GetComputedValues().font_size;
  478. case Property::DP:
  479. return property->value.Get< float >() * ElementUtilities::GetDensityIndependentPixelRatio(element);
  480. case Property::DEG:
  481. return Math::DegreesToRadians(property->value.Get< float >());
  482. }
  483. // Values based on pixels-per-inch.
  484. if (property->unit & Property::PPI_UNIT)
  485. {
  486. float inch = property->value.Get< float >() * element->GetRenderInterface()->GetPixelsPerInch();
  487. switch (property->unit)
  488. {
  489. case Property::INCH: // inch
  490. return inch;
  491. case Property::CM: // centimeter
  492. return inch * (1.0f / 2.54f);
  493. case Property::MM: // millimeter
  494. return inch * (1.0f / 25.4f);
  495. case Property::PT: // point
  496. return inch * (1.0f / 72.0f);
  497. case Property::PC: // pica
  498. return inch * (1.0f / 6.0f);
  499. }
  500. }
  501. // We're not a numeric property; return 0.
  502. return 0.0f;
  503. }
  504. // Resolves one of this element's properties.
  505. float ElementStyle::ResolveProperty(const String& name, float base_value)
  506. {
  507. const Property* property = GetProperty(name);
  508. if (!property)
  509. {
  510. ROCKET_ERROR;
  511. return 0.0f;
  512. }
  513. // The calculated value of the font-size property is inherited, so we need to check if this
  514. // is an inherited property. If so, then we return our parent's font size instead.
  515. if (name == FONT_SIZE && property->unit & Property::RELATIVE_UNIT)
  516. {
  517. // If the rem unit is used, the font-size is inherited directly from the document,
  518. // otherwise we use the parent's font size.
  519. if (property->unit & Property::REM)
  520. {
  521. Rocket::Core::ElementDocument* owner_document = element->GetOwnerDocument();
  522. if (owner_document == NULL)
  523. return 0;
  524. base_value = owner_document->ResolveProperty(FONT_SIZE, 0);
  525. }
  526. else
  527. {
  528. Rocket::Core::Element* parent = element->GetParentNode();
  529. if (parent == NULL)
  530. return 0;
  531. if (GetLocalProperty(FONT_SIZE) == NULL)
  532. return parent->ResolveProperty(FONT_SIZE, 0);
  533. // The base value for font size is always the height of *this* element's parent's font.
  534. base_value = parent->ResolveProperty(FONT_SIZE, 0);
  535. }
  536. switch (property->unit)
  537. {
  538. case Property::PERCENT:
  539. return base_value * property->value.Get< float >() * 0.01f;
  540. case Property::EM:
  541. return property->value.Get< float >() * base_value;
  542. case Property::REM:
  543. // If an rem-relative font size is specified, it is expressed relative to the document's
  544. // font height.
  545. return property->value.Get< float >() * element->GetOwnerDocument()->GetComputedValues().font_size;
  546. }
  547. }
  548. return ResolveProperty(property, base_value);
  549. }
  550. // Iterates over the properties defined on the element.
  551. bool ElementStyle::IterateProperties(int& index, String& name, const Property*& property, const PseudoClassList** property_pseudo_classes)
  552. {
  553. // First check for locally defined properties.
  554. if (local_properties != NULL)
  555. {
  556. if (index < local_properties->GetNumProperties())
  557. {
  558. PropertyMap::const_iterator i = local_properties->GetProperties().begin();
  559. for (int count = 0; count < index; ++count)
  560. ++i;
  561. name = (*i).first;
  562. property = &((*i).second);
  563. if (property_pseudo_classes)
  564. * property_pseudo_classes = nullptr;
  565. ++index;
  566. return true;
  567. }
  568. }
  569. const ElementDefinition* definition = GetDefinition();
  570. if (definition != NULL)
  571. {
  572. int index_offset = 0;
  573. if (local_properties != NULL)
  574. index_offset = local_properties->GetNumProperties();
  575. // Offset the index to be relative to the definition before we start indexing. When we do get a property back,
  576. // check that it hasn't been overridden by the element's local properties; if so, continue on to the next one.
  577. index -= index_offset;
  578. while (definition->IterateProperties(index, pseudo_classes, name, property, property_pseudo_classes))
  579. {
  580. if (local_properties == NULL ||
  581. local_properties->GetProperty(name) == NULL)
  582. {
  583. index += index_offset;
  584. return true;
  585. }
  586. }
  587. return false;
  588. }
  589. return false;
  590. }
  591. // Returns the active style sheet for this element. This may be NULL.
  592. StyleSheet* ElementStyle::GetStyleSheet() const
  593. {
  594. ElementDocument* document = element->GetOwnerDocument();
  595. if (document != NULL)
  596. return document->GetStyleSheet();
  597. return NULL;
  598. }
  599. void ElementStyle::DirtyDefinition()
  600. {
  601. definition_dirty = true;
  602. DirtyChildDefinitions();
  603. }
  604. void ElementStyle::DirtyChildDefinitions()
  605. {
  606. for (int i = 0; i < element->GetNumChildren(true); i++)
  607. element->GetChild(i)->GetStyle()->DirtyDefinition();
  608. }
  609. // Dirties every property.
  610. void ElementStyle::DirtyProperties()
  611. {
  612. const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
  613. DirtyProperties(properties);
  614. }
  615. // Dirties em-relative properties.
  616. void ElementStyle::DirtyEmProperties()
  617. {
  618. if (!em_properties)
  619. {
  620. // Check if any of these are currently em-relative. If so, dirty them.
  621. em_properties = new PropertyNameList;
  622. for (auto& property : StyleSheetSpecification::GetRegisteredProperties())
  623. {
  624. // Skip font-size; this is relative to our parent's em, not ours.
  625. if (property == FONT_SIZE)
  626. continue;
  627. // Get this property from this element. If this is em-relative, then add it to the list to
  628. // dirty.
  629. if (element->GetProperty(property)->unit == Property::EM)
  630. em_properties->insert(property);
  631. }
  632. }
  633. if (!em_properties->empty())
  634. DirtyProperties(*em_properties, false);
  635. // Now dirty all of our descendant's font-size properties that are relative to ems.
  636. int num_children = element->GetNumChildren(true);
  637. for (int i = 0; i < num_children; ++i)
  638. element->GetChild(i)->GetStyle()->DirtyInheritedEmProperties();
  639. }
  640. // Dirties font-size on child elements if appropriate.
  641. void ElementStyle::DirtyInheritedEmProperties()
  642. {
  643. const Property* font_size = element->GetLocalProperty(FONT_SIZE);
  644. if (font_size == NULL)
  645. {
  646. int num_children = element->GetNumChildren(true);
  647. for (int i = 0; i < num_children; ++i)
  648. element->GetChild(i)->GetStyle()->DirtyInheritedEmProperties();
  649. }
  650. else
  651. {
  652. if (font_size->unit & Property::RELATIVE_UNIT)
  653. DirtyProperty(FONT_SIZE);
  654. }
  655. }
  656. // Dirties rem properties.
  657. void ElementStyle::DirtyRemProperties()
  658. {
  659. const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
  660. PropertyNameList rem_properties;
  661. // Dirty all the properties of this element that use the rem unit.
  662. for (PropertyNameList::const_iterator list_iterator = properties.begin(); list_iterator != properties.end(); ++list_iterator)
  663. {
  664. if (element->GetProperty(*list_iterator)->unit == Property::REM)
  665. rem_properties.insert(*list_iterator);
  666. }
  667. if (!rem_properties.empty())
  668. DirtyProperties(rem_properties, false);
  669. // Now dirty all of our descendant's properties that use the rem unit.
  670. int num_children = element->GetNumChildren(true);
  671. for (int i = 0; i < num_children; ++i)
  672. element->GetChild(i)->GetStyle()->DirtyRemProperties();
  673. }
  674. void ElementStyle::DirtyDpProperties()
  675. {
  676. const PropertyNameList &properties = StyleSheetSpecification::GetRegisteredProperties();
  677. PropertyNameList dp_properties;
  678. // Dirty all the properties of this element that use the dp unit.
  679. for (PropertyNameList::const_iterator list_iterator = properties.begin(); list_iterator != properties.end(); ++list_iterator)
  680. {
  681. if (element->GetProperty(*list_iterator)->unit == Property::DP)
  682. dp_properties.insert(*list_iterator);
  683. }
  684. if (!dp_properties.empty())
  685. DirtyProperties(dp_properties, false);
  686. // Now dirty all of our descendant's properties that use the dp unit.
  687. int num_children = element->GetNumChildren(true);
  688. for (int i = 0; i < num_children; ++i)
  689. element->GetChild(i)->GetStyle()->DirtyDpProperties();
  690. }
  691. // Sets a single property as dirty.
  692. void ElementStyle::DirtyProperty(const String& property)
  693. {
  694. PropertyNameList properties;
  695. properties.insert(String(property));
  696. DirtyProperties(properties);
  697. }
  698. // Sets a list of properties as dirty.
  699. void ElementStyle::DirtyProperties(const PropertyNameList& properties, bool clear_em_properties)
  700. {
  701. if (properties.empty())
  702. return;
  703. bool all_inherited_dirty =
  704. &properties == &StyleSheetSpecification::GetRegisteredProperties() ||
  705. StyleSheetSpecification::GetRegisteredProperties() == properties ||
  706. StyleSheetSpecification::GetRegisteredInheritedProperties() == properties;
  707. if (all_inherited_dirty)
  708. {
  709. const PropertyNameList &all_inherited_properties = StyleSheetSpecification::GetRegisteredInheritedProperties();
  710. for (int i = 0; i < element->GetNumChildren(true); i++)
  711. element->GetChild(i)->GetStyle()->DirtyInheritedProperties(all_inherited_properties);
  712. }
  713. else
  714. {
  715. PropertyNameList inherited_properties;
  716. for (PropertyNameList::const_iterator i = properties.begin(); i != properties.end(); ++i)
  717. {
  718. // If this property is an inherited property, then push it into the list to be passed onto our children.
  719. const PropertyDefinition* property = StyleSheetSpecification::GetProperty(*i);
  720. if (property != NULL &&
  721. property->IsInherited())
  722. inherited_properties.insert(*i);
  723. }
  724. // Pass the list of those properties that are inherited onto our children.
  725. if (!inherited_properties.empty())
  726. {
  727. for (int i = 0; i < element->GetNumChildren(true); i++)
  728. element->GetChild(i)->GetStyle()->DirtyInheritedProperties(inherited_properties);
  729. }
  730. }
  731. // clear the list of EM-properties, we will refill it in DirtyEmProperties
  732. if (clear_em_properties && em_properties != NULL)
  733. {
  734. delete em_properties;
  735. em_properties = NULL;
  736. }
  737. // And send the event.
  738. element->DirtyProperties(properties);
  739. }
  740. // Sets a list of our potentially inherited properties as dirtied by an ancestor.
  741. void ElementStyle::DirtyInheritedProperties(const PropertyNameList& properties)
  742. {
  743. bool clear_em_properties = em_properties != NULL;
  744. PropertyNameList inherited_properties;
  745. for (PropertyNameList::const_iterator i = properties.begin(); i != properties.end(); ++i)
  746. {
  747. const Property *property = GetLocalProperty((*i));
  748. if (property == NULL)
  749. {
  750. inherited_properties.insert(*i);
  751. if (!clear_em_properties && em_properties != NULL && em_properties->find((*i)) != em_properties->end()) {
  752. clear_em_properties = true;
  753. }
  754. }
  755. }
  756. if (inherited_properties.empty())
  757. return;
  758. // clear the list of EM-properties, we will refill it in DirtyEmProperties
  759. if (clear_em_properties && em_properties != NULL)
  760. {
  761. delete em_properties;
  762. em_properties = NULL;
  763. }
  764. // Pass the list of those properties that this element doesn't override onto our children.
  765. for (int i = 0; i < element->GetNumChildren(true); i++)
  766. element->GetChild(i)->GetStyle()->DirtyInheritedProperties(inherited_properties);
  767. element->DirtyProperties(properties);
  768. }
  769. static float ComputeLength(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  770. {
  771. // Note that percentages are not lengths! They have to be resolved elsewhere.
  772. if (!property)
  773. {
  774. ROCKET_ERROR;
  775. return 0.0f;
  776. }
  777. switch (property->unit)
  778. {
  779. case Property::NUMBER:
  780. case Property::PX:
  781. case Property::RAD:
  782. return property->value.Get< float >();
  783. case Property::EM:
  784. return property->value.Get< float >() * font_size;
  785. case Property::REM:
  786. return property->value.Get< float >() * document_font_size;
  787. case Property::DP:
  788. return property->value.Get< float >() * dp_ratio;
  789. case Property::DEG:
  790. return Math::DegreesToRadians(property->value.Get< float >());
  791. default:
  792. break;
  793. }
  794. // Values based on pixels-per-inch.
  795. if (property->unit & Property::PPI_UNIT)
  796. {
  797. float inch = property->value.Get< float >() * pixels_per_inch;
  798. switch (property->unit)
  799. {
  800. case Property::INCH: // inch
  801. return inch;
  802. case Property::CM: // centimeter
  803. return inch * (1.0f / 2.54f);
  804. case Property::MM: // millimeter
  805. return inch * (1.0f / 25.4f);
  806. case Property::PT: // point
  807. return inch * (1.0f / 72.0f);
  808. case Property::PC: // pica
  809. return inch * (1.0f / 6.0f);
  810. default:
  811. break;
  812. }
  813. }
  814. // We're not a numeric property; return 0.
  815. return 0.0f;
  816. }
  817. static float ComputeAbsoluteLength(const Property& property, float dp_ratio, float pixels_per_inch)
  818. {
  819. ROCKET_ASSERT(property.unit & Property::ABSOLUTE_LENGTH);
  820. switch (property.unit)
  821. {
  822. case Property::PX:
  823. return property.value.Get< float >();
  824. case Property::DP:
  825. return property.value.Get< float >()* dp_ratio;
  826. default:
  827. // Values based on pixels-per-inch.
  828. if (property.unit & Property::PPI_UNIT)
  829. {
  830. float inch = property.value.Get< float >() * pixels_per_inch;
  831. switch (property.unit)
  832. {
  833. case Property::INCH: // inch
  834. return inch;
  835. case Property::CM: // centimeter
  836. return inch * (1.0f / 2.54f);
  837. case Property::MM: // millimeter
  838. return inch * (1.0f / 25.4f);
  839. case Property::PT: // point
  840. return inch * (1.0f / 72.0f);
  841. case Property::PC: // pica
  842. return inch * (1.0f / 6.0f);
  843. }
  844. }
  845. }
  846. ROCKET_ERROR;
  847. return 0.0f;
  848. }
  849. // Resolves one of this element's properties.
  850. 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)
  851. {
  852. // The calculated value of the font-size property is inherited, so we need to check if this
  853. // is an inherited property. If so, then we return our parent's font size instead.
  854. if (property.unit & Property::RELATIVE_UNIT)
  855. {
  856. float multiplier = 1.0f;
  857. switch (property.unit)
  858. {
  859. case Property::PERCENT:
  860. multiplier = 0.01f;
  861. [[fallthrough]];
  862. case Property::EM:
  863. if (!parent_values)
  864. return 0;
  865. return property.value.Get< float >() * multiplier * parent_values->font_size;
  866. case Property::REM:
  867. if (!document_values)
  868. return 0;
  869. // If the current element is a document, the rem unit is relative to the default size
  870. if(&values == document_values)
  871. return property.value.Get< float >() * DefaultComputedValues.font_size;
  872. // Otherwise it is relative to the document font size
  873. return property.value.Get< float >() * document_values->font_size;
  874. default:
  875. ROCKET_ERRORMSG("A relative unit must be percentage, em or rem.");
  876. }
  877. }
  878. return ComputeAbsoluteLength(property, dp_ratio, pixels_per_inch);
  879. }
  880. static inline Style::Clip ComputeClip(const Property* property)
  881. {
  882. int value = property->Get<int>();
  883. if (property->unit == Property::KEYWORD)
  884. return Style::Clip(value == CLIP_NONE ? Style::Clip::None : Style::Clip::Auto);
  885. else if (property->unit == Property::NUMBER)
  886. return Style::Clip(Style::Clip::Number, value);
  887. ROCKET_ERRORMSG("Invalid clip type");
  888. return Style::Clip();
  889. }
  890. static inline Style::LineHeight ComputeLineHeight(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  891. {
  892. if (property->unit & Property::LENGTH)
  893. {
  894. float value = ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch);
  895. return Style::LineHeight(value, Style::LineHeight::Length, value);
  896. }
  897. float scale_factor = 1.0f;
  898. switch (property->unit)
  899. {
  900. case Property::NUMBER:
  901. scale_factor = property->value.Get< float >();
  902. break;
  903. case Property::PERCENT:
  904. scale_factor = property->value.Get< float >() * 0.01f;
  905. break;
  906. default:
  907. ROCKET_ERRORMSG("Invalid unit for line-height");
  908. }
  909. float value = font_size * scale_factor;
  910. return Style::LineHeight(value, Style::LineHeight::Number, scale_factor);
  911. }
  912. 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)
  913. {
  914. if (property->unit & Property::LENGTH)
  915. {
  916. float value = ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch);
  917. return Style::VerticalAlign(value);
  918. }
  919. else if (property->unit & Property::PERCENT)
  920. {
  921. return Style::VerticalAlign(property->Get<float>() * line_height);
  922. }
  923. ROCKET_ASSERT(property->unit & Property::KEYWORD);
  924. return Style::VerticalAlign((Style::VerticalAlign::Type)property->Get<int>());
  925. }
  926. static inline Style::LengthPercentage ComputeLengthPercentage(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  927. {
  928. using namespace Style;
  929. if (property->unit & Property::PERCENT)
  930. return LengthPercentage(LengthPercentage::Percentage, property->Get<float>());
  931. return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch));
  932. }
  933. static inline Style::LengthPercentageAuto ComputeLengthPercentageAuto(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  934. {
  935. using namespace Style;
  936. // Assuming here that 'auto' is the only possible keyword
  937. if (property->unit & Property::PERCENT)
  938. return LengthPercentageAuto(LengthPercentageAuto::Percentage, property->Get<float>());
  939. else if (property->unit & Property::KEYWORD)
  940. return LengthPercentageAuto(LengthPercentageAuto::Auto);
  941. return LengthPercentageAuto(LengthPercentageAuto::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch));
  942. }
  943. static inline Style::LengthPercentage ComputeOrigin(const Property* property, float font_size, float document_font_size, float dp_ratio, float pixels_per_inch)
  944. {
  945. using namespace Style;
  946. static_assert((int)OriginX::Left == (int)OriginY::Top && (int)OriginX::Center == (int)OriginY::Center && (int)OriginX::Right == (int)OriginY::Bottom, "");
  947. if (property->unit & Property::KEYWORD)
  948. {
  949. float percent = 0.0f;
  950. OriginX origin = (OriginX)property->Get<int>();
  951. switch (origin)
  952. {
  953. case OriginX::Left: percent = 0.0f; break;
  954. case OriginX::Center: percent = 50.0f; break;
  955. case OriginX::Right: percent = 100.f; break;
  956. }
  957. return LengthPercentage(LengthPercentage::Percentage, percent);
  958. }
  959. else if (property->unit & Property::PERCENT)
  960. return LengthPercentage(LengthPercentage::Percentage, property->Get<float>());
  961. return LengthPercentage(LengthPercentage::Length, ComputeLength(property, font_size, document_font_size, dp_ratio, pixels_per_inch));
  962. }
  963. // Must be called in correct order, from document root to children elements.
  964. 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)
  965. {
  966. // Generally, this is how it works (for now, we can probably be smarter about this):
  967. // 1. Assign default values (clears any newly dirtied properties)
  968. // 2. Inherit inheritable values from parent
  969. // 3. Assign any local properties (from inline style or stylesheet)
  970. // The next flag is just a small optimization, if the element was just created we don't need to copy all the default values.
  971. if (!values_are_defaulted)
  972. {
  973. values = DefaultComputedValues;
  974. }
  975. // Always do font-size first if dirty, because of em-relative values
  976. if (auto p = GetLocalProperty(FONT_SIZE))
  977. values.font_size = ComputeFontsize(*p, values, parent_values, document_values, dp_ratio, pixels_per_inch);
  978. else if (parent_values)
  979. values.font_size = parent_values->font_size;
  980. const float font_size = values.font_size;
  981. const float document_font_size = (document_values ? document_values->font_size : DefaultComputedValues.font_size);
  982. // Since vertical-align depends on line-height we compute this before iteration
  983. if (auto p = GetLocalProperty(LINE_HEIGHT))
  984. {
  985. values.line_height = ComputeLineHeight(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  986. }
  987. else if (parent_values)
  988. {
  989. // 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.
  990. // See CSS specs for details. Percent is already converted to number.
  991. if (parent_values->line_height.inherit_type == Style::LineHeight::Number)
  992. values.line_height = Style::LineHeight(font_size * parent_values->line_height.inherit_value, Style::LineHeight::Number, parent_values->line_height.inherit_value);
  993. else
  994. values.line_height = parent_values->line_height;
  995. }
  996. if (parent_values)
  997. {
  998. // Inherited properties are copied here, but may be overwritten below by locally defined properties
  999. // Line-height and font-size are computed above
  1000. values.clip = parent_values->clip;
  1001. values.color = parent_values->color;
  1002. values.opacity = parent_values->opacity;
  1003. values.font_family = parent_values->font_family;
  1004. values.font_charset = parent_values->font_charset;
  1005. values.font_style = parent_values->font_style;
  1006. values.font_weight = parent_values->font_weight;
  1007. values.text_align = parent_values->text_align;
  1008. values.text_decoration = parent_values->text_decoration;
  1009. values.text_transform = parent_values->text_transform;
  1010. values.white_space = parent_values->white_space;
  1011. values.cursor = parent_values->cursor;
  1012. values.focus = parent_values->focus;
  1013. values.pointer_events = parent_values->pointer_events;
  1014. }
  1015. int index = 0;
  1016. String name;
  1017. const Property* p = nullptr;
  1018. while (IterateProperties(index, name, p))
  1019. {
  1020. using namespace Style;
  1021. // @performance: Can use a switch-case with constexpr hashing function
  1022. // 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...
  1023. // @performance: Compare to the list of actually changed properties, skip if not inside it
  1024. if (name == MARGIN_TOP)
  1025. values.margin_top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1026. else if (name == MARGIN_RIGHT)
  1027. values.margin_right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1028. else if (name == MARGIN_BOTTOM)
  1029. values.margin_bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1030. else if (name == MARGIN_LEFT)
  1031. values.margin_left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1032. else if (name == PADDING_TOP)
  1033. values.padding_top = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1034. else if (name == PADDING_RIGHT)
  1035. values.padding_right = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1036. else if (name == PADDING_BOTTOM)
  1037. values.padding_bottom = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1038. else if (name == PADDING_LEFT)
  1039. values.padding_left = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1040. else if (name == BORDER_TOP_WIDTH)
  1041. values.border_top_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1042. else if (name == BORDER_RIGHT_WIDTH)
  1043. values.border_right_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1044. else if (name == BORDER_BOTTOM_WIDTH)
  1045. values.border_bottom_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1046. else if (name == BORDER_LEFT_WIDTH)
  1047. values.border_left_width = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1048. else if (name == BORDER_TOP_COLOR)
  1049. values.border_top_color = p->Get<Colourb>();
  1050. else if (name == BORDER_RIGHT_COLOR)
  1051. values.border_right_color = p->Get<Colourb>();
  1052. else if (name == BORDER_BOTTOM_COLOR)
  1053. values.border_bottom_color = p->Get<Colourb>();
  1054. else if (name == BORDER_LEFT_COLOR)
  1055. values.border_left_color = p->Get<Colourb>();
  1056. else if (name == DISPLAY)
  1057. values.display = (Display)p->Get<int>();
  1058. else if (name == POSITION)
  1059. values.position = (Position)p->Get<int>();
  1060. else if (name == TOP)
  1061. values.top = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1062. else if (name == RIGHT)
  1063. values.right = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1064. else if (name == BOTTOM)
  1065. values.bottom = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1066. else if (name == LEFT)
  1067. values.left = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1068. else if (name == FLOAT)
  1069. values.float_ = (Float)p->Get<int>();
  1070. else if (name == CLEAR)
  1071. values.clear = (Clear)p->Get<int>();
  1072. else if (name == Z_INDEX)
  1073. values.z_index = (p->unit == Property::KEYWORD ? ZIndex(ZIndex::Auto) : ZIndex(ZIndex::Number, p->Get<float>()));
  1074. else if (name == WIDTH)
  1075. values.width = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1076. else if (name == MIN_WIDTH)
  1077. values.min_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1078. else if (name == MAX_WIDTH)
  1079. values.max_width = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1080. else if (name == HEIGHT)
  1081. values.height = ComputeLengthPercentageAuto(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1082. else if (name == MIN_HEIGHT)
  1083. values.min_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1084. else if (name == MAX_HEIGHT)
  1085. values.max_height = ComputeLengthPercentage(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1086. // (Line-height computed above)
  1087. else if (name == VERTICAL_ALIGN)
  1088. values.vertical_align = ComputeVerticalAlign(p, values.line_height.value, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1089. else if (name == OVERFLOW_X)
  1090. values.overflow_x = (Overflow)p->Get< int >();
  1091. else if (name == OVERFLOW_Y)
  1092. values.overflow_y = (Overflow)p->Get< int >();
  1093. else if (name == CLIP)
  1094. values.clip = ComputeClip(p);
  1095. else if (name == VISIBILITY)
  1096. values.visibility = (Visibility)p->Get< int >();
  1097. else if (name == BACKGROUND_COLOR)
  1098. values.background_color = p->Get<Colourb>();
  1099. else if (name == COLOR)
  1100. values.color = p->Get<Colourb>();
  1101. else if (name == IMAGE_COLOR)
  1102. values.image_color = p->Get<Colourb>();
  1103. else if (name == OPACITY)
  1104. values.opacity = p->Get<float>();
  1105. else if (name == FONT_FAMILY)
  1106. values.font_family = ToLower(p->Get<String>());
  1107. else if (name == FONT_CHARSET)
  1108. values.font_charset = p->Get<String>();
  1109. else if (name == FONT_STYLE)
  1110. values.font_style = (FontStyle)p->Get< int >();
  1111. else if (name == FONT_WEIGHT)
  1112. values.font_weight = (FontWeight)p->Get< int >();
  1113. // (font-size computed above)
  1114. else if (name == TEXT_ALIGN)
  1115. values.text_align = (TextAlign)p->Get< int >();
  1116. else if (name == TEXT_DECORATION)
  1117. values.text_decoration = (TextDecoration)p->Get< int >();
  1118. else if (name == TEXT_TRANSFORM)
  1119. values.text_transform = (TextTransform)p->Get< int >();
  1120. else if (name == WHITE_SPACE)
  1121. values.white_space = (WhiteSpace)p->Get< int >();
  1122. else if (name == CURSOR)
  1123. values.cursor = p->Get< String >();
  1124. else if (name == DRAG)
  1125. values.drag = (Drag)p->Get< int >();
  1126. else if (name == TAB_INDEX)
  1127. values.tab_index = (TabIndex)p->Get< int >();
  1128. else if (name == FOCUS)
  1129. values.focus = (Focus)p->Get<int>();
  1130. else if (name == SCROLLBAR_MARGIN)
  1131. values.scrollbar_margin = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1132. else if (name == POINTER_EVENTS)
  1133. values.pointer_events = (PointerEvents)p->Get<int>();
  1134. else if (name == PERSPECTIVE)
  1135. values.perspective = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1136. else if (name == PERSPECTIVE_ORIGIN_X)
  1137. values.perspective_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1138. else if (name == PERSPECTIVE_ORIGIN_Y)
  1139. values.perspective_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1140. else if (name == TRANSFORM)
  1141. values.transform = p->Get<TransformRef>();
  1142. else if(name == TRANSFORM_ORIGIN_X)
  1143. values.transform_origin_x = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1144. else if (name == TRANSFORM_ORIGIN_Y)
  1145. values.transform_origin_y = ComputeOrigin(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1146. else if (name == TRANSFORM_ORIGIN_Z)
  1147. values.transform_origin_z = ComputeLength(p, font_size, document_font_size, dp_ratio, pixels_per_inch);
  1148. else if (name == TRANSITION)
  1149. values.transition = p->Get<TransitionList>();
  1150. else if (name == ANIMATION)
  1151. values.animation = p->Get<AnimationList>();
  1152. }
  1153. }
  1154. }
  1155. }