conversions.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #pragma once
  8. #include <folly/Conv.h>
  9. #include <folly/dynamic.h>
  10. #include <react/attributedstring/AttributedString.h>
  11. #include <react/attributedstring/ParagraphAttributes.h>
  12. #include <react/attributedstring/TextAttributes.h>
  13. #include <react/attributedstring/conversions.h>
  14. #include <react/attributedstring/primitives.h>
  15. #include <react/core/LayoutableShadowNode.h>
  16. #include <react/core/ShadowNode.h>
  17. #include <react/core/conversions.h>
  18. #include <react/core/propsConversions.h>
  19. #include <react/graphics/Geometry.h>
  20. #include <react/graphics/conversions.h>
  21. #include <cmath>
  22. #include <glog/logging.h>
  23. namespace facebook {
  24. namespace react {
  25. inline std::string toString(const EllipsizeMode &ellipsisMode) {
  26. switch (ellipsisMode) {
  27. case EllipsizeMode::Clip:
  28. return "clip";
  29. case EllipsizeMode::Head:
  30. return "head";
  31. case EllipsizeMode::Tail:
  32. return "tail";
  33. case EllipsizeMode::Middle:
  34. return "middle";
  35. }
  36. }
  37. inline void fromRawValue(const RawValue &value, EllipsizeMode &result) {
  38. auto string = (std::string)value;
  39. if (string == "clip") {
  40. result = EllipsizeMode::Clip;
  41. return;
  42. }
  43. if (string == "head") {
  44. result = EllipsizeMode::Head;
  45. return;
  46. }
  47. if (string == "tail") {
  48. result = EllipsizeMode::Tail;
  49. return;
  50. }
  51. if (string == "middle") {
  52. result = EllipsizeMode::Middle;
  53. return;
  54. }
  55. abort();
  56. }
  57. inline std::string toString(const TextBreakStrategy &textBreakStrategy) {
  58. switch (textBreakStrategy) {
  59. case TextBreakStrategy::Simple:
  60. return "simple";
  61. case TextBreakStrategy::HighQuality:
  62. return "highQuality";
  63. case TextBreakStrategy::Balanced:
  64. return "balanced";
  65. }
  66. }
  67. inline void fromRawValue(const RawValue &value, TextBreakStrategy &result) {
  68. auto string = (std::string)value;
  69. if (string == "simple") {
  70. result = TextBreakStrategy::Simple;
  71. return;
  72. }
  73. if (string == "highQuality") {
  74. result = TextBreakStrategy::HighQuality;
  75. return;
  76. }
  77. if (string == "balanced") {
  78. result = TextBreakStrategy::Balanced;
  79. return;
  80. }
  81. abort();
  82. }
  83. inline void fromRawValue(const RawValue &value, FontWeight &result) {
  84. auto string = (std::string)value;
  85. if (string == "normal") {
  86. result = FontWeight::Regular;
  87. return;
  88. }
  89. if (string == "regular") {
  90. result = FontWeight::Regular;
  91. return;
  92. }
  93. if (string == "bold") {
  94. result = FontWeight::Bold;
  95. return;
  96. }
  97. if (string == "100") {
  98. result = FontWeight::Weight100;
  99. return;
  100. }
  101. if (string == "200") {
  102. result = FontWeight::Weight200;
  103. return;
  104. }
  105. if (string == "300") {
  106. result = FontWeight::Weight300;
  107. return;
  108. }
  109. if (string == "400") {
  110. result = FontWeight::Weight400;
  111. return;
  112. }
  113. if (string == "500") {
  114. result = FontWeight::Weight500;
  115. return;
  116. }
  117. if (string == "600") {
  118. result = FontWeight::Weight600;
  119. return;
  120. }
  121. if (string == "700") {
  122. result = FontWeight::Weight700;
  123. return;
  124. }
  125. if (string == "800") {
  126. result = FontWeight::Weight800;
  127. return;
  128. }
  129. if (string == "900") {
  130. result = FontWeight::Weight900;
  131. return;
  132. }
  133. abort();
  134. }
  135. inline std::string toString(const FontWeight &fontWeight) {
  136. return folly::to<std::string>((int)fontWeight);
  137. }
  138. inline void fromRawValue(const RawValue &value, FontStyle &result) {
  139. auto string = (std::string)value;
  140. if (string == "normal") {
  141. result = FontStyle::Normal;
  142. return;
  143. }
  144. if (string == "italic") {
  145. result = FontStyle::Italic;
  146. return;
  147. }
  148. if (string == "oblique") {
  149. result = FontStyle::Oblique;
  150. return;
  151. }
  152. abort();
  153. }
  154. inline std::string toString(const FontStyle &fontStyle) {
  155. switch (fontStyle) {
  156. case FontStyle::Normal:
  157. return "normal";
  158. case FontStyle::Italic:
  159. return "italic";
  160. case FontStyle::Oblique:
  161. return "oblique";
  162. }
  163. }
  164. inline void fromRawValue(const RawValue &value, FontVariant &result) {
  165. assert(value.hasType<std::vector<std::string>>());
  166. result = FontVariant::Default;
  167. auto items = std::vector<std::string>{value};
  168. for (const auto &item : items) {
  169. if (item == "small-caps") {
  170. result = (FontVariant)((int)result | (int)FontVariant::SmallCaps);
  171. continue;
  172. }
  173. if (item == "oldstyle-nums") {
  174. result = (FontVariant)((int)result | (int)FontVariant::OldstyleNums);
  175. continue;
  176. }
  177. if (item == "lining-nums") {
  178. result = (FontVariant)((int)result | (int)FontVariant::LiningNums);
  179. continue;
  180. }
  181. if (item == "tabular-nums") {
  182. result = (FontVariant)((int)result | (int)FontVariant::TabularNums);
  183. continue;
  184. }
  185. if (item == "proportional-nums") {
  186. result = (FontVariant)((int)result | (int)FontVariant::ProportionalNums);
  187. continue;
  188. }
  189. }
  190. }
  191. inline std::string toString(const FontVariant &fontVariant) {
  192. auto result = std::string{};
  193. auto separator = std::string{", "};
  194. if ((int)fontVariant & (int)FontVariant::SmallCaps) {
  195. result += "small-caps" + separator;
  196. }
  197. if ((int)fontVariant & (int)FontVariant::OldstyleNums) {
  198. result += "oldstyle-nums" + separator;
  199. }
  200. if ((int)fontVariant & (int)FontVariant::LiningNums) {
  201. result += "lining-nums" + separator;
  202. }
  203. if ((int)fontVariant & (int)FontVariant::TabularNums) {
  204. result += "tabular-nums" + separator;
  205. }
  206. if ((int)fontVariant & (int)FontVariant::ProportionalNums) {
  207. result += "proportional-nums" + separator;
  208. }
  209. if (!result.empty()) {
  210. result.erase(result.length() - separator.length());
  211. }
  212. return result;
  213. }
  214. inline void fromRawValue(const RawValue &value, TextAlignment &result) {
  215. auto string = (std::string)value;
  216. if (string == "auto") {
  217. result = TextAlignment::Natural;
  218. return;
  219. }
  220. if (string == "left") {
  221. result = TextAlignment::Left;
  222. return;
  223. }
  224. if (string == "center") {
  225. result = TextAlignment::Center;
  226. return;
  227. }
  228. if (string == "right") {
  229. result = TextAlignment::Right;
  230. return;
  231. }
  232. if (string == "justify") {
  233. result = TextAlignment::Justified;
  234. return;
  235. }
  236. abort();
  237. }
  238. inline std::string toString(const TextAlignment &textAlignment) {
  239. switch (textAlignment) {
  240. case TextAlignment::Natural:
  241. return "natural";
  242. case TextAlignment::Left:
  243. return "left";
  244. case TextAlignment::Center:
  245. return "center";
  246. case TextAlignment::Right:
  247. return "right";
  248. case TextAlignment::Justified:
  249. return "justified";
  250. }
  251. }
  252. inline void fromRawValue(const RawValue &value, WritingDirection &result) {
  253. auto string = (std::string)value;
  254. if (string == "natural") {
  255. result = WritingDirection::Natural;
  256. return;
  257. }
  258. if (string == "ltr") {
  259. result = WritingDirection::LeftToRight;
  260. return;
  261. }
  262. if (string == "rtl") {
  263. result = WritingDirection::RightToLeft;
  264. return;
  265. }
  266. abort();
  267. }
  268. inline std::string toString(const WritingDirection &writingDirection) {
  269. switch (writingDirection) {
  270. case WritingDirection::Natural:
  271. return "natural";
  272. case WritingDirection::LeftToRight:
  273. return "ltr";
  274. case WritingDirection::RightToLeft:
  275. return "rtl";
  276. }
  277. }
  278. inline void fromRawValue(
  279. const RawValue &value,
  280. TextDecorationLineType &result) {
  281. auto string = (std::string)value;
  282. if (string == "none") {
  283. result = TextDecorationLineType::None;
  284. return;
  285. }
  286. if (string == "underline") {
  287. result = TextDecorationLineType::Underline;
  288. return;
  289. }
  290. // TODO: remove "line-through" after deprecation
  291. if (string == "strikethrough" || string == "line-through") {
  292. result = TextDecorationLineType::Strikethrough;
  293. return;
  294. }
  295. // TODO: remove "underline line-through" after "line-through" deprecation
  296. if (string == "underline-strikethrough" ||
  297. string == "underline line-through") {
  298. result = TextDecorationLineType::UnderlineStrikethrough;
  299. return;
  300. }
  301. abort();
  302. }
  303. inline std::string toString(
  304. const TextDecorationLineType &textDecorationLineType) {
  305. switch (textDecorationLineType) {
  306. case TextDecorationLineType::None:
  307. return "none";
  308. case TextDecorationLineType::Underline:
  309. return "underline";
  310. case TextDecorationLineType::Strikethrough:
  311. return "strikethrough";
  312. case TextDecorationLineType::UnderlineStrikethrough:
  313. return "underline-strikethrough";
  314. }
  315. }
  316. inline void fromRawValue(
  317. const RawValue &value,
  318. TextDecorationLineStyle &result) {
  319. auto string = (std::string)value;
  320. if (string == "single") {
  321. result = TextDecorationLineStyle::Single;
  322. return;
  323. }
  324. if (string == "thick") {
  325. result = TextDecorationLineStyle::Thick;
  326. return;
  327. }
  328. if (string == "double") {
  329. result = TextDecorationLineStyle::Double;
  330. return;
  331. }
  332. abort();
  333. }
  334. inline std::string toString(
  335. const TextDecorationLineStyle &textDecorationLineStyle) {
  336. switch (textDecorationLineStyle) {
  337. case TextDecorationLineStyle::Single:
  338. return "single";
  339. case TextDecorationLineStyle::Thick:
  340. return "thick";
  341. case TextDecorationLineStyle::Double:
  342. return "double";
  343. }
  344. }
  345. inline void fromRawValue(
  346. const RawValue &value,
  347. TextDecorationLinePattern &result) {
  348. auto string = (std::string)value;
  349. if (string == "solid") {
  350. result = TextDecorationLinePattern::Solid;
  351. return;
  352. }
  353. if (string == "dot") {
  354. result = TextDecorationLinePattern::Dot;
  355. return;
  356. }
  357. if (string == "dash") {
  358. result = TextDecorationLinePattern::Dash;
  359. return;
  360. }
  361. if (string == "dash-dot") {
  362. result = TextDecorationLinePattern::DashDot;
  363. return;
  364. }
  365. if (string == "dash-dot-dot") {
  366. result = TextDecorationLinePattern::DashDotDot;
  367. return;
  368. }
  369. abort();
  370. }
  371. inline std::string toString(
  372. const TextDecorationLinePattern &textDecorationLinePattern) {
  373. switch (textDecorationLinePattern) {
  374. case TextDecorationLinePattern::Solid:
  375. return "solid";
  376. case TextDecorationLinePattern::Dot:
  377. return "dot";
  378. case TextDecorationLinePattern::Dash:
  379. return "dash";
  380. case TextDecorationLinePattern::DashDot:
  381. return "dash-dot";
  382. case TextDecorationLinePattern::DashDotDot:
  383. return "dash-dot-dot";
  384. }
  385. }
  386. inline ParagraphAttributes convertRawProp(
  387. RawProps const &rawProps,
  388. ParagraphAttributes const &sourceParagraphAttributes,
  389. ParagraphAttributes const &defaultParagraphAttributes) {
  390. auto paragraphAttributes = ParagraphAttributes{};
  391. paragraphAttributes.maximumNumberOfLines = convertRawProp(
  392. rawProps,
  393. "numberOfLines",
  394. sourceParagraphAttributes.maximumNumberOfLines,
  395. defaultParagraphAttributes.maximumNumberOfLines);
  396. paragraphAttributes.ellipsizeMode = convertRawProp(
  397. rawProps,
  398. "ellipsizeMode",
  399. sourceParagraphAttributes.ellipsizeMode,
  400. defaultParagraphAttributes.ellipsizeMode);
  401. paragraphAttributes.textBreakStrategy = convertRawProp(
  402. rawProps,
  403. "textBreakStrategy",
  404. sourceParagraphAttributes.textBreakStrategy,
  405. defaultParagraphAttributes.textBreakStrategy);
  406. paragraphAttributes.adjustsFontSizeToFit = convertRawProp(
  407. rawProps,
  408. "adjustsFontSizeToFit",
  409. sourceParagraphAttributes.adjustsFontSizeToFit,
  410. defaultParagraphAttributes.adjustsFontSizeToFit);
  411. paragraphAttributes.minimumFontSize = convertRawProp(
  412. rawProps,
  413. "minimumFontSize",
  414. sourceParagraphAttributes.minimumFontSize,
  415. defaultParagraphAttributes.minimumFontSize);
  416. paragraphAttributes.maximumFontSize = convertRawProp(
  417. rawProps,
  418. "maximumFontSize",
  419. sourceParagraphAttributes.maximumFontSize,
  420. defaultParagraphAttributes.maximumFontSize);
  421. return paragraphAttributes;
  422. }
  423. inline void fromRawValue(
  424. RawValue const &value,
  425. AttributedString::Range &result) {
  426. auto map = (better::map<std::string, int>)value;
  427. auto start = map.find("start");
  428. if (start != map.end()) {
  429. result.location = start->second;
  430. }
  431. auto end = map.find("end");
  432. if (end != map.end()) {
  433. result.length = start->second - result.location;
  434. }
  435. }
  436. inline std::string toString(AttributedString::Range const &range) {
  437. return "{location: " + folly::to<std::string>(range.location) +
  438. ", length: " + folly::to<std::string>(range.length) + "}";
  439. }
  440. #ifdef ANDROID
  441. inline folly::dynamic toDynamic(
  442. const ParagraphAttributes &paragraphAttributes) {
  443. auto values = folly::dynamic::object();
  444. values("maximumNumberOfLines", paragraphAttributes.maximumNumberOfLines);
  445. values("ellipsizeMode", toString(paragraphAttributes.ellipsizeMode));
  446. values("textBreakStrategy", toString(paragraphAttributes.textBreakStrategy));
  447. values("adjustsFontSizeToFit", paragraphAttributes.adjustsFontSizeToFit);
  448. return values;
  449. }
  450. inline folly::dynamic toDynamic(const FontVariant &fontVariant) {
  451. auto result = folly::dynamic::array();
  452. if ((int)fontVariant & (int)FontVariant::SmallCaps) {
  453. result.push_back("small-caps");
  454. }
  455. if ((int)fontVariant & (int)FontVariant::OldstyleNums) {
  456. result.push_back("oldstyle-nums");
  457. }
  458. if ((int)fontVariant & (int)FontVariant::LiningNums) {
  459. result.push_back("lining-nums");
  460. }
  461. if ((int)fontVariant & (int)FontVariant::TabularNums) {
  462. result.push_back("tabular-nums");
  463. }
  464. if ((int)fontVariant & (int)FontVariant::ProportionalNums) {
  465. result.push_back("proportional-nums");
  466. }
  467. return result;
  468. }
  469. inline folly::dynamic toDynamic(const TextAttributes &textAttributes) {
  470. auto _textAttributes = folly::dynamic::object();
  471. if (textAttributes.foregroundColor) {
  472. _textAttributes(
  473. "foregroundColor", toDynamic(textAttributes.foregroundColor));
  474. }
  475. if (textAttributes.backgroundColor) {
  476. _textAttributes(
  477. "backgroundColor", toDynamic(textAttributes.backgroundColor));
  478. }
  479. if (!std::isnan(textAttributes.opacity)) {
  480. _textAttributes("opacity", textAttributes.opacity);
  481. }
  482. if (!textAttributes.fontFamily.empty()) {
  483. _textAttributes("fontFamily", textAttributes.fontFamily);
  484. }
  485. if (!std::isnan(textAttributes.fontSize)) {
  486. _textAttributes("fontSize", textAttributes.fontSize);
  487. }
  488. if (!std::isnan(textAttributes.fontSizeMultiplier)) {
  489. _textAttributes("fontSizeMultiplier", textAttributes.fontSizeMultiplier);
  490. }
  491. if (textAttributes.fontWeight.has_value()) {
  492. _textAttributes("fontWeight", toString(*textAttributes.fontWeight));
  493. }
  494. if (textAttributes.fontStyle.has_value()) {
  495. _textAttributes("fontStyle", toString(*textAttributes.fontStyle));
  496. }
  497. if (textAttributes.fontVariant.has_value()) {
  498. _textAttributes("fontVariant", toDynamic(*textAttributes.fontVariant));
  499. }
  500. if (textAttributes.allowFontScaling.has_value()) {
  501. _textAttributes("allowFontScaling", *textAttributes.allowFontScaling);
  502. }
  503. if (!std::isnan(textAttributes.letterSpacing)) {
  504. _textAttributes("letterSpacing", textAttributes.letterSpacing);
  505. }
  506. if (!std::isnan(textAttributes.lineHeight)) {
  507. _textAttributes("lineHeight", textAttributes.lineHeight);
  508. }
  509. if (textAttributes.alignment.has_value()) {
  510. _textAttributes("alignment", toString(*textAttributes.alignment));
  511. }
  512. if (textAttributes.baseWritingDirection.has_value()) {
  513. _textAttributes(
  514. "baseWritingDirection", toString(*textAttributes.baseWritingDirection));
  515. }
  516. // Decoration
  517. if (textAttributes.textDecorationColor) {
  518. _textAttributes(
  519. "textDecorationColor", toDynamic(textAttributes.textDecorationColor));
  520. }
  521. if (textAttributes.textDecorationLineType.has_value()) {
  522. _textAttributes(
  523. "textDecorationLine", toString(*textAttributes.textDecorationLineType));
  524. }
  525. if (textAttributes.textDecorationLineStyle.has_value()) {
  526. _textAttributes(
  527. "textDecorationLineStyle",
  528. toString(*textAttributes.textDecorationLineStyle));
  529. }
  530. if (textAttributes.textDecorationLinePattern.has_value()) {
  531. _textAttributes(
  532. "textDecorationLinePattern",
  533. toString(*textAttributes.textDecorationLinePattern));
  534. }
  535. // Shadow
  536. // textShadowOffset = textAttributes.textShadowOffset.has_value() ?
  537. // textAttributes.textShadowOffset.value() : textShadowOffset;
  538. if (!std::isnan(textAttributes.textShadowRadius)) {
  539. _textAttributes("textShadowRadius", textAttributes.textShadowRadius);
  540. }
  541. if (textAttributes.textShadowColor) {
  542. _textAttributes(
  543. "textShadowColor", toDynamic(textAttributes.textShadowColor));
  544. }
  545. // Special
  546. if (textAttributes.isHighlighted.has_value()) {
  547. _textAttributes("isHighlighted", *textAttributes.isHighlighted);
  548. }
  549. if (textAttributes.layoutDirection.has_value()) {
  550. _textAttributes(
  551. "layoutDirection", toString(*textAttributes.layoutDirection));
  552. }
  553. return _textAttributes;
  554. }
  555. inline folly::dynamic toDynamic(const AttributedString &attributedString) {
  556. auto value = folly::dynamic::object();
  557. auto fragments = folly::dynamic::array();
  558. for (auto fragment : attributedString.getFragments()) {
  559. folly::dynamic dynamicFragment = folly::dynamic::object();
  560. dynamicFragment["string"] = fragment.string;
  561. if (fragment.parentShadowView.componentHandle) {
  562. dynamicFragment["reactTag"] = fragment.parentShadowView.tag;
  563. }
  564. if (fragment.isAttachment()) {
  565. dynamicFragment["isAttachment"] = true;
  566. dynamicFragment["width"] =
  567. (int)fragment.parentShadowView.layoutMetrics.frame.size.width;
  568. dynamicFragment["height"] =
  569. (int)fragment.parentShadowView.layoutMetrics.frame.size.height;
  570. }
  571. dynamicFragment["textAttributes"] = toDynamic(fragment.textAttributes);
  572. fragments.push_back(dynamicFragment);
  573. }
  574. value("fragments", fragments);
  575. value(
  576. "hash", std::hash<facebook::react::AttributedString>{}(attributedString));
  577. value("string", attributedString.getString());
  578. return value;
  579. }
  580. inline folly::dynamic toDynamic(AttributedString::Range const &range) {
  581. folly::dynamic dynamicValue = folly::dynamic::object();
  582. dynamicValue["location"] = range.location;
  583. dynamicValue["length"] = range.length;
  584. return dynamicValue;
  585. }
  586. #endif
  587. } // namespace react
  588. } // namespace facebook