PageRenderTime 86ms CodeModel.GetById 2ms app.highlight 75ms 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

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