PropertyParserNumber.cpp 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #include "PropertyParserNumber.h"
  2. #include <stdlib.h>
  3. namespace Rml {
  4. struct PropertyParserNumberData {
  5. const UnorderedMap<String, Unit> unit_string_map = {
  6. {"", Unit::NUMBER},
  7. {"%", Unit::PERCENT},
  8. {"px", Unit::PX},
  9. {"dp", Unit::DP},
  10. {"x", Unit::X},
  11. {"vw", Unit::VW},
  12. {"vh", Unit::VH},
  13. {"em", Unit::EM},
  14. {"rem", Unit::REM},
  15. {"in", Unit::INCH},
  16. {"cm", Unit::CM},
  17. {"mm", Unit::MM},
  18. {"pt", Unit::PT},
  19. {"pc", Unit::PC},
  20. {"deg", Unit::DEG},
  21. {"rad", Unit::RAD},
  22. };
  23. };
  24. ControlledLifetimeResource<PropertyParserNumberData> PropertyParserNumber::parser_data;
  25. void PropertyParserNumber::Initialize()
  26. {
  27. parser_data.Initialize();
  28. }
  29. void PropertyParserNumber::Shutdown()
  30. {
  31. parser_data.Shutdown();
  32. }
  33. PropertyParserNumber::PropertyParserNumber(Units units, Unit zero_unit) : units(units), zero_unit(zero_unit) {}
  34. PropertyParserNumber::~PropertyParserNumber() {}
  35. bool PropertyParserNumber::ParseValue(Property& property, const String& value, const ParameterMap& /*parameters*/) const
  36. {
  37. // Find the beginning of the unit string in 'value'.
  38. size_t unit_pos = 0;
  39. for (size_t i = value.size(); i--;)
  40. {
  41. const char c = value[i];
  42. if ((c >= '0' && c <= '9') || StringUtilities::IsWhitespace(c))
  43. {
  44. unit_pos = i + 1;
  45. break;
  46. }
  47. }
  48. String str_number = value.substr(0, unit_pos);
  49. String str_unit = StringUtilities::ToLower(value.substr(unit_pos));
  50. char* str_end = nullptr;
  51. float float_value = strtof(str_number.c_str(), &str_end);
  52. if (str_number.c_str() == str_end)
  53. {
  54. // Number conversion failed
  55. return false;
  56. }
  57. const auto it = parser_data->unit_string_map.find(str_unit);
  58. if (it == parser_data->unit_string_map.end())
  59. {
  60. // Invalid unit name
  61. return false;
  62. }
  63. const Unit unit = it->second;
  64. if (Any(unit & units))
  65. {
  66. property.value = float_value;
  67. property.unit = unit;
  68. return true;
  69. }
  70. // Detected unit not allowed.
  71. // However, we allow a value of "0" if zero_unit is set and no unit specified (that is, unit is a pure NUMBER).
  72. if (unit == Unit::NUMBER)
  73. {
  74. if (zero_unit != Unit::UNKNOWN && float_value == 0.0f)
  75. {
  76. property.unit = zero_unit;
  77. property.value = Variant(0.0f);
  78. return true;
  79. }
  80. }
  81. return false;
  82. }
  83. } // namespace Rml