PropertyParserTransform.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #include "PropertyParserTransform.h"
  2. #include "../../Include/RmlUi/Core/NumericValue.h"
  3. #include "../../Include/RmlUi/Core/Transform.h"
  4. #include "../../Include/RmlUi/Core/TransformPrimitive.h"
  5. #include <string.h>
  6. namespace Rml {
  7. PropertyParserTransform::PropertyParserTransform() :
  8. number(Unit::NUMBER), length(Unit::LENGTH, Unit::PX), length_pct(Unit::LENGTH_PERCENT, Unit::PX), angle(Unit::ANGLE, Unit::RAD)
  9. {}
  10. PropertyParserTransform::~PropertyParserTransform() {}
  11. bool PropertyParserTransform::ParseValue(Property& property, const String& value, const ParameterMap& /*parameters*/) const
  12. {
  13. if (value == "none")
  14. {
  15. property.value = Variant(TransformPtr());
  16. property.unit = Unit::TRANSFORM;
  17. return true;
  18. }
  19. TransformPtr transform = MakeShared<Transform>();
  20. char const* next = value.c_str();
  21. NumericValue args[16];
  22. const PropertyParser* number16[] = {&number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number, &number,
  23. &number, &number, &number, &number};
  24. const PropertyParser* lengthpct2_length1[] = {&length_pct, &length_pct, &length};
  25. const PropertyParser* number3angle1[] = {&number, &number, &number, &angle};
  26. const PropertyParser* angle2[] = {&angle, &angle};
  27. const PropertyParser* length1[] = {&length};
  28. // For semantic purposes, define subsets of the above parsers when scanning primitives below.
  29. auto lengthpct1 = lengthpct2_length1;
  30. auto lengthpct2 = lengthpct2_length1;
  31. auto angle1 = angle2;
  32. auto number1 = number16;
  33. auto number2 = number16;
  34. auto number3 = number16;
  35. auto number6 = number16;
  36. while (*next)
  37. {
  38. using namespace Transforms;
  39. int bytes_read = 0;
  40. if (Scan(bytes_read, next, "perspective", length1, args, 1))
  41. {
  42. transform->AddPrimitive({Perspective(args)});
  43. }
  44. else if (Scan(bytes_read, next, "matrix", number6, args, 6))
  45. {
  46. transform->AddPrimitive({Matrix2D(args)});
  47. }
  48. else if (Scan(bytes_read, next, "matrix3d", number16, args, 16))
  49. {
  50. transform->AddPrimitive({Matrix3D(args)});
  51. }
  52. else if (Scan(bytes_read, next, "translateX", lengthpct1, args, 1))
  53. {
  54. transform->AddPrimitive({TranslateX(args)});
  55. }
  56. else if (Scan(bytes_read, next, "translateY", lengthpct1, args, 1))
  57. {
  58. transform->AddPrimitive({TranslateY(args)});
  59. }
  60. else if (Scan(bytes_read, next, "translateZ", length1, args, 1))
  61. {
  62. transform->AddPrimitive({TranslateZ(args)});
  63. }
  64. else if (Scan(bytes_read, next, "translate", lengthpct2, args, 2))
  65. {
  66. transform->AddPrimitive({Translate2D(args)});
  67. }
  68. else if (Scan(bytes_read, next, "translate3d", lengthpct2_length1, args, 3))
  69. {
  70. transform->AddPrimitive({Translate3D(args)});
  71. }
  72. else if (Scan(bytes_read, next, "scaleX", number1, args, 1))
  73. {
  74. transform->AddPrimitive({ScaleX(args)});
  75. }
  76. else if (Scan(bytes_read, next, "scaleY", number1, args, 1))
  77. {
  78. transform->AddPrimitive({ScaleY(args)});
  79. }
  80. else if (Scan(bytes_read, next, "scaleZ", number1, args, 1))
  81. {
  82. transform->AddPrimitive({ScaleZ(args)});
  83. }
  84. else if (Scan(bytes_read, next, "scale", number2, args, 2))
  85. {
  86. transform->AddPrimitive({Scale2D(args)});
  87. }
  88. else if (Scan(bytes_read, next, "scale", number1, args, 1))
  89. {
  90. args[1] = args[0];
  91. transform->AddPrimitive({Scale2D(args)});
  92. }
  93. else if (Scan(bytes_read, next, "scale3d", number3, args, 3))
  94. {
  95. transform->AddPrimitive({Scale3D(args)});
  96. }
  97. else if (Scan(bytes_read, next, "rotateX", angle1, args, 1))
  98. {
  99. transform->AddPrimitive({RotateX(args)});
  100. }
  101. else if (Scan(bytes_read, next, "rotateY", angle1, args, 1))
  102. {
  103. transform->AddPrimitive({RotateY(args)});
  104. }
  105. else if (Scan(bytes_read, next, "rotateZ", angle1, args, 1))
  106. {
  107. transform->AddPrimitive({RotateZ(args)});
  108. }
  109. else if (Scan(bytes_read, next, "rotate", angle1, args, 1))
  110. {
  111. transform->AddPrimitive({Rotate2D(args)});
  112. }
  113. else if (Scan(bytes_read, next, "rotate3d", number3angle1, args, 4))
  114. {
  115. transform->AddPrimitive({Rotate3D(args)});
  116. }
  117. else if (Scan(bytes_read, next, "skewX", angle1, args, 1))
  118. {
  119. transform->AddPrimitive({SkewX(args)});
  120. }
  121. else if (Scan(bytes_read, next, "skewY", angle1, args, 1))
  122. {
  123. transform->AddPrimitive({SkewY(args)});
  124. }
  125. else if (Scan(bytes_read, next, "skew", angle2, args, 2))
  126. {
  127. transform->AddPrimitive({Skew2D(args)});
  128. }
  129. if (bytes_read > 0)
  130. {
  131. next += bytes_read;
  132. }
  133. else
  134. {
  135. return false;
  136. }
  137. }
  138. property.value = Variant(std::move(transform));
  139. property.unit = Unit::TRANSFORM;
  140. return true;
  141. }
  142. bool PropertyParserTransform::Scan(int& out_bytes_read, const char* str, const char* keyword, const PropertyParser** parsers, NumericValue* args,
  143. int nargs) const
  144. {
  145. out_bytes_read = 0;
  146. int total_bytes_read = 0, bytes_read = 0;
  147. /* skip leading white space */
  148. bytes_read = 0;
  149. sscanf(str, " %n", &bytes_read);
  150. str += bytes_read;
  151. total_bytes_read += bytes_read;
  152. /* find the keyword */
  153. if (!memcmp(str, keyword, strlen(keyword)))
  154. {
  155. bytes_read = (int)strlen(keyword);
  156. str += bytes_read;
  157. total_bytes_read += bytes_read;
  158. }
  159. else
  160. {
  161. return false;
  162. }
  163. /* skip any white space */
  164. bytes_read = 0;
  165. sscanf(str, " %n", &bytes_read);
  166. str += bytes_read;
  167. total_bytes_read += bytes_read;
  168. /* find the opening brace */
  169. bytes_read = 0;
  170. if (sscanf(str, " ( %n", &bytes_read), bytes_read)
  171. {
  172. str += bytes_read;
  173. total_bytes_read += bytes_read;
  174. }
  175. else
  176. {
  177. return false;
  178. }
  179. /* use the quicker stack-based argument buffer, if possible */
  180. char* arg = nullptr;
  181. char arg_stack[1024];
  182. String arg_heap;
  183. if (strlen(str) < sizeof(arg_stack))
  184. {
  185. arg = arg_stack;
  186. }
  187. else
  188. {
  189. arg_heap = str;
  190. arg = &arg_heap[0];
  191. }
  192. /* parse the arguments */
  193. for (int i = 0; i < nargs; ++i)
  194. {
  195. Property prop;
  196. bytes_read = 0;
  197. if (sscanf(str, " %[^,)] %n", arg, &bytes_read), bytes_read && parsers[i]->ParseValue(prop, String(arg), ParameterMap()))
  198. {
  199. args[i].number = prop.value.Get<float>();
  200. args[i].unit = prop.unit;
  201. str += bytes_read;
  202. total_bytes_read += bytes_read;
  203. }
  204. else
  205. {
  206. return false;
  207. }
  208. /* find the comma */
  209. if (i < nargs - 1)
  210. {
  211. bytes_read = 0;
  212. if (sscanf(str, " , %n", &bytes_read), bytes_read)
  213. {
  214. str += bytes_read;
  215. total_bytes_read += bytes_read;
  216. }
  217. else
  218. {
  219. return false;
  220. }
  221. }
  222. }
  223. /* find the closing brace */
  224. bytes_read = 0;
  225. if (sscanf(str, " ) %n", &bytes_read), bytes_read)
  226. {
  227. str += bytes_read;
  228. total_bytes_read += bytes_read;
  229. }
  230. else
  231. {
  232. return false;
  233. }
  234. out_bytes_read = total_bytes_read;
  235. return total_bytes_read > 0;
  236. }
  237. } // namespace Rml