PageRenderTime 87ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 1ms

/peek-build/src/netdepends/libcss/src/parse/properties/border_outline.c

https://bitbucket.org/C0deMaver1ck/peeklinux
C | 2221 lines | 1438 code | 277 blank | 506 comment | 554 complexity | c005bdfc7d82b82d2632ebaf6a58a7ef MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
  1. /*
  2. * This file is part of LibCSS.
  3. * Licensed under the MIT License,
  4. * http://www.opensource.org/licenses/mit-license.php
  5. * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
  6. */
  7. #include <assert.h>
  8. #include <string.h>
  9. #include "bytecode/bytecode.h"
  10. #include "bytecode/opcodes.h"
  11. #include "parse/properties/properties.h"
  12. #include "parse/properties/utils.h"
  13. enum { SIDE_TOP = 0, SIDE_RIGHT = 1, SIDE_BOTTOM = 2, SIDE_LEFT = 3 };
  14. static css_error parse_border_side(css_language *c,
  15. const parserutils_vector *vector, int *ctx,
  16. uint32_t side, css_style **result);
  17. static css_error parse_border_side_color(css_language *c,
  18. const parserutils_vector *vector, int *ctx,
  19. uint16_t op, css_style **result);
  20. static css_error parse_border_side_style(css_language *c,
  21. const parserutils_vector *vector, int *ctx,
  22. uint16_t op, css_style **result);
  23. static css_error parse_border_side_width(css_language *c,
  24. const parserutils_vector *vector, int *ctx,
  25. uint16_t op, css_style **result);
  26. /**
  27. * Parse border shorthand
  28. *
  29. * \param c Parsing context
  30. * \param vector Vector of tokens to process
  31. * \param ctx Pointer to vector iteration context
  32. * \param result Pointer to location to receive resulting style
  33. * \return CSS_OK on success,
  34. * CSS_NOMEM on memory exhaustion,
  35. * CSS_INVALID if the input is not valid
  36. *
  37. * Post condition: \a *ctx is updated with the next token to process
  38. * If the input is invalid, then \a *ctx remains unchanged.
  39. */
  40. css_error parse_border(css_language *c,
  41. const parserutils_vector *vector, int *ctx,
  42. css_style **result)
  43. {
  44. int orig_ctx = *ctx;
  45. css_style *top = NULL;
  46. css_style *right = NULL;
  47. css_style *bottom = NULL;
  48. css_style *left = NULL;
  49. css_style *ret = NULL;
  50. uint32_t required_size;
  51. css_error error;
  52. error = parse_border_side(c, vector, ctx, SIDE_TOP, &top);
  53. if (error != CSS_OK)
  54. goto cleanup;
  55. *ctx = orig_ctx;
  56. error = parse_border_side(c, vector, ctx, SIDE_RIGHT, &right);
  57. if (error != CSS_OK)
  58. goto cleanup;
  59. *ctx = orig_ctx;
  60. error = parse_border_side(c, vector, ctx, SIDE_BOTTOM, &bottom);
  61. if (error != CSS_OK)
  62. goto cleanup;
  63. *ctx = orig_ctx;
  64. error = parse_border_side(c, vector, ctx, SIDE_LEFT, &left);
  65. if (error != CSS_OK)
  66. goto cleanup;
  67. required_size = top->length + right->length +
  68. bottom->length + left->length;
  69. error = css_stylesheet_style_create(c->sheet, required_size, &ret);
  70. if (error != CSS_OK)
  71. goto cleanup;
  72. required_size = 0;
  73. memcpy(((uint8_t *) ret->bytecode) + required_size,
  74. top->bytecode, top->length);
  75. required_size += top->length;
  76. memcpy(((uint8_t *) ret->bytecode) + required_size,
  77. right->bytecode, right->length);
  78. required_size += right->length;
  79. memcpy(((uint8_t *) ret->bytecode) + required_size,
  80. bottom->bytecode, bottom->length);
  81. required_size += bottom->length;
  82. memcpy(((uint8_t *) ret->bytecode) + required_size,
  83. left->bytecode, left->length);
  84. required_size += left->length;
  85. assert(required_size == ret->length);
  86. *result = ret;
  87. ret = NULL;
  88. /* Clean up after ourselves */
  89. cleanup:
  90. if (top)
  91. css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK);
  92. if (right)
  93. css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK);
  94. if (bottom)
  95. css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK);
  96. if (left)
  97. css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK);
  98. if (ret)
  99. css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK);
  100. if (error != CSS_OK)
  101. *ctx = orig_ctx;
  102. return error;
  103. }
  104. /**
  105. * Parse border-bottom shorthand
  106. *
  107. * \param c Parsing context
  108. * \param vector Vector of tokens to process
  109. * \param ctx Pointer to vector iteration context
  110. * \param result Pointer to location to receive resulting style
  111. * \return CSS_OK on success,
  112. * CSS_NOMEM on memory exhaustion,
  113. * CSS_INVALID if the input is not valid
  114. *
  115. * Post condition: \a *ctx is updated with the next token to process
  116. * If the input is invalid, then \a *ctx remains unchanged.
  117. */
  118. css_error parse_border_bottom(css_language *c,
  119. const parserutils_vector *vector, int *ctx,
  120. css_style **result)
  121. {
  122. return parse_border_side(c, vector, ctx, SIDE_BOTTOM, result);
  123. }
  124. /**
  125. * Parse border-bottom-color
  126. *
  127. * \param c Parsing context
  128. * \param vector Vector of tokens to process
  129. * \param ctx Pointer to vector iteration context
  130. * \param result Pointer to location to receive resulting style
  131. * \return CSS_OK on success,
  132. * CSS_NOMEM on memory exhaustion,
  133. * CSS_INVALID if the input is not valid
  134. *
  135. * Post condition: \a *ctx is updated with the next token to process
  136. * If the input is invalid, then \a *ctx remains unchanged.
  137. */
  138. css_error parse_border_bottom_color(css_language *c,
  139. const parserutils_vector *vector, int *ctx,
  140. css_style **result)
  141. {
  142. return parse_border_side_color(c, vector, ctx,
  143. CSS_PROP_BORDER_BOTTOM_COLOR, result);
  144. }
  145. /**
  146. * Parse border-bottom-style
  147. *
  148. * \param c Parsing context
  149. * \param vector Vector of tokens to process
  150. * \param ctx Pointer to vector iteration context
  151. * \param result Pointer to location to receive resulting style
  152. * \return CSS_OK on success,
  153. * CSS_NOMEM on memory exhaustion,
  154. * CSS_INVALID if the input is not valid
  155. *
  156. * Post condition: \a *ctx is updated with the next token to process
  157. * If the input is invalid, then \a *ctx remains unchanged.
  158. */
  159. css_error parse_border_bottom_style(css_language *c,
  160. const parserutils_vector *vector, int *ctx,
  161. css_style **result)
  162. {
  163. return parse_border_side_style(c, vector, ctx,
  164. CSS_PROP_BORDER_BOTTOM_STYLE, result);
  165. }
  166. /**
  167. * Parse border-bottom-width
  168. *
  169. * \param c Parsing context
  170. * \param vector Vector of tokens to process
  171. * \param ctx Pointer to vector iteration context
  172. * \param result Pointer to location to receive resulting style
  173. * \return CSS_OK on success,
  174. * CSS_NOMEM on memory exhaustion,
  175. * CSS_INVALID if the input is not valid
  176. *
  177. * Post condition: \a *ctx is updated with the next token to process
  178. * If the input is invalid, then \a *ctx remains unchanged.
  179. */
  180. css_error parse_border_bottom_width(css_language *c,
  181. const parserutils_vector *vector, int *ctx,
  182. css_style **result)
  183. {
  184. return parse_border_side_width(c, vector, ctx,
  185. CSS_PROP_BORDER_BOTTOM_WIDTH, result);
  186. }
  187. /**
  188. * Parse border-collapse
  189. *
  190. * \param c Parsing context
  191. * \param vector Vector of tokens to process
  192. * \param ctx Pointer to vector iteration context
  193. * \param result Pointer to location to receive resulting style
  194. * \return CSS_OK on success,
  195. * CSS_NOMEM on memory exhaustion,
  196. * CSS_INVALID if the input is not valid
  197. *
  198. * Post condition: \a *ctx is updated with the next token to process
  199. * If the input is invalid, then \a *ctx remains unchanged.
  200. */
  201. css_error parse_border_collapse(css_language *c,
  202. const parserutils_vector *vector, int *ctx,
  203. css_style **result)
  204. {
  205. int orig_ctx = *ctx;
  206. css_error error;
  207. const css_token *ident;
  208. uint8_t flags = 0;
  209. uint16_t value = 0;
  210. uint32_t opv;
  211. bool match;
  212. /* IDENT (collapse, separate, inherit) */
  213. ident = parserutils_vector_iterate(vector, ctx);
  214. if (ident == NULL || ident->type != CSS_TOKEN_IDENT) {
  215. *ctx = orig_ctx;
  216. return CSS_INVALID;
  217. }
  218. if ((lwc_string_caseless_isequal(
  219. ident->idata, c->strings[INHERIT],
  220. &match) == lwc_error_ok && match)) {
  221. flags |= FLAG_INHERIT;
  222. } else if ((lwc_string_caseless_isequal(
  223. ident->idata, c->strings[COLLAPSE],
  224. &match) == lwc_error_ok && match)) {
  225. value = BORDER_COLLAPSE_COLLAPSE;
  226. } else if ((lwc_string_caseless_isequal(
  227. ident->idata, c->strings[SEPARATE],
  228. &match) == lwc_error_ok && match)) {
  229. value = BORDER_COLLAPSE_SEPARATE;
  230. } else {
  231. *ctx = orig_ctx;
  232. return CSS_INVALID;
  233. }
  234. opv = buildOPV(CSS_PROP_BORDER_COLLAPSE, flags, value);
  235. /* Allocate result */
  236. error = css_stylesheet_style_create(c->sheet, sizeof(opv), result);
  237. if (error != CSS_OK) {
  238. *ctx = orig_ctx;
  239. return error;
  240. }
  241. /* Copy the bytecode to it */
  242. memcpy((*result)->bytecode, &opv, sizeof(opv));
  243. return CSS_OK;
  244. }
  245. /**
  246. * Parse border-color shorthand
  247. *
  248. * \param c Parsing context
  249. * \param vector Vector of tokens to process
  250. * \param ctx Pointer to vector iteration context
  251. * \param result Pointer to location to receive resulting style
  252. * \return CSS_OK on success,
  253. * CSS_NOMEM on memory exhaustion,
  254. * CSS_INVALID if the input is not valid
  255. *
  256. * Post condition: \a *ctx is updated with the next token to process
  257. * If the input is invalid, then \a *ctx remains unchanged.
  258. */
  259. css_error parse_border_color(css_language *c,
  260. const parserutils_vector *vector, int *ctx,
  261. css_style **result)
  262. {
  263. int orig_ctx = *ctx;
  264. int prev_ctx;
  265. const css_token *token;
  266. css_style *top = NULL;
  267. css_style *right = NULL;
  268. css_style *bottom = NULL;
  269. css_style *left = NULL;
  270. css_style *ret = NULL;
  271. uint32_t num_sides = 0;
  272. uint32_t required_size;
  273. bool match;
  274. css_error error;
  275. /* Firstly, handle inherit */
  276. token = parserutils_vector_peek(vector, *ctx);
  277. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  278. (lwc_string_caseless_isequal(
  279. token->idata, c->strings[INHERIT],
  280. &match) == lwc_error_ok && match)) {
  281. uint32_t *bytecode;
  282. error = css_stylesheet_style_create(c->sheet,
  283. 4 * sizeof(uint32_t), &ret);
  284. if (error != CSS_OK) {
  285. *ctx = orig_ctx;
  286. return error;
  287. }
  288. bytecode = (uint32_t *) ret->bytecode;
  289. *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR,
  290. FLAG_INHERIT, 0);
  291. *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR,
  292. FLAG_INHERIT, 0);
  293. *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR,
  294. FLAG_INHERIT, 0);
  295. *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_COLOR,
  296. FLAG_INHERIT, 0);
  297. parserutils_vector_iterate(vector, ctx);
  298. *result = ret;
  299. return CSS_OK;
  300. } else if (token == NULL) {
  301. /* No tokens -- clearly garbage */
  302. *ctx = orig_ctx;
  303. return CSS_INVALID;
  304. }
  305. /* Attempt to parse up to 4 colours */
  306. do {
  307. prev_ctx = *ctx;
  308. error = CSS_OK;
  309. /* Ensure that we're not about to parse another inherit */
  310. token = parserutils_vector_peek(vector, *ctx);
  311. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  312. (lwc_string_caseless_isequal(
  313. token->idata, c->strings[INHERIT],
  314. &match) == lwc_error_ok && match)) {
  315. error = CSS_INVALID;
  316. goto cleanup;
  317. }
  318. if (top == NULL &&
  319. (error = parse_border_side_color(c, vector,
  320. ctx, CSS_PROP_BORDER_TOP_COLOR, &top)) ==
  321. CSS_OK) {
  322. num_sides = 1;
  323. } else if (right == NULL &&
  324. (error = parse_border_side_color(c, vector,
  325. ctx, CSS_PROP_BORDER_RIGHT_COLOR, &right)) ==
  326. CSS_OK) {
  327. num_sides = 2;
  328. } else if (bottom == NULL &&
  329. (error = parse_border_side_color(c, vector,
  330. ctx, CSS_PROP_BORDER_BOTTOM_COLOR, &bottom)) ==
  331. CSS_OK) {
  332. num_sides = 3;
  333. } else if (left == NULL &&
  334. (error = parse_border_side_color(c, vector,
  335. ctx, CSS_PROP_BORDER_LEFT_COLOR, &left)) ==
  336. CSS_OK) {
  337. num_sides = 4;
  338. }
  339. if (error == CSS_OK) {
  340. consumeWhitespace(vector, ctx);
  341. token = parserutils_vector_peek(vector, *ctx);
  342. } else {
  343. /* Forcibly cause loop to exit */
  344. token = NULL;
  345. }
  346. } while (*ctx != prev_ctx && token != NULL);
  347. if (num_sides == 0) {
  348. error = CSS_INVALID;
  349. goto cleanup;
  350. }
  351. /* Calculate size of resultant style */
  352. if (num_sides == 1) {
  353. required_size = 4 * top->length;
  354. } else if (num_sides == 2) {
  355. required_size = 2 * top->length + 2 * right->length;
  356. } else if (num_sides == 3) {
  357. required_size = top->length + 2 * right->length +
  358. bottom->length;
  359. } else {
  360. required_size = top->length + right->length +
  361. bottom->length + left->length;
  362. }
  363. error = css_stylesheet_style_create(c->sheet, required_size, &ret);
  364. if (error != CSS_OK)
  365. goto cleanup;
  366. required_size = 0;
  367. if (num_sides == 1) {
  368. uint32_t *opv = ((uint32_t *) top->bytecode);
  369. uint8_t flags = getFlags(*opv);
  370. uint16_t value = getValue(*opv);
  371. memcpy(((uint8_t *) ret->bytecode) + required_size,
  372. top->bytecode, top->length);
  373. required_size += top->length;
  374. *opv = buildOPV(CSS_PROP_BORDER_RIGHT_COLOR, flags, value);
  375. memcpy(((uint8_t *) ret->bytecode) + required_size,
  376. top->bytecode, top->length);
  377. required_size += top->length;
  378. *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, flags, value);
  379. memcpy(((uint8_t *) ret->bytecode) + required_size,
  380. top->bytecode, top->length);
  381. required_size += top->length;
  382. *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value);
  383. memcpy(((uint8_t *) ret->bytecode) + required_size,
  384. top->bytecode, top->length);
  385. required_size += top->length;
  386. } else if (num_sides == 2) {
  387. uint32_t *vopv = ((uint32_t *) top->bytecode);
  388. uint32_t *hopv = ((uint32_t *) right->bytecode);
  389. uint8_t vflags = getFlags(*vopv);
  390. uint8_t hflags = getFlags(*hopv);
  391. uint16_t vvalue = getValue(*vopv);
  392. uint16_t hvalue = getValue(*hopv);
  393. memcpy(((uint8_t *) ret->bytecode) + required_size,
  394. top->bytecode, top->length);
  395. required_size += top->length;
  396. memcpy(((uint8_t *) ret->bytecode) + required_size,
  397. right->bytecode, right->length);
  398. required_size += right->length;
  399. *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_COLOR, vflags, vvalue);
  400. memcpy(((uint8_t *) ret->bytecode) + required_size,
  401. top->bytecode, top->length);
  402. required_size += top->length;
  403. *hopv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, hflags, hvalue);
  404. memcpy(((uint8_t *) ret->bytecode) + required_size,
  405. right->bytecode, right->length);
  406. required_size += right->length;
  407. } else if (num_sides == 3) {
  408. uint32_t *opv = ((uint32_t *) right->bytecode);
  409. uint8_t flags = getFlags(*opv);
  410. uint16_t value = getValue(*opv);
  411. memcpy(((uint8_t *) ret->bytecode) + required_size,
  412. top->bytecode, top->length);
  413. required_size += top->length;
  414. memcpy(((uint8_t *) ret->bytecode) + required_size,
  415. right->bytecode, right->length);
  416. required_size += right->length;
  417. memcpy(((uint8_t *) ret->bytecode) + required_size,
  418. bottom->bytecode, bottom->length);
  419. required_size += bottom->length;
  420. *opv = buildOPV(CSS_PROP_BORDER_LEFT_COLOR, flags, value);
  421. memcpy(((uint8_t *) ret->bytecode) + required_size,
  422. right->bytecode, right->length);
  423. required_size += right->length;
  424. } else {
  425. memcpy(((uint8_t *) ret->bytecode) + required_size,
  426. top->bytecode, top->length);
  427. required_size += top->length;
  428. memcpy(((uint8_t *) ret->bytecode) + required_size,
  429. right->bytecode, right->length);
  430. required_size += right->length;
  431. memcpy(((uint8_t *) ret->bytecode) + required_size,
  432. bottom->bytecode, bottom->length);
  433. required_size += bottom->length;
  434. memcpy(((uint8_t *) ret->bytecode) + required_size,
  435. left->bytecode, left->length);
  436. required_size += left->length;
  437. }
  438. assert(required_size == ret->length);
  439. /* Write the result */
  440. *result = ret;
  441. /* Invalidate ret, so that cleanup doesn't destroy it */
  442. ret = NULL;
  443. /* Clean up after ourselves */
  444. cleanup:
  445. if (top)
  446. css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK);
  447. if (right)
  448. css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK);
  449. if (bottom)
  450. css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK);
  451. if (left)
  452. css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK);
  453. if (ret)
  454. css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK);
  455. if (error != CSS_OK)
  456. *ctx = orig_ctx;
  457. return error;
  458. }
  459. /**
  460. * Parse border-left shorthand
  461. *
  462. * \param c Parsing context
  463. * \param vector Vector of tokens to process
  464. * \param ctx Pointer to vector iteration context
  465. * \param result Pointer to location to receive resulting style
  466. * \return CSS_OK on success,
  467. * CSS_NOMEM on memory exhaustion,
  468. * CSS_INVALID if the input is not valid
  469. *
  470. * Post condition: \a *ctx is updated with the next token to process
  471. * If the input is invalid, then \a *ctx remains unchanged.
  472. */
  473. css_error parse_border_left(css_language *c,
  474. const parserutils_vector *vector, int *ctx,
  475. css_style **result)
  476. {
  477. return parse_border_side(c, vector, ctx, SIDE_LEFT, result);
  478. }
  479. /**
  480. * Parse border-left-color
  481. *
  482. * \param c Parsing context
  483. * \param vector Vector of tokens to process
  484. * \param ctx Pointer to vector iteration context
  485. * \param result Pointer to location to receive resulting style
  486. * \return CSS_OK on success,
  487. * CSS_NOMEM on memory exhaustion,
  488. * CSS_INVALID if the input is not valid
  489. *
  490. * Post condition: \a *ctx is updated with the next token to process
  491. * If the input is invalid, then \a *ctx remains unchanged.
  492. */
  493. css_error parse_border_left_color(css_language *c,
  494. const parserutils_vector *vector, int *ctx,
  495. css_style **result)
  496. {
  497. return parse_border_side_color(c, vector, ctx,
  498. CSS_PROP_BORDER_LEFT_COLOR, result);
  499. }
  500. /**
  501. * Parse border-left-style
  502. *
  503. * \param c Parsing context
  504. * \param vector Vector of tokens to process
  505. * \param ctx Pointer to vector iteration context
  506. * \param result Pointer to location to receive resulting style
  507. * \return CSS_OK on success,
  508. * CSS_NOMEM on memory exhaustion,
  509. * CSS_INVALID if the input is not valid
  510. *
  511. * Post condition: \a *ctx is updated with the next token to process
  512. * If the input is invalid, then \a *ctx remains unchanged.
  513. */
  514. css_error parse_border_left_style(css_language *c,
  515. const parserutils_vector *vector, int *ctx,
  516. css_style **result)
  517. {
  518. return parse_border_side_style(c, vector, ctx,
  519. CSS_PROP_BORDER_LEFT_STYLE, result);
  520. }
  521. /**
  522. * Parse border-left-width
  523. *
  524. * \param c Parsing context
  525. * \param vector Vector of tokens to process
  526. * \param ctx Pointer to vector iteration context
  527. * \param result Pointer to location to receive resulting style
  528. * \return CSS_OK on success,
  529. * CSS_NOMEM on memory exhaustion,
  530. * CSS_INVALID if the input is not valid
  531. *
  532. * Post condition: \a *ctx is updated with the next token to process
  533. * If the input is invalid, then \a *ctx remains unchanged.
  534. */
  535. css_error parse_border_left_width(css_language *c,
  536. const parserutils_vector *vector, int *ctx,
  537. css_style **result)
  538. {
  539. return parse_border_side_width(c, vector, ctx,
  540. CSS_PROP_BORDER_LEFT_WIDTH, result);
  541. }
  542. /**
  543. * Parse border-right shorthand
  544. *
  545. * \param c Parsing context
  546. * \param vector Vector of tokens to process
  547. * \param ctx Pointer to vector iteration context
  548. * \param result Pointer to location to receive resulting style
  549. * \return CSS_OK on success,
  550. * CSS_NOMEM on memory exhaustion,
  551. * CSS_INVALID if the input is not valid
  552. *
  553. * Post condition: \a *ctx is updated with the next token to process
  554. * If the input is invalid, then \a *ctx remains unchanged.
  555. */
  556. css_error parse_border_right(css_language *c,
  557. const parserutils_vector *vector, int *ctx,
  558. css_style **result)
  559. {
  560. return parse_border_side(c, vector, ctx, SIDE_RIGHT, result);
  561. }
  562. /**
  563. * Parse border-right-color
  564. *
  565. * \param c Parsing context
  566. * \param vector Vector of tokens to process
  567. * \param ctx Pointer to vector iteration context
  568. * \param result Pointer to location to receive resulting style
  569. * \return CSS_OK on success,
  570. * CSS_NOMEM on memory exhaustion,
  571. * CSS_INVALID if the input is not valid
  572. *
  573. * Post condition: \a *ctx is updated with the next token to process
  574. * If the input is invalid, then \a *ctx remains unchanged.
  575. */
  576. css_error parse_border_right_color(css_language *c,
  577. const parserutils_vector *vector, int *ctx,
  578. css_style **result)
  579. {
  580. return parse_border_side_color(c, vector, ctx,
  581. CSS_PROP_BORDER_RIGHT_COLOR, result);
  582. }
  583. /**
  584. * Parse border-right-style
  585. *
  586. * \param c Parsing context
  587. * \param vector Vector of tokens to process
  588. * \param ctx Pointer to vector iteration context
  589. * \param result Pointer to location to receive resulting style
  590. * \return CSS_OK on success,
  591. * CSS_NOMEM on memory exhaustion,
  592. * CSS_INVALID if the input is not valid
  593. *
  594. * Post condition: \a *ctx is updated with the next token to process
  595. * If the input is invalid, then \a *ctx remains unchanged.
  596. */
  597. css_error parse_border_right_style(css_language *c,
  598. const parserutils_vector *vector, int *ctx,
  599. css_style **result)
  600. {
  601. return parse_border_side_style(c, vector, ctx,
  602. CSS_PROP_BORDER_RIGHT_STYLE, result);
  603. }
  604. /**
  605. * Parse border-right-width
  606. *
  607. * \param c Parsing context
  608. * \param vector Vector of tokens to process
  609. * \param ctx Pointer to vector iteration context
  610. * \param result Pointer to location to receive resulting style
  611. * \return CSS_OK on success,
  612. * CSS_NOMEM on memory exhaustion,
  613. * CSS_INVALID if the input is not valid
  614. *
  615. * Post condition: \a *ctx is updated with the next token to process
  616. * If the input is invalid, then \a *ctx remains unchanged.
  617. */
  618. css_error parse_border_right_width(css_language *c,
  619. const parserutils_vector *vector, int *ctx,
  620. css_style **result)
  621. {
  622. return parse_border_side_width(c, vector, ctx,
  623. CSS_PROP_BORDER_RIGHT_WIDTH, result);
  624. }
  625. /**
  626. * Parse border-spacing
  627. *
  628. * \param c Parsing context
  629. * \param vector Vector of tokens to process
  630. * \param ctx Pointer to vector iteration context
  631. * \param result Pointer to location to receive resulting style
  632. * \return CSS_OK on success,
  633. * CSS_NOMEM on memory exhaustion,
  634. * CSS_INVALID if the input is not valid
  635. *
  636. * Post condition: \a *ctx is updated with the next token to process
  637. * If the input is invalid, then \a *ctx remains unchanged.
  638. */
  639. css_error parse_border_spacing(css_language *c,
  640. const parserutils_vector *vector, int *ctx,
  641. css_style **result)
  642. {
  643. int orig_ctx = *ctx;
  644. css_error error;
  645. const css_token *token;
  646. uint8_t flags = 0;
  647. uint16_t value = 0;
  648. uint32_t opv;
  649. css_fixed length[2] = { 0 };
  650. uint32_t unit[2] = { 0 };
  651. uint32_t required_size;
  652. bool match;
  653. /* length length? | IDENT(inherit) */
  654. token = parserutils_vector_peek(vector, *ctx);
  655. if (token == NULL) {
  656. *ctx = orig_ctx;
  657. return CSS_INVALID;
  658. }
  659. if (token->type == CSS_TOKEN_IDENT &&
  660. (lwc_string_caseless_isequal(
  661. token->idata, c->strings[INHERIT],
  662. &match) == lwc_error_ok && match)) {
  663. parserutils_vector_iterate(vector, ctx);
  664. flags = FLAG_INHERIT;
  665. } else {
  666. int num_lengths = 0;
  667. error = parse_unit_specifier(c, vector, ctx, UNIT_PX,
  668. &length[0], &unit[0]);
  669. if (error != CSS_OK) {
  670. *ctx = orig_ctx;
  671. return error;
  672. }
  673. if (unit[0] & UNIT_ANGLE || unit[0] & UNIT_TIME ||
  674. unit[0] & UNIT_FREQ || unit[0] & UNIT_PCT) {
  675. *ctx = orig_ctx;
  676. return CSS_INVALID;
  677. }
  678. num_lengths = 1;
  679. consumeWhitespace(vector, ctx);
  680. token = parserutils_vector_peek(vector, *ctx);
  681. if (token != NULL) {
  682. /* Attempt second length, ignoring errors.
  683. * The core !important parser will ensure
  684. * any remaining junk is thrown out.
  685. * Ctx will be preserved on error, as usual
  686. */
  687. error = parse_unit_specifier(c, vector, ctx, UNIT_PX,
  688. &length[1], &unit[1]);
  689. if (error == CSS_OK) {
  690. if (unit[1] & UNIT_ANGLE ||
  691. unit[1] & UNIT_TIME ||
  692. unit[1] & UNIT_FREQ ||
  693. unit[1] & UNIT_PCT) {
  694. *ctx = orig_ctx;
  695. return CSS_INVALID;
  696. }
  697. num_lengths = 2;
  698. }
  699. }
  700. if (num_lengths == 1) {
  701. /* Only one length specified. Use for both axes. */
  702. length[1] = length[0];
  703. unit[1] = unit[0];
  704. }
  705. /* Lengths must not be negative */
  706. if (length[0] < 0 || length[1] < 0) {
  707. *ctx = orig_ctx;
  708. return CSS_INVALID;
  709. }
  710. value = BORDER_SPACING_SET;
  711. }
  712. opv = buildOPV(CSS_PROP_BORDER_SPACING, flags, value);
  713. required_size = sizeof(opv);
  714. if ((flags & FLAG_INHERIT) == false && value == BORDER_SPACING_SET)
  715. required_size += 2 * (sizeof(length[0]) + sizeof(unit[0]));
  716. /* Allocate result */
  717. error = css_stylesheet_style_create(c->sheet, required_size, result);
  718. if (error != CSS_OK) {
  719. *ctx = orig_ctx;
  720. return error;
  721. }
  722. /* Copy the bytecode to it */
  723. memcpy((*result)->bytecode, &opv, sizeof(opv));
  724. if ((flags & FLAG_INHERIT) == false && value == BORDER_SPACING_SET) {
  725. uint8_t *ptr = ((uint8_t *) (*result)->bytecode) + sizeof(opv);
  726. memcpy(ptr, &length[0], sizeof(length[0]));
  727. ptr += sizeof(length[0]);
  728. memcpy(ptr, &unit[0], sizeof(unit[0]));
  729. ptr += sizeof(unit[0]);
  730. memcpy(ptr, &length[1], sizeof(length[1]));
  731. ptr += sizeof(length[1]);
  732. memcpy(ptr, &unit[1], sizeof(unit[1]));
  733. }
  734. return CSS_OK;
  735. }
  736. /**
  737. * Parse border-style shorthand
  738. *
  739. * \param c Parsing context
  740. * \param vector Vector of tokens to process
  741. * \param ctx Pointer to vector iteration context
  742. * \param result Pointer to location to receive resulting style
  743. * \return CSS_OK on success,
  744. * CSS_NOMEM on memory exhaustion,
  745. * CSS_INVALID if the input is not valid
  746. *
  747. * Post condition: \a *ctx is updated with the next token to process
  748. * If the input is invalid, then \a *ctx remains unchanged.
  749. */
  750. css_error parse_border_style(css_language *c,
  751. const parserutils_vector *vector, int *ctx,
  752. css_style **result)
  753. {
  754. int orig_ctx = *ctx;
  755. int prev_ctx;
  756. const css_token *token;
  757. css_style *top = NULL;
  758. css_style *right = NULL;
  759. css_style *bottom = NULL;
  760. css_style *left = NULL;
  761. css_style *ret = NULL;
  762. uint32_t num_sides = 0;
  763. uint32_t required_size;
  764. bool match;
  765. css_error error;
  766. /* Firstly, handle inherit */
  767. token = parserutils_vector_peek(vector, *ctx);
  768. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  769. (lwc_string_caseless_isequal(
  770. token->idata, c->strings[INHERIT],
  771. &match) == lwc_error_ok && match)) {
  772. uint32_t *bytecode;
  773. error = css_stylesheet_style_create(c->sheet,
  774. 4 * sizeof(uint32_t), &ret);
  775. if (error != CSS_OK) {
  776. *ctx = orig_ctx;
  777. return error;
  778. }
  779. bytecode = (uint32_t *) ret->bytecode;
  780. *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE,
  781. FLAG_INHERIT, 0);
  782. *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE,
  783. FLAG_INHERIT, 0);
  784. *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE,
  785. FLAG_INHERIT, 0);
  786. *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_STYLE,
  787. FLAG_INHERIT, 0);
  788. parserutils_vector_iterate(vector, ctx);
  789. *result = ret;
  790. return CSS_OK;
  791. } else if (token == NULL) {
  792. /* No tokens -- clearly garbage */
  793. *ctx = orig_ctx;
  794. return CSS_INVALID;
  795. }
  796. /* Attempt to parse up to 4 styles */
  797. do {
  798. prev_ctx = *ctx;
  799. error = CSS_OK;
  800. /* Ensure that we're not about to parse another inherit */
  801. token = parserutils_vector_peek(vector, *ctx);
  802. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  803. (lwc_string_caseless_isequal(
  804. token->idata, c->strings[INHERIT],
  805. &match) == lwc_error_ok && match)) {
  806. error = CSS_INVALID;
  807. goto cleanup;
  808. }
  809. if (top == NULL &&
  810. (error = parse_border_side_style(c, vector,
  811. ctx, CSS_PROP_BORDER_TOP_STYLE, &top)) ==
  812. CSS_OK) {
  813. num_sides = 1;
  814. } else if (right == NULL &&
  815. (error = parse_border_side_style(c, vector,
  816. ctx, CSS_PROP_BORDER_RIGHT_STYLE, &right)) ==
  817. CSS_OK) {
  818. num_sides = 2;
  819. } else if (bottom == NULL &&
  820. (error = parse_border_side_style(c, vector,
  821. ctx, CSS_PROP_BORDER_BOTTOM_STYLE, &bottom)) ==
  822. CSS_OK) {
  823. num_sides = 3;
  824. } else if (left == NULL &&
  825. (error = parse_border_side_style(c, vector,
  826. ctx, CSS_PROP_BORDER_LEFT_STYLE, &left)) ==
  827. CSS_OK) {
  828. num_sides = 4;
  829. }
  830. if (error == CSS_OK) {
  831. consumeWhitespace(vector, ctx);
  832. token = parserutils_vector_peek(vector, *ctx);
  833. } else {
  834. /* Forcibly cause loop to exit */
  835. token = NULL;
  836. }
  837. } while (*ctx != prev_ctx && token != NULL);
  838. if (num_sides == 0) {
  839. error = CSS_INVALID;
  840. goto cleanup;
  841. }
  842. /* Calculate size of resultant style */
  843. if (num_sides == 1) {
  844. required_size = 4 * top->length;
  845. } else if (num_sides == 2) {
  846. required_size = 2 * top->length + 2 * right->length;
  847. } else if (num_sides == 3) {
  848. required_size = top->length + 2 * right->length +
  849. bottom->length;
  850. } else {
  851. required_size = top->length + right->length +
  852. bottom->length + left->length;
  853. }
  854. error = css_stylesheet_style_create(c->sheet, required_size, &ret);
  855. if (error != CSS_OK)
  856. goto cleanup;
  857. required_size = 0;
  858. if (num_sides == 1) {
  859. uint32_t *opv = ((uint32_t *) top->bytecode);
  860. uint8_t flags = getFlags(*opv);
  861. uint16_t value = getValue(*opv);
  862. memcpy(((uint8_t *) ret->bytecode) + required_size,
  863. top->bytecode, top->length);
  864. required_size += top->length;
  865. *opv = buildOPV(CSS_PROP_BORDER_RIGHT_STYLE, flags, value);
  866. memcpy(((uint8_t *) ret->bytecode) + required_size,
  867. top->bytecode, top->length);
  868. required_size += top->length;
  869. *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, flags, value);
  870. memcpy(((uint8_t *) ret->bytecode) + required_size,
  871. top->bytecode, top->length);
  872. required_size += top->length;
  873. *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value);
  874. memcpy(((uint8_t *) ret->bytecode) + required_size,
  875. top->bytecode, top->length);
  876. required_size += top->length;
  877. } else if (num_sides == 2) {
  878. uint32_t *vopv = ((uint32_t *) top->bytecode);
  879. uint32_t *hopv = ((uint32_t *) right->bytecode);
  880. uint8_t vflags = getFlags(*vopv);
  881. uint8_t hflags = getFlags(*hopv);
  882. uint16_t vvalue = getValue(*vopv);
  883. uint16_t hvalue = getValue(*hopv);
  884. memcpy(((uint8_t *) ret->bytecode) + required_size,
  885. top->bytecode, top->length);
  886. required_size += top->length;
  887. memcpy(((uint8_t *) ret->bytecode) + required_size,
  888. right->bytecode, right->length);
  889. required_size += right->length;
  890. *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_STYLE, vflags, vvalue);
  891. memcpy(((uint8_t *) ret->bytecode) + required_size,
  892. top->bytecode, top->length);
  893. required_size += top->length;
  894. *hopv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, hflags, hvalue);
  895. memcpy(((uint8_t *) ret->bytecode) + required_size,
  896. right->bytecode, right->length);
  897. required_size += right->length;
  898. } else if (num_sides == 3) {
  899. uint32_t *opv = ((uint32_t *) right->bytecode);
  900. uint8_t flags = getFlags(*opv);
  901. uint16_t value = getValue(*opv);
  902. memcpy(((uint8_t *) ret->bytecode) + required_size,
  903. top->bytecode, top->length);
  904. required_size += top->length;
  905. memcpy(((uint8_t *) ret->bytecode) + required_size,
  906. right->bytecode, right->length);
  907. required_size += right->length;
  908. memcpy(((uint8_t *) ret->bytecode) + required_size,
  909. bottom->bytecode, bottom->length);
  910. required_size += bottom->length;
  911. *opv = buildOPV(CSS_PROP_BORDER_LEFT_STYLE, flags, value);
  912. memcpy(((uint8_t *) ret->bytecode) + required_size,
  913. right->bytecode, right->length);
  914. required_size += right->length;
  915. } else {
  916. memcpy(((uint8_t *) ret->bytecode) + required_size,
  917. top->bytecode, top->length);
  918. required_size += top->length;
  919. memcpy(((uint8_t *) ret->bytecode) + required_size,
  920. right->bytecode, right->length);
  921. required_size += right->length;
  922. memcpy(((uint8_t *) ret->bytecode) + required_size,
  923. bottom->bytecode, bottom->length);
  924. required_size += bottom->length;
  925. memcpy(((uint8_t *) ret->bytecode) + required_size,
  926. left->bytecode, left->length);
  927. required_size += left->length;
  928. }
  929. assert(required_size == ret->length);
  930. /* Write the result */
  931. *result = ret;
  932. /* Invalidate ret, so that cleanup doesn't destroy it */
  933. ret = NULL;
  934. /* Clean up after ourselves */
  935. cleanup:
  936. if (top)
  937. css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK);
  938. if (right)
  939. css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK);
  940. if (bottom)
  941. css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK);
  942. if (left)
  943. css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK);
  944. if (ret)
  945. css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK);
  946. if (error != CSS_OK)
  947. *ctx = orig_ctx;
  948. return error;
  949. }
  950. /**
  951. * Parse border-top shorthand
  952. *
  953. * \param c Parsing context
  954. * \param vector Vector of tokens to process
  955. * \param ctx Pointer to vector iteration context
  956. * \param result Pointer to location to receive resulting style
  957. * \return CSS_OK on success,
  958. * CSS_NOMEM on memory exhaustion,
  959. * CSS_INVALID if the input is not valid
  960. *
  961. * Post condition: \a *ctx is updated with the next token to process
  962. * If the input is invalid, then \a *ctx remains unchanged.
  963. */
  964. css_error parse_border_top(css_language *c,
  965. const parserutils_vector *vector, int *ctx,
  966. css_style **result)
  967. {
  968. return parse_border_side(c, vector, ctx, SIDE_TOP, result);
  969. }
  970. /**
  971. * Parse border-top-color
  972. *
  973. * \param c Parsing context
  974. * \param vector Vector of tokens to process
  975. * \param ctx Pointer to vector iteration context
  976. * \param result Pointer to location to receive resulting style
  977. * \return CSS_OK on success,
  978. * CSS_NOMEM on memory exhaustion,
  979. * CSS_INVALID if the input is not valid
  980. *
  981. * Post condition: \a *ctx is updated with the next token to process
  982. * If the input is invalid, then \a *ctx remains unchanged.
  983. */
  984. css_error parse_border_top_color(css_language *c,
  985. const parserutils_vector *vector, int *ctx,
  986. css_style **result)
  987. {
  988. return parse_border_side_color(c, vector, ctx,
  989. CSS_PROP_BORDER_TOP_COLOR, result);
  990. }
  991. /**
  992. * Parse border-top-style
  993. *
  994. * \param c Parsing context
  995. * \param vector Vector of tokens to process
  996. * \param ctx Pointer to vector iteration context
  997. * \param result Pointer to location to receive resulting style
  998. * \return CSS_OK on success,
  999. * CSS_NOMEM on memory exhaustion,
  1000. * CSS_INVALID if the input is not valid
  1001. *
  1002. * Post condition: \a *ctx is updated with the next token to process
  1003. * If the input is invalid, then \a *ctx remains unchanged.
  1004. */
  1005. css_error parse_border_top_style(css_language *c,
  1006. const parserutils_vector *vector, int *ctx,
  1007. css_style **result)
  1008. {
  1009. return parse_border_side_style(c, vector, ctx,
  1010. CSS_PROP_BORDER_TOP_STYLE, result);
  1011. }
  1012. /**
  1013. * Parse border-top-width
  1014. *
  1015. * \param c Parsing context
  1016. * \param vector Vector of tokens to process
  1017. * \param ctx Pointer to vector iteration context
  1018. * \param result Pointer to location to receive resulting style
  1019. * \return CSS_OK on success,
  1020. * CSS_NOMEM on memory exhaustion,
  1021. * CSS_INVALID if the input is not valid
  1022. *
  1023. * Post condition: \a *ctx is updated with the next token to process
  1024. * If the input is invalid, then \a *ctx remains unchanged.
  1025. */
  1026. css_error parse_border_top_width(css_language *c,
  1027. const parserutils_vector *vector, int *ctx,
  1028. css_style **result)
  1029. {
  1030. return parse_border_side_width(c, vector, ctx,
  1031. CSS_PROP_BORDER_TOP_WIDTH, result);
  1032. }
  1033. /**
  1034. * Parse border-width shorthand
  1035. *
  1036. * \param c Parsing context
  1037. * \param vector Vector of tokens to process
  1038. * \param ctx Pointer to vector iteration context
  1039. * \param result Pointer to location to receive resulting style
  1040. * \return CSS_OK on success,
  1041. * CSS_NOMEM on memory exhaustion,
  1042. * CSS_INVALID if the input is not valid
  1043. *
  1044. * Post condition: \a *ctx is updated with the next token to process
  1045. * If the input is invalid, then \a *ctx remains unchanged.
  1046. */
  1047. css_error parse_border_width(css_language *c,
  1048. const parserutils_vector *vector, int *ctx,
  1049. css_style **result)
  1050. {
  1051. int orig_ctx = *ctx;
  1052. int prev_ctx;
  1053. const css_token *token;
  1054. css_style *top = NULL;
  1055. css_style *right = NULL;
  1056. css_style *bottom = NULL;
  1057. css_style *left = NULL;
  1058. css_style *ret = NULL;
  1059. uint32_t num_sides = 0;
  1060. uint32_t required_size;
  1061. bool match;
  1062. css_error error;
  1063. /* Firstly, handle inherit */
  1064. token = parserutils_vector_peek(vector, *ctx);
  1065. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  1066. (lwc_string_caseless_isequal(
  1067. token->idata, c->strings[INHERIT],
  1068. &match) == lwc_error_ok && match)) {
  1069. uint32_t *bytecode;
  1070. error = css_stylesheet_style_create(c->sheet,
  1071. 4 * sizeof(uint32_t), &ret);
  1072. if (error != CSS_OK) {
  1073. *ctx = orig_ctx;
  1074. return error;
  1075. }
  1076. bytecode = (uint32_t *) ret->bytecode;
  1077. *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH,
  1078. FLAG_INHERIT, 0);
  1079. *(bytecode++) = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH,
  1080. FLAG_INHERIT, 0);
  1081. *(bytecode++) = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH,
  1082. FLAG_INHERIT, 0);
  1083. *(bytecode++) = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH,
  1084. FLAG_INHERIT, 0);
  1085. parserutils_vector_iterate(vector, ctx);
  1086. *result = ret;
  1087. return CSS_OK;
  1088. } else if (token == NULL) {
  1089. /* No tokens -- clearly garbage */
  1090. *ctx = orig_ctx;
  1091. return CSS_INVALID;
  1092. }
  1093. /* Attempt to parse up to 4 widths */
  1094. do {
  1095. prev_ctx = *ctx;
  1096. error = CSS_OK;
  1097. /* Ensure that we're not about to parse another inherit */
  1098. token = parserutils_vector_peek(vector, *ctx);
  1099. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  1100. (lwc_string_caseless_isequal(
  1101. token->idata, c->strings[INHERIT],
  1102. &match) == lwc_error_ok && match)) {
  1103. error = CSS_INVALID;
  1104. goto cleanup;
  1105. }
  1106. if (top == NULL &&
  1107. (error = parse_border_side_width(c, vector,
  1108. ctx, CSS_PROP_BORDER_TOP_WIDTH, &top)) ==
  1109. CSS_OK) {
  1110. num_sides = 1;
  1111. } else if (right == NULL &&
  1112. (error = parse_border_side_width(c, vector,
  1113. ctx, CSS_PROP_BORDER_RIGHT_WIDTH, &right)) ==
  1114. CSS_OK) {
  1115. num_sides = 2;
  1116. } else if (bottom == NULL &&
  1117. (error = parse_border_side_width(c, vector,
  1118. ctx, CSS_PROP_BORDER_BOTTOM_WIDTH, &bottom)) ==
  1119. CSS_OK) {
  1120. num_sides = 3;
  1121. } else if (left == NULL &&
  1122. (error = parse_border_side_width(c, vector,
  1123. ctx, CSS_PROP_BORDER_LEFT_WIDTH, &left)) ==
  1124. CSS_OK) {
  1125. num_sides = 4;
  1126. }
  1127. if (error == CSS_OK) {
  1128. consumeWhitespace(vector, ctx);
  1129. token = parserutils_vector_peek(vector, *ctx);
  1130. } else {
  1131. /* Forcibly cause loop to exit */
  1132. token = NULL;
  1133. }
  1134. } while (*ctx != prev_ctx && token != NULL);
  1135. if (num_sides == 0) {
  1136. error = CSS_INVALID;
  1137. goto cleanup;
  1138. }
  1139. /* Calculate size of resultant style */
  1140. if (num_sides == 1) {
  1141. required_size = 4 * top->length;
  1142. } else if (num_sides == 2) {
  1143. required_size = 2 * top->length + 2 * right->length;
  1144. } else if (num_sides == 3) {
  1145. required_size = top->length + 2 * right->length +
  1146. bottom->length;
  1147. } else {
  1148. required_size = top->length + right->length +
  1149. bottom->length + left->length;
  1150. }
  1151. error = css_stylesheet_style_create(c->sheet, required_size, &ret);
  1152. if (error != CSS_OK)
  1153. goto cleanup;
  1154. required_size = 0;
  1155. if (num_sides == 1) {
  1156. uint32_t *opv = ((uint32_t *) top->bytecode);
  1157. uint8_t flags = getFlags(*opv);
  1158. uint16_t value = getValue(*opv);
  1159. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1160. top->bytecode, top->length);
  1161. required_size += top->length;
  1162. *opv = buildOPV(CSS_PROP_BORDER_RIGHT_WIDTH, flags, value);
  1163. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1164. top->bytecode, top->length);
  1165. required_size += top->length;
  1166. *opv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, flags, value);
  1167. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1168. top->bytecode, top->length);
  1169. required_size += top->length;
  1170. *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value);
  1171. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1172. top->bytecode, top->length);
  1173. required_size += top->length;
  1174. } else if (num_sides == 2) {
  1175. uint32_t *vopv = ((uint32_t *) top->bytecode);
  1176. uint32_t *hopv = ((uint32_t *) right->bytecode);
  1177. uint8_t vflags = getFlags(*vopv);
  1178. uint8_t hflags = getFlags(*hopv);
  1179. uint16_t vvalue = getValue(*vopv);
  1180. uint16_t hvalue = getValue(*hopv);
  1181. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1182. top->bytecode, top->length);
  1183. required_size += top->length;
  1184. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1185. right->bytecode, right->length);
  1186. required_size += right->length;
  1187. *vopv = buildOPV(CSS_PROP_BORDER_BOTTOM_WIDTH, vflags, vvalue);
  1188. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1189. top->bytecode, top->length);
  1190. required_size += top->length;
  1191. *hopv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, hflags, hvalue);
  1192. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1193. right->bytecode, right->length);
  1194. required_size += right->length;
  1195. } else if (num_sides == 3) {
  1196. uint32_t *opv = ((uint32_t *) right->bytecode);
  1197. uint8_t flags = getFlags(*opv);
  1198. uint16_t value = getValue(*opv);
  1199. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1200. top->bytecode, top->length);
  1201. required_size += top->length;
  1202. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1203. right->bytecode, right->length);
  1204. required_size += right->length;
  1205. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1206. bottom->bytecode, bottom->length);
  1207. required_size += bottom->length;
  1208. *opv = buildOPV(CSS_PROP_BORDER_LEFT_WIDTH, flags, value);
  1209. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1210. right->bytecode, right->length);
  1211. required_size += right->length;
  1212. } else {
  1213. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1214. top->bytecode, top->length);
  1215. required_size += top->length;
  1216. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1217. right->bytecode, right->length);
  1218. required_size += right->length;
  1219. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1220. bottom->bytecode, bottom->length);
  1221. required_size += bottom->length;
  1222. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1223. left->bytecode, left->length);
  1224. required_size += left->length;
  1225. }
  1226. assert(required_size == ret->length);
  1227. /* Write the result */
  1228. *result = ret;
  1229. /* Invalidate ret, so that cleanup doesn't destroy it */
  1230. ret = NULL;
  1231. /* Clean up after ourselves */
  1232. cleanup:
  1233. if (top)
  1234. css_stylesheet_style_destroy(c->sheet, top, error == CSS_OK);
  1235. if (right)
  1236. css_stylesheet_style_destroy(c->sheet, right, error == CSS_OK);
  1237. if (bottom)
  1238. css_stylesheet_style_destroy(c->sheet, bottom, error == CSS_OK);
  1239. if (left)
  1240. css_stylesheet_style_destroy(c->sheet, left, error == CSS_OK);
  1241. if (ret)
  1242. css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK);
  1243. if (error != CSS_OK)
  1244. *ctx = orig_ctx;
  1245. return error;
  1246. }
  1247. /**
  1248. * Parse outline shorthand
  1249. *
  1250. * \param c Parsing context
  1251. * \param vector Vector of tokens to process
  1252. * \param ctx Pointer to vector iteration context
  1253. * \param result Pointer to location to receive resulting style
  1254. * \return CSS_OK on success,
  1255. * CSS_NOMEM on memory exhaustion,
  1256. * CSS_INVALID if the input is not valid
  1257. *
  1258. * Post condition: \a *ctx is updated with the next token to process
  1259. * If the input is invalid, then \a *ctx remains unchanged.
  1260. */
  1261. css_error parse_outline(css_language *c,
  1262. const parserutils_vector *vector, int *ctx,
  1263. css_style **result)
  1264. {
  1265. int orig_ctx = *ctx;
  1266. int prev_ctx;
  1267. const css_token *token;
  1268. css_style *color = NULL;
  1269. css_style *style = NULL;
  1270. css_style *width = NULL;
  1271. css_style *ret = NULL;
  1272. uint32_t required_size;
  1273. bool match;
  1274. css_error error;
  1275. /* Firstly, handle inherit */
  1276. token = parserutils_vector_peek(vector, *ctx);
  1277. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  1278. (lwc_string_caseless_isequal(
  1279. token->idata, c->strings[INHERIT],
  1280. &match) == lwc_error_ok && match)) {
  1281. uint32_t *bytecode;
  1282. error = css_stylesheet_style_create(c->sheet,
  1283. 3 * sizeof(uint32_t), &ret);
  1284. if (error != CSS_OK) {
  1285. *ctx = orig_ctx;
  1286. return error;
  1287. }
  1288. bytecode = (uint32_t *) ret->bytecode;
  1289. *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_COLOR,
  1290. FLAG_INHERIT, 0);
  1291. *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_STYLE,
  1292. FLAG_INHERIT, 0);
  1293. *(bytecode++) = buildOPV(CSS_PROP_OUTLINE_WIDTH,
  1294. FLAG_INHERIT, 0);
  1295. parserutils_vector_iterate(vector, ctx);
  1296. *result = ret;
  1297. return CSS_OK;
  1298. } else if (token == NULL) {
  1299. /* No tokens -- clearly garbage */
  1300. *ctx = orig_ctx;
  1301. return CSS_INVALID;
  1302. }
  1303. /* Attempt to parse individual properties */
  1304. do {
  1305. prev_ctx = *ctx;
  1306. error = CSS_OK;
  1307. /* Ensure that we're not about to parse another inherit */
  1308. token = parserutils_vector_peek(vector, *ctx);
  1309. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  1310. (lwc_string_caseless_isequal(
  1311. token->idata, c->strings[INHERIT],
  1312. &match) == lwc_error_ok && match)) {
  1313. error = CSS_INVALID;
  1314. goto cleanup;
  1315. }
  1316. if (color == NULL &&
  1317. (error = parse_outline_color(c, vector,
  1318. ctx, &color)) == CSS_OK) {
  1319. } else if (style == NULL &&
  1320. (error = parse_outline_style(c, vector,
  1321. ctx, &style)) == CSS_OK) {
  1322. } else if (width == NULL &&
  1323. (error = parse_outline_width(c, vector,
  1324. ctx, &width)) == CSS_OK) {
  1325. }
  1326. if (error == CSS_OK) {
  1327. consumeWhitespace(vector, ctx);
  1328. token = parserutils_vector_peek(vector, *ctx);
  1329. } else {
  1330. /* Forcibly cause loop to exit */
  1331. token = NULL;
  1332. }
  1333. } while (*ctx != prev_ctx && token != NULL);
  1334. /* Calculate size of resultant style */
  1335. required_size = 0;
  1336. if (color)
  1337. required_size += color->length;
  1338. else
  1339. required_size += sizeof(uint32_t);
  1340. if (style)
  1341. required_size += style->length;
  1342. else
  1343. required_size += sizeof(uint32_t);
  1344. if (width)
  1345. required_size += width->length;
  1346. else
  1347. required_size += sizeof(uint32_t);
  1348. error = css_stylesheet_style_create(c->sheet, required_size, &ret);
  1349. if (error != CSS_OK)
  1350. goto cleanup;
  1351. required_size = 0;
  1352. if (color) {
  1353. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1354. color->bytecode, color->length);
  1355. required_size += color->length;
  1356. } else {
  1357. void *bc = ((uint8_t *) ret->bytecode) + required_size;
  1358. *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_COLOR,
  1359. 0, OUTLINE_COLOR_INVERT);
  1360. required_size += sizeof(uint32_t);
  1361. }
  1362. if (style) {
  1363. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1364. style->bytecode, style->length);
  1365. required_size += style->length;
  1366. } else {
  1367. void *bc = ((uint8_t *) ret->bytecode) + required_size;
  1368. *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_STYLE,
  1369. 0, OUTLINE_STYLE_NONE);
  1370. required_size += sizeof(uint32_t);
  1371. }
  1372. if (width) {
  1373. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1374. width->bytecode, width->length);
  1375. required_size += width->length;
  1376. } else {
  1377. void *bc = ((uint8_t *) ret->bytecode) + required_size;
  1378. *((uint32_t *) bc) = buildOPV(CSS_PROP_OUTLINE_WIDTH,
  1379. 0, OUTLINE_WIDTH_MEDIUM);
  1380. required_size += sizeof(uint32_t);
  1381. }
  1382. assert(required_size == ret->length);
  1383. /* Write the result */
  1384. *result = ret;
  1385. /* Invalidate ret, so that cleanup doesn't destroy it */
  1386. ret = NULL;
  1387. /* Clean up after ourselves */
  1388. cleanup:
  1389. if (color)
  1390. css_stylesheet_style_destroy(c->sheet, color, error == CSS_OK);
  1391. if (style)
  1392. css_stylesheet_style_destroy(c->sheet, style, error == CSS_OK);
  1393. if (width)
  1394. css_stylesheet_style_destroy(c->sheet, width, error == CSS_OK);
  1395. if (ret)
  1396. css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK);
  1397. if (error != CSS_OK)
  1398. *ctx = orig_ctx;
  1399. return error;
  1400. }
  1401. /**
  1402. * Parse outline-color
  1403. *
  1404. * \param c Parsing context
  1405. * \param vector Vector of tokens to process
  1406. * \param ctx Pointer to vector iteration context
  1407. * \param result Pointer to location to receive resulting style
  1408. * \return CSS_OK on success,
  1409. * CSS_NOMEM on memory exhaustion,
  1410. * CSS_INVALID if the input is not valid
  1411. *
  1412. * Post condition: \a *ctx is updated with the next token to process
  1413. * If the input is invalid, then \a *ctx remains unchanged.
  1414. */
  1415. css_error parse_outline_color(css_language *c,
  1416. const parserutils_vector *vector, int *ctx,
  1417. css_style **result)
  1418. {
  1419. int orig_ctx = *ctx;
  1420. css_error error;
  1421. const css_token *token;
  1422. uint8_t flags = 0;
  1423. uint16_t value = 0;
  1424. uint32_t opv;
  1425. uint32_t colour = 0;
  1426. uint32_t required_size;
  1427. bool match;
  1428. /* colour | IDENT (invert, inherit) */
  1429. token = parserutils_vector_peek(vector, *ctx);
  1430. if (token == NULL) {
  1431. *ctx = orig_ctx;
  1432. return CSS_INVALID;
  1433. }
  1434. if (token->type == CSS_TOKEN_IDENT &&
  1435. (lwc_string_caseless_isequal(
  1436. token->idata, c->strings[INHERIT],
  1437. &match) == lwc_error_ok && match)) {
  1438. parserutils_vector_iterate(vector, ctx);
  1439. flags |= FLAG_INHERIT;
  1440. } else if (token->type == CSS_TOKEN_IDENT &&
  1441. (lwc_string_caseless_isequal(
  1442. token->idata, c->strings[INVERT],
  1443. &match) == lwc_error_ok && match)) {
  1444. parserutils_vector_iterate(vector, ctx);
  1445. value = OUTLINE_COLOR_INVERT;
  1446. } else {
  1447. error = parse_colour_specifier(c, vector, ctx, &colour);
  1448. if (error != CSS_OK) {
  1449. *ctx = orig_ctx;
  1450. return error;
  1451. }
  1452. value = OUTLINE_COLOR_SET;
  1453. }
  1454. opv = buildOPV(CSS_PROP_OUTLINE_COLOR, flags, value);
  1455. required_size = sizeof(opv);
  1456. if ((flags & FLAG_INHERIT) == false && value == OUTLINE_COLOR_SET)
  1457. required_size += sizeof(colour);
  1458. /* Allocate result */
  1459. error = css_stylesheet_style_create(c->sheet, required_size, result);
  1460. if (error != CSS_OK) {
  1461. *ctx = orig_ctx;
  1462. return error;
  1463. }
  1464. /* Copy the bytecode to it */
  1465. memcpy((*result)->bytecode, &opv, sizeof(opv));
  1466. if ((flags & FLAG_INHERIT) == false && value == OUTLINE_COLOR_SET) {
  1467. memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv),
  1468. &colour, sizeof(colour));
  1469. }
  1470. return CSS_OK;
  1471. }
  1472. /**
  1473. * Parse outline-style
  1474. *
  1475. * \param c Parsing context
  1476. * \param vector Vector of tokens to process
  1477. * \param ctx Pointer to vector iteration context
  1478. * \param result Pointer to location to receive resulting style
  1479. * \return CSS_OK on success,
  1480. * CSS_NOMEM on memory exhaustion,
  1481. * CSS_INVALID if the input is not valid
  1482. *
  1483. * Post condition: \a *ctx is updated with the next token to process
  1484. * If the input is invalid, then \a *ctx remains unchanged.
  1485. */
  1486. css_error parse_outline_style(css_language *c,
  1487. const parserutils_vector *vector, int *ctx,
  1488. css_style **result)
  1489. {
  1490. int orig_ctx = *ctx;
  1491. css_error error;
  1492. uint32_t opv;
  1493. uint16_t value;
  1494. /* Parse as a border style */
  1495. error = parse_border_side_style(c, vector, ctx,
  1496. CSS_PROP_OUTLINE_STYLE, result);
  1497. if (error != CSS_OK) {
  1498. *ctx = orig_ctx;
  1499. return error;
  1500. }
  1501. opv = *((uint32_t *) (*result)->bytecode);
  1502. value = getValue(opv);
  1503. /* Hidden is invalid */
  1504. if (value == BORDER_STYLE_HIDDEN) {
  1505. *ctx = orig_ctx;
  1506. return CSS_INVALID;
  1507. }
  1508. return CSS_OK;
  1509. }
  1510. /**
  1511. * Parse outline-width
  1512. *
  1513. * \param c Parsing context
  1514. * \param vector Vector of tokens to process
  1515. * \param ctx Pointer to vector iteration context
  1516. * \param result Pointer to location to receive resulting style
  1517. * \return CSS_OK on success,
  1518. * CSS_NOMEM on memory exhaustion,
  1519. * CSS_INVALID if the input is not valid
  1520. *
  1521. * Post condition: \a *ctx is updated with the next token to process
  1522. * If the input is invalid, then \a *ctx remains unchanged.
  1523. */
  1524. css_error parse_outline_width(css_language *c,
  1525. const parserutils_vector *vector, int *ctx,
  1526. css_style **result)
  1527. {
  1528. /* Parse as border width */
  1529. return parse_border_side_width(c, vector, ctx,
  1530. CSS_PROP_OUTLINE_WIDTH, result);
  1531. }
  1532. /**
  1533. * Parse border-{top,right,bottom,left} shorthand
  1534. *
  1535. * \param c Parsing context
  1536. * \param vector Vector of tokens to process
  1537. * \param ctx Pointer to vector iteration context
  1538. * \param side The side we're parsing for
  1539. * \param result Pointer to location to receive resulting style
  1540. * \return CSS_OK on success,
  1541. * CSS_NOMEM on memory exhaustion,
  1542. * CSS_INVALID if the input is not valid
  1543. *
  1544. * Post condition: \a *ctx is updated with the next token to process
  1545. * If the input is invalid, then \a *ctx remains unchanged.
  1546. */
  1547. css_error parse_border_side(css_language *c,
  1548. const parserutils_vector *vector, int *ctx,
  1549. uint32_t side, css_style **result)
  1550. {
  1551. int orig_ctx = *ctx;
  1552. int prev_ctx;
  1553. const css_token *token;
  1554. css_style *color = NULL;
  1555. css_style *style = NULL;
  1556. css_style *width = NULL;
  1557. css_style *ret = NULL;
  1558. uint32_t required_size;
  1559. bool match;
  1560. css_error error;
  1561. /* Firstly, handle inherit */
  1562. token = parserutils_vector_peek(vector, *ctx);
  1563. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  1564. (lwc_string_caseless_isequal(
  1565. token->idata, c->strings[INHERIT],
  1566. &match) == lwc_error_ok && match)) {
  1567. uint32_t *bytecode;
  1568. error = css_stylesheet_style_create(c->sheet,
  1569. 3 * sizeof(uint32_t), &ret);
  1570. if (error != CSS_OK) {
  1571. *ctx = orig_ctx;
  1572. return error;
  1573. }
  1574. bytecode = (uint32_t *) ret->bytecode;
  1575. *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_COLOR + side,
  1576. FLAG_INHERIT, 0);
  1577. *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side,
  1578. FLAG_INHERIT, 0);
  1579. *(bytecode++) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side,
  1580. FLAG_INHERIT, 0);
  1581. parserutils_vector_iterate(vector, ctx);
  1582. *result = ret;
  1583. return CSS_OK;
  1584. } else if (token == NULL) {
  1585. /* No tokens -- clearly garbage */
  1586. *ctx = orig_ctx;
  1587. return CSS_INVALID;
  1588. }
  1589. /* Attempt to parse individual properties */
  1590. do {
  1591. prev_ctx = *ctx;
  1592. error = CSS_OK;
  1593. /* Ensure that we're not about to parse another inherit */
  1594. token = parserutils_vector_peek(vector, *ctx);
  1595. if (token != NULL && token->type == CSS_TOKEN_IDENT &&
  1596. (lwc_string_caseless_isequal(
  1597. token->idata, c->strings[INHERIT],
  1598. &match) == lwc_error_ok && match)) {
  1599. error = CSS_INVALID;
  1600. goto cleanup;
  1601. }
  1602. if (color == NULL &&
  1603. (error = parse_border_side_color(c, vector, ctx,
  1604. CSS_PROP_BORDER_TOP_COLOR + side, &color)) ==
  1605. CSS_OK) {
  1606. } else if (style == NULL &&
  1607. (error = parse_border_side_style(c, vector, ctx,
  1608. CSS_PROP_BORDER_TOP_STYLE + side, &style)) ==
  1609. CSS_OK) {
  1610. } else if (width == NULL &&
  1611. (error = parse_border_side_width(c, vector, ctx,
  1612. CSS_PROP_BORDER_TOP_WIDTH + side, &width)) ==
  1613. CSS_OK) {
  1614. }
  1615. if (error == CSS_OK) {
  1616. consumeWhitespace(vector, ctx);
  1617. token = parserutils_vector_peek(vector, *ctx);
  1618. } else {
  1619. /* Forcibly cause loop to exit */
  1620. token = NULL;
  1621. }
  1622. } while (*ctx != prev_ctx && token != NULL);
  1623. /* Calculate size of resultant style */
  1624. required_size = 0;
  1625. if (color)
  1626. required_size += color->length;
  1627. if (style)
  1628. required_size += style->length;
  1629. else
  1630. required_size += sizeof(uint32_t);
  1631. if (width)
  1632. required_size += width->length;
  1633. else
  1634. required_size += sizeof(uint32_t);
  1635. error = css_stylesheet_style_create(c->sheet, required_size, &ret);
  1636. if (error != CSS_OK)
  1637. goto cleanup;
  1638. required_size = 0;
  1639. if (color) {
  1640. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1641. color->bytecode, color->length);
  1642. required_size += color->length;
  1643. }
  1644. if (style) {
  1645. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1646. style->bytecode, style->length);
  1647. required_size += style->length;
  1648. } else {
  1649. void *bc = ((uint8_t *) ret->bytecode) + required_size;
  1650. *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_STYLE + side,
  1651. 0, BORDER_STYLE_NONE);
  1652. required_size += sizeof(uint32_t);
  1653. }
  1654. if (width) {
  1655. memcpy(((uint8_t *) ret->bytecode) + required_size,
  1656. width->bytecode, width->length);
  1657. required_size += width->length;
  1658. } else {
  1659. void *bc = ((uint8_t *) ret->bytecode) + required_size;
  1660. *((uint32_t *) bc) = buildOPV(CSS_PROP_BORDER_TOP_WIDTH + side,
  1661. 0, BORDER_WIDTH_MEDIUM);
  1662. required_size += sizeof(uint32_t);
  1663. }
  1664. assert(required_size == ret->length);
  1665. /* Write the result */
  1666. *result = ret;
  1667. /* Invalidate ret, so that cleanup doesn't destroy it */
  1668. ret = NULL;
  1669. /* Clean up after ourselves */
  1670. cleanup:
  1671. if (color)
  1672. css_stylesheet_style_destroy(c->sheet, color, error == CSS_OK);
  1673. if (style)
  1674. css_stylesheet_style_destroy(c->sheet, style, error == CSS_OK);
  1675. if (width)
  1676. css_stylesheet_style_destroy(c->sheet, width, error == CSS_OK);
  1677. if (ret)
  1678. css_stylesheet_style_destroy(c->sheet, ret, error == CSS_OK);
  1679. if (error != CSS_OK)
  1680. *ctx = orig_ctx;
  1681. return error;
  1682. }
  1683. /**
  1684. * Parse border-{top,right,bottom,left}-color
  1685. *
  1686. * \param c Parsing context
  1687. * \param vector Vector of tokens to process
  1688. * \param ctx Pointer to vector iteration context
  1689. * \param op Opcode to parse for (encodes side)
  1690. * \param result Pointer to location to receive resulting style
  1691. * \return CSS_OK on success,
  1692. * CSS_NOMEM on memory exhaustion,
  1693. * CSS_INVALID if the input is not valid
  1694. *
  1695. * Post condition: \a *ctx is updated with the next token to process
  1696. * If the input is invalid, then \a *ctx remains unchanged.
  1697. */
  1698. css_error parse_border_side_color(css_language *c,
  1699. const parserutils_vector *vector, int *ctx,
  1700. uint16_t op, css_style **result)
  1701. {
  1702. int orig_ctx = *ctx;
  1703. css_error error;
  1704. const css_token *token;
  1705. uint32_t opv;
  1706. uint8_t flags = 0;
  1707. uint16_t value = 0;
  1708. uint32_t colour = 0;
  1709. uint32_t required_size;
  1710. bool match;
  1711. /* colour | IDENT (transparent, inherit) */
  1712. token= parserutils_vector_peek(vector, *ctx);
  1713. if (token == NULL) {
  1714. *ctx = orig_ctx;
  1715. return CSS_INVALID;
  1716. }
  1717. if (token->type == CSS_TOKEN_IDENT &&
  1718. (lwc_string_caseless_isequal(
  1719. token->idata, c->strings[INHERIT],
  1720. &match) == lwc_error_ok && match)) {
  1721. parserutils_vector_iterate(vector, ctx);
  1722. flags |= FLAG_INHERIT;
  1723. } else if (token->type == CSS_TOKEN_IDENT &&
  1724. (lwc_string_caseless_isequal(
  1725. token->idata, c->strings[TRANSPARENT],
  1726. &match) == lwc_error_ok && match)) {
  1727. parserutils_vector_iterate(vector, ctx);
  1728. value = BORDER_COLOR_TRANSPARENT;
  1729. } else {
  1730. error = parse_colour_specifier(c, vector, ctx, &colour);
  1731. if (error != CSS_OK) {
  1732. *ctx = orig_ctx;
  1733. return error;
  1734. }
  1735. value = BORDER_COLOR_SET;
  1736. }
  1737. opv = buildOPV(op, flags, value);
  1738. required_size = sizeof(opv);
  1739. if ((flags & FLAG_INHERIT) == false && value == BORDER_COLOR_SET)
  1740. required_size += sizeof(colour);
  1741. /* Allocate result */
  1742. error = css_stylesheet_style_create(c->sheet, required_size, result);
  1743. if (error != CSS_OK) {
  1744. *ctx = orig_ctx;
  1745. return error;
  1746. }
  1747. /* Copy the bytecode to it */
  1748. memcpy((*result)->bytecode, &opv, sizeof(opv));
  1749. if ((flags & FLAG_INHERIT) == false && value == BORDER_COLOR_SET) {
  1750. memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv),
  1751. &colour, sizeof(colour));
  1752. }
  1753. return CSS_OK;
  1754. }
  1755. /**
  1756. * Parse border-{top,right,bottom,left}-style
  1757. *
  1758. * \param c Parsing context
  1759. * \param vector Vector of tokens to process
  1760. * \param ctx Pointer to vector iteration context
  1761. * \param op Opcode to parse for (encodes side)
  1762. * \param result Pointer to location to receive resulting style
  1763. * \return CSS_OK on success,
  1764. * CSS_NOMEM on memory exhaustion,
  1765. * CSS_INVALID if the input is not valid
  1766. *
  1767. * Post condition: \a *ctx is updated with the next token to process
  1768. * If the input is invalid, then \a *ctx remains unchanged.
  1769. */
  1770. css_error parse_border_side_style(css_language *c,
  1771. const parserutils_vector *vector, int *ctx,
  1772. uint16_t op, css_style **result)
  1773. {
  1774. int orig_ctx = *ctx;
  1775. css_error error;
  1776. const css_token *ident;
  1777. uint8_t flags = 0;
  1778. uint16_t value = 0;
  1779. uint32_t opv;
  1780. bool match;
  1781. /* IDENT (none, hidden, dotted, dashed, solid, double, groove,
  1782. * ridge, inset, outset, inherit) */
  1783. ident = parserutils_vector_iterate(vector, ctx);
  1784. if (ident == NULL || ident->type != CSS_TOKEN_IDENT) {
  1785. *ctx = orig_ctx;
  1786. return CSS_INVALID;
  1787. }
  1788. if ((lwc_string_caseless_isequal(
  1789. ident->idata, c->strings[INHERIT],
  1790. &match) == lwc_error_ok && match)) {
  1791. flags |= FLAG_INHERIT;
  1792. } else if ((lwc_string_caseless_isequal(
  1793. ident->idata, c->strings[NONE],
  1794. &match) == lwc_error_ok && match)) {
  1795. value = BORDER_STYLE_NONE;
  1796. } else if ((lwc_string_caseless_isequal(
  1797. ident->idata, c->strings[HIDDEN],
  1798. &match) == lwc_error_ok && match)) {
  1799. value = BORDER_STYLE_HIDDEN;
  1800. } else if ((lwc_string_caseless_isequal(
  1801. ident->idata, c->strings[DOTTED],
  1802. &match) == lwc_error_ok && match)) {
  1803. value = BORDER_STYLE_DOTTED;
  1804. } else if ((lwc_string_caseless_isequal(
  1805. ident->idata, c->strings[DASHED],
  1806. &match) == lwc_error_ok && match)) {
  1807. value = BORDER_STYLE_DASHED;
  1808. } else if ((lwc_string_caseless_isequal(
  1809. ident->idata, c->strings[SOLID],
  1810. &match) == lwc_error_ok && match)) {
  1811. value = BORDER_STYLE_SOLID;
  1812. } else if ((lwc_string_caseless_isequal(
  1813. ident->idata, c->strings[DOUBLE],
  1814. &match) == lwc_error_ok && match)) {
  1815. value = BORDER_STYLE_DOUBLE;
  1816. } else if ((lwc_string_caseless_isequal(
  1817. ident->idata, c->strings[GROOVE],
  1818. &match) == lwc_error_ok && match)) {
  1819. value = BORDER_STYLE_GROOVE;
  1820. } else if ((lwc_string_caseless_isequal(
  1821. ident->idata, c->strings[RIDGE],
  1822. &match) == lwc_error_ok && match)) {
  1823. value = BORDER_STYLE_RIDGE;
  1824. } else if ((lwc_string_caseless_isequal(
  1825. ident->idata, c->strings[INSET],
  1826. &match) == lwc_error_ok && match)) {
  1827. value = BORDER_STYLE_INSET;
  1828. } else if ((lwc_string_caseless_isequal(
  1829. ident->idata, c->strings[OUTSET],
  1830. &match) == lwc_error_ok && match)) {
  1831. value = BORDER_STYLE_OUTSET;
  1832. } else {
  1833. *ctx = orig_ctx;
  1834. return CSS_INVALID;
  1835. }
  1836. opv = buildOPV(op, flags, value);
  1837. /* Allocate result */
  1838. error = css_stylesheet_style_create(c->sheet, sizeof(opv), result);
  1839. if (error != CSS_OK) {
  1840. *ctx = orig_ctx;
  1841. return error;
  1842. }
  1843. /* Copy the bytecode to it */
  1844. memcpy((*result)->bytecode, &opv, sizeof(opv));
  1845. return CSS_OK;
  1846. }
  1847. /**
  1848. * Parse border-{top,right,bottom,left}-width
  1849. *
  1850. * \param c Parsing context
  1851. * \param vector Vector of tokens to process
  1852. * \param ctx Pointer to vector iteration context
  1853. * \param op Opcode to parse for (encodes side)
  1854. * \param result Pointer to location to receive resulting style
  1855. * \return CSS_OK on success,
  1856. * CSS_NOMEM on memory exhaustion,
  1857. * CSS_INVALID if the input is not valid
  1858. *
  1859. * Post condition: \a *ctx is updated with the next token to process
  1860. * If the input is invalid, then \a *ctx remains unchanged.
  1861. */
  1862. css_error parse_border_side_width(css_language *c,
  1863. const parserutils_vector *vector, int *ctx,
  1864. uint16_t op, css_style **result)
  1865. {
  1866. int orig_ctx = *ctx;
  1867. css_error error;
  1868. const css_token *token;
  1869. uint8_t flags = 0;
  1870. uint16_t value = 0;
  1871. uint32_t opv;
  1872. css_fixed length = 0;
  1873. uint32_t unit = 0;
  1874. uint32_t required_size;
  1875. bool match;
  1876. /* length | IDENT(thin, medium, thick, inherit) */
  1877. token= parserutils_vector_peek(vector, *ctx);
  1878. if (token == NULL) {
  1879. *ctx = orig_ctx;
  1880. return CSS_INVALID;
  1881. }
  1882. if (token->type == CSS_TOKEN_IDENT &&
  1883. (lwc_string_caseless_isequal(
  1884. token->idata, c->strings[INHERIT],
  1885. &match) == lwc_error_ok && match)) {
  1886. parserutils_vector_iterate(vector, ctx);
  1887. flags |= FLAG_INHERIT;
  1888. } else if (token->type == CSS_TOKEN_IDENT &&
  1889. (lwc_string_caseless_isequal(
  1890. token->idata, c->strings[THIN],
  1891. &match) == lwc_error_ok && match)) {
  1892. parserutils_vector_iterate(vector, ctx);
  1893. value = BORDER_WIDTH_THIN;
  1894. } else if (token->type == CSS_TOKEN_IDENT &&
  1895. (lwc_string_caseless_isequal(
  1896. token->idata, c->strings[MEDIUM],
  1897. &match) == lwc_error_ok && match)) {
  1898. parserutils_vector_iterate(vector, ctx);
  1899. value = BORDER_WIDTH_MEDIUM;
  1900. } else if (token->type == CSS_TOKEN_IDENT &&
  1901. (lwc_string_caseless_isequal(
  1902. token->idata, c->strings[THICK],
  1903. &match) == lwc_error_ok && match)) {
  1904. parserutils_vector_iterate(vector, ctx);
  1905. value = BORDER_WIDTH_THICK;
  1906. } else {
  1907. error = parse_unit_specifier(c, vector, ctx, UNIT_PX,
  1908. &length, &unit);
  1909. if (error != CSS_OK) {
  1910. *ctx = orig_ctx;
  1911. return error;
  1912. }
  1913. if (unit == UNIT_PCT || unit & UNIT_ANGLE ||
  1914. unit & UNIT_TIME || unit & UNIT_FREQ) {
  1915. *ctx = orig_ctx;
  1916. return CSS_INVALID;
  1917. }
  1918. /* Length must be positive */
  1919. if (length < 0) {
  1920. *ctx = orig_ctx;
  1921. return CSS_INVALID;
  1922. }
  1923. value = BORDER_WIDTH_SET;
  1924. }
  1925. opv = buildOPV(op, flags, value);
  1926. required_size = sizeof(opv);
  1927. if ((flags & FLAG_INHERIT) == false && value == BORDER_WIDTH_SET)
  1928. required_size += sizeof(length) + sizeof(unit);
  1929. /* Allocate result */
  1930. error = css_stylesheet_style_create(c->sheet, required_size, result);
  1931. if (error != CSS_OK) {
  1932. *ctx = orig_ctx;
  1933. return error;
  1934. }
  1935. /* Copy the bytecode to it */
  1936. memcpy((*result)->bytecode, &opv, sizeof(opv));
  1937. if ((flags & FLAG_INHERIT) == false && value == BORDER_WIDTH_SET) {
  1938. memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv),
  1939. &length, sizeof(length));
  1940. memcpy(((uint8_t *) (*result)->bytecode) + sizeof(opv) +
  1941. sizeof(length), &unit, sizeof(unit));
  1942. }
  1943. return CSS_OK;
  1944. }