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