PageRenderTime 73ms CodeModel.GetById 2ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 1ms

/peek-build/src/netdepends/libcss/src/select/computed.c

https://bitbucket.org/C0deMaver1ck/peeklinux
C | 1009 lines | 656 code | 153 blank | 200 comment | 230 complexity | 6b9e650fee7f2a7c3afb7da149e32772 MD5 | raw 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 <string.h>
   9
  10#include "select/computed.h"
  11#include "select/dispatch.h"
  12#include "select/propget.h"
  13#include "select/propset.h"
  14#include "utils/utils.h"
  15
  16static css_error compute_border_colors(css_computed_style *style);
  17
  18static css_error compute_absolute_border_width(css_computed_style *style,
  19		const css_hint_length *ex_size);
  20static css_error compute_absolute_border_side_width(css_computed_style *style,
  21		const css_hint_length *ex_size,
  22		uint8_t (*get)(const css_computed_style *style, 
  23				css_fixed *len, css_unit *unit),
  24		css_error (*set)(css_computed_style *style, uint8_t type,
  25				css_fixed len, css_unit unit));
  26static css_error compute_absolute_sides(css_computed_style *style,
  27		const css_hint_length *ex_size);
  28static css_error compute_absolute_clip(css_computed_style *style,
  29		const css_hint_length *ex_size);
  30static css_error compute_absolute_line_height(css_computed_style *style,
  31		const css_hint_length *ex_size);
  32static css_error compute_absolute_margins(css_computed_style *style,
  33		const css_hint_length *ex_size);
  34static css_error compute_absolute_padding(css_computed_style *style,
  35		const css_hint_length *ex_size);
  36static css_error compute_absolute_vertical_align(css_computed_style *style,
  37		const css_hint_length *ex_size);
  38static css_error compute_absolute_length(css_computed_style *style,
  39		const css_hint_length *ex_size,
  40		uint8_t (*get)(const css_computed_style *style, 
  41				css_fixed *len, css_unit *unit),
  42		css_error (*set)(css_computed_style *style, uint8_t type,
  43				css_fixed len, css_unit unit));
  44static css_error compute_absolute_length_auto(css_computed_style *style,
  45		const css_hint_length *ex_size,
  46		uint8_t (*get)(const css_computed_style *style, 
  47				css_fixed *len, css_unit *unit),
  48		css_error (*set)(css_computed_style *style, uint8_t type,
  49				css_fixed len, css_unit unit));
  50static css_error compute_absolute_length_none(css_computed_style *style,
  51		const css_hint_length *ex_size,
  52		uint8_t (*get)(const css_computed_style *style, 
  53				css_fixed *len, css_unit *unit),
  54		css_error (*set)(css_computed_style *style, uint8_t type,
  55				css_fixed len, css_unit unit));
  56static css_error compute_absolute_length_normal(css_computed_style *style,
  57		const css_hint_length *ex_size,
  58		uint8_t (*get)(const css_computed_style *style, 
  59				css_fixed *len, css_unit *unit),
  60		css_error (*set)(css_computed_style *style, uint8_t type,
  61				css_fixed len, css_unit unit));
  62static css_error compute_absolute_length_pair(css_computed_style *style,
  63		const css_hint_length *ex_size,
  64		uint8_t (*get)(const css_computed_style *style, 
  65				css_fixed *len1, css_unit *unit1,
  66				css_fixed *len2, css_unit *unit2),
  67		css_error (*set)(css_computed_style *style, uint8_t type,
  68				css_fixed len1, css_unit unit1,
  69				css_fixed len2, css_unit unit2));
  70
  71
  72/**
  73 * Create a computed style
  74 *
  75 * \param alloc   Memory (de)allocation function
  76 * \param pw      Pointer to client-specific data
  77 * \param result  Pointer to location to receive result
  78 * \return CSS_OK on success,
  79 *         CSS_NOMEM on memory exhaustion,
  80 *         CSS_BADPARM on bad parameters.
  81 */
  82css_error css_computed_style_create(css_allocator_fn alloc, void *pw,
  83		css_computed_style **result)
  84{
  85	css_computed_style *s;
  86
  87	if (alloc == NULL || result == NULL)
  88		return CSS_BADPARM;
  89
  90	s = alloc(NULL, sizeof(css_computed_style), pw);
  91	if (s == NULL)
  92		return CSS_NOMEM;
  93
  94	memset(s, 0, sizeof(css_computed_style));
  95
  96	s->alloc = alloc;
  97	s->pw = pw;
  98
  99	*result = s;
 100
 101	return CSS_OK;
 102}
 103
 104/**
 105 * Destroy a computed style
 106 *
 107 * \param style  Style to destroy
 108 * \return CSS_OK on success, appropriate error otherwise
 109 */
 110css_error css_computed_style_destroy(css_computed_style *style)
 111{
 112	if (style == NULL)
 113		return CSS_BADPARM;
 114
 115	if (style->uncommon != NULL) {
 116		if (style->uncommon->counter_increment != NULL) {
 117			css_computed_counter *c;
 118
 119			for (c = style->uncommon->counter_increment; 
 120					c->name != NULL; c++) {
 121				lwc_string_unref(c->name);
 122			}
 123
 124			style->alloc(style->uncommon->counter_increment, 0,
 125					style->pw);
 126		}
 127
 128		if (style->uncommon->counter_reset != NULL) {
 129			css_computed_counter *c;
 130
 131			for (c = style->uncommon->counter_reset; 
 132					c->name != NULL; c++) {
 133				lwc_string_unref(c->name);
 134			}
 135
 136			style->alloc(style->uncommon->counter_reset, 0,
 137					style->pw);
 138		}
 139	
 140		if (style->uncommon->cursor != NULL) {
 141			lwc_string **s;
 142
 143			for (s = style->uncommon->cursor; *s != NULL; s++) {
 144				lwc_string_unref(*s);
 145			}
 146
 147			style->alloc(style->uncommon->cursor, 0, style->pw);
 148		}
 149
 150		if (style->uncommon->content != NULL) {
 151			css_computed_content_item *c;
 152
 153			for (c = style->uncommon->content; 
 154					c->type != CSS_COMPUTED_CONTENT_NONE;
 155					c++) {
 156				switch (c->type) {
 157				case CSS_COMPUTED_CONTENT_STRING:
 158					lwc_string_unref(c->data.string);
 159					break;
 160				case CSS_COMPUTED_CONTENT_URI:
 161					lwc_string_unref(c->data.uri);
 162					break;
 163				case CSS_COMPUTED_CONTENT_ATTR:
 164					lwc_string_unref(c->data.attr);
 165					break;
 166				case CSS_COMPUTED_CONTENT_COUNTER:
 167					lwc_string_unref(c->data.counter.name);
 168					break;
 169				case CSS_COMPUTED_CONTENT_COUNTERS:
 170					lwc_string_unref(c->data.counters.name);
 171					lwc_string_unref(c->data.counters.sep);
 172					break;
 173				default:
 174					break;
 175				}
 176			}
 177
 178			style->alloc(style->uncommon->content, 0, style->pw);
 179		}
 180
 181		style->alloc(style->uncommon, 0, style->pw);
 182	}
 183
 184	if (style->page != NULL) {
 185		style->alloc(style->page, 0, style->pw);
 186	}
 187
 188	if (style->aural != NULL) {
 189		style->alloc(style->aural, 0, style->pw);
 190	}
 191
 192	if (style->font_family != NULL) {
 193		lwc_string **s;
 194
 195		for (s = style->font_family; *s != NULL; s++) {
 196			lwc_string_unref(*s);
 197		}
 198
 199		style->alloc(style->font_family, 0, style->pw);
 200	}
 201
 202	if (style->quotes != NULL) {
 203		lwc_string **s;
 204
 205		for (s = style->quotes; *s != NULL; s++) {
 206			lwc_string_unref(*s);
 207		}
 208
 209		style->alloc(style->quotes, 0, style->pw);
 210	}
 211
 212	if (style->list_style_image != NULL)
 213		lwc_string_unref(style->list_style_image);
 214
 215	if (style->background_image != NULL)
 216		lwc_string_unref(style->background_image);
 217
 218	style->alloc(style, 0, style->pw);
 219
 220	return CSS_OK;
 221}
 222
 223/**
 224 * Populate a blank computed style with Initial values
 225 *
 226 * \param style    Computed style to populate
 227 * \param handler  Dispatch table of handler functions
 228 * \param pw       Client-specific private data for handler functions
 229 * \return CSS_OK on success.
 230 */
 231css_error css_computed_style_initialise(css_computed_style *style,
 232		css_select_handler *handler, void *pw)
 233{
 234	css_select_state state;
 235	uint32_t i;
 236	css_error error;
 237
 238	if (style == NULL)
 239		return CSS_BADPARM;
 240
 241	state.node = NULL;
 242	state.pseudo_element = CSS_PSEUDO_ELEMENT_NONE;
 243	state.media = CSS_MEDIA_ALL;
 244	state.result = style;
 245	state.handler = handler;
 246	state.pw = pw;
 247
 248	for (i = 0; i < CSS_N_PROPERTIES; i++) {
 249		/* No need to initialise anything other than the normal
 250		 * properties -- the others are handled by the accessors */
 251		if (prop_dispatch[i].inherited == false &&
 252				prop_dispatch[i].group == GROUP_NORMAL) {
 253			error = prop_dispatch[i].initial(&state);
 254			if (error != CSS_OK)
 255				return error;
 256		}
 257	}
 258
 259	return CSS_OK;
 260}
 261
 262/**
 263 * Compose two computed styles
 264 *
 265 * \param parent             Parent style
 266 * \param child              Child style
 267 * \param compute_font_size  Function to compute an absolute font size
 268 * \param pw                 Client data for compute_font_size
 269 * \param result             Pointer to style to compose into
 270 * \return CSS_OK on success, appropriate error otherwise.
 271 *
 272 * \pre \a parent is a fully composed style (thus has no inherited properties)
 273 *
 274 * \note \a child and \a result may point at the same object
 275 */
 276css_error css_computed_style_compose(const css_computed_style *parent,
 277		const css_computed_style *child,
 278		css_error (*compute_font_size)(void *pw,
 279			const css_hint *parent, css_hint *size),
 280		void *pw,
 281		css_computed_style *result)
 282{
 283	css_error error = CSS_OK;
 284	size_t i;
 285
 286	/* Iterate through the properties */
 287	for (i = 0; i < CSS_N_PROPERTIES; i++) {
 288		/* Skip any in extension blocks if the block does not exist */	
 289		if (prop_dispatch[i].group == GROUP_UNCOMMON &&
 290				parent->uncommon == NULL && 
 291				child->uncommon == NULL)
 292			continue;
 293
 294		if (prop_dispatch[i].group == GROUP_PAGE &&
 295				parent->page == NULL && child->page == NULL)
 296			continue;
 297
 298		if (prop_dispatch[i].group == GROUP_AURAL &&
 299				parent->aural == NULL && child->aural == NULL)
 300			continue;
 301
 302		/* Compose the property */
 303		error = prop_dispatch[i].compose(parent, child, result);
 304		if (error != CSS_OK)
 305			break;
 306	}
 307
 308	/* Finally, compute absolute values for everything */
 309	return compute_absolute_values(parent, result, compute_font_size, pw);
 310}
 311
 312/******************************************************************************
 313 * Library internals                                                          *
 314 ******************************************************************************/
 315
 316/**
 317 * Compute the absolute values of a style
 318 *
 319 * \param parent             Parent style, or NULL for tree root
 320 * \param style              Computed style to process
 321 * \param compute_font_size  Callback to calculate an absolute font-size
 322 * \param pw                 Private word for callback
 323 * \return CSS_OK on success.
 324 */
 325css_error compute_absolute_values(const css_computed_style *parent,
 326		css_computed_style *style,
 327		css_error (*compute_font_size)(void *pw, 
 328			const css_hint *parent, css_hint *size),
 329		void *pw)
 330{
 331	css_hint psize, size, ex_size;
 332	css_error error;
 333
 334	/* Ensure font-size is absolute */
 335	if (parent != NULL) {
 336		psize.status = get_font_size(parent, 
 337				&psize.data.length.value, 
 338				&psize.data.length.unit);
 339	}
 340
 341	size.status = get_font_size(style, 
 342			&size.data.length.value, 
 343			&size.data.length.unit);
 344
 345	error = compute_font_size(pw, parent != NULL ? &psize : NULL, &size);
 346	if (error != CSS_OK)
 347		return error;
 348
 349	error = set_font_size(style, size.status,
 350			size.data.length.value, 
 351			size.data.length.unit);
 352	if (error != CSS_OK)
 353		return error;
 354
 355	/* Compute the size of an ex unit */
 356	ex_size.status = CSS_FONT_SIZE_DIMENSION;
 357	ex_size.data.length.value = INTTOFIX(1);
 358	ex_size.data.length.unit = CSS_UNIT_EX;
 359	error = compute_font_size(pw, &size, &ex_size);
 360	if (error != CSS_OK)
 361		return error;
 362
 363	/* Convert ex size into ems */
 364	if (size.data.length.value != 0)
 365		ex_size.data.length.value = FDIV(ex_size.data.length.value, 
 366					size.data.length.value);
 367	else
 368		ex_size.data.length.value = 0;
 369	ex_size.data.length.unit = CSS_UNIT_EM;
 370
 371	/* Fix up background-position */
 372	error = compute_absolute_length_pair(style, &ex_size.data.length, 
 373			get_background_position,
 374			set_background_position);
 375	if (error != CSS_OK)
 376		return error;
 377
 378	/* Fix up border-{top,right,bottom,left}-color */
 379	error = compute_border_colors(style);
 380	if (error != CSS_OK)
 381		return error;
 382
 383	/* Fix up border-{top,right,bottom,left}-width */
 384	error = compute_absolute_border_width(style, &ex_size.data.length);
 385	if (error != CSS_OK)
 386		return error;
 387
 388	/* Fix up sides */
 389	error = compute_absolute_sides(style, &ex_size.data.length);
 390	if (error != CSS_OK)
 391		return error;
 392
 393	/* Fix up height */
 394	error = compute_absolute_length_auto(style, &ex_size.data.length, 
 395			get_height, set_height);
 396	if (error != CSS_OK)
 397		return error;
 398
 399	/* Fix up line-height (must be before vertical-align) */
 400	error = compute_absolute_line_height(style, &ex_size.data.length);
 401	if (error != CSS_OK)
 402		return error;
 403
 404	/* Fix up margins */
 405	error = compute_absolute_margins(style, &ex_size.data.length);
 406	if (error != CSS_OK)
 407		return error;
 408
 409	/* Fix up max-height */
 410	error = compute_absolute_length_none(style, &ex_size.data.length, 
 411			get_max_height, set_max_height);
 412	if (error != CSS_OK)
 413		return error;
 414
 415	/* Fix up max-width */
 416	error = compute_absolute_length_none(style, &ex_size.data.length, 
 417			get_max_width, set_max_width);
 418	if (error != CSS_OK)
 419		return error;
 420
 421	/* Fix up min-height */
 422	error = compute_absolute_length(style, &ex_size.data.length, 
 423			get_min_height, set_min_height);
 424	if (error != CSS_OK)
 425		return error;
 426
 427	/* Fix up min-width */
 428	error = compute_absolute_length(style, &ex_size.data.length, 
 429			get_min_width, set_min_width);
 430	if (error != CSS_OK)
 431		return error;
 432
 433	/* Fix up padding */
 434	error = compute_absolute_padding(style, &ex_size.data.length);
 435	if (error != CSS_OK)
 436		return error;
 437
 438	/* Fix up text-indent */
 439	error = compute_absolute_length(style, &ex_size.data.length, 
 440			get_text_indent, set_text_indent);
 441	if (error != CSS_OK)
 442		return error;
 443
 444	/* Fix up vertical-align */
 445	error = compute_absolute_vertical_align(style, &ex_size.data.length);
 446	if (error != CSS_OK)
 447		return error;
 448
 449	/* Fix up width */
 450	error = compute_absolute_length_auto(style, &ex_size.data.length, 
 451			get_width, set_width);
 452	if (error != CSS_OK)
 453		return error;
 454
 455	/* Uncommon properties */
 456	if (style->uncommon != NULL) {
 457		/* Fix up border-spacing */
 458		error = compute_absolute_length_pair(style,
 459				&ex_size.data.length,
 460				get_border_spacing,
 461				set_border_spacing);
 462		if (error != CSS_OK)
 463			return error;
 464
 465		/* Fix up clip */
 466		error = compute_absolute_clip(style, &ex_size.data.length);
 467		if (error != CSS_OK)
 468			return error;
 469
 470		/* Fix up letter-spacing */
 471		error = compute_absolute_length_normal(style,
 472				&ex_size.data.length,
 473				get_letter_spacing, 
 474				set_letter_spacing);
 475		if (error != CSS_OK)
 476			return error;
 477
 478		/* Fix up outline-width */
 479		error = compute_absolute_border_side_width(style, 
 480				&ex_size.data.length, 
 481				get_outline_width, 
 482				set_outline_width);
 483		if (error != CSS_OK)
 484			return error;
 485
 486		/* Fix up word spacing */
 487		error = compute_absolute_length_normal(style,
 488				&ex_size.data.length,
 489				get_word_spacing, 
 490				set_word_spacing);
 491		if (error != CSS_OK)
 492			return error;
 493	}
 494
 495	return CSS_OK;
 496}
 497
 498/******************************************************************************
 499 * Absolute value calculators
 500 ******************************************************************************/
 501
 502/**
 503 * Compute border colours, replacing any set to initial with 
 504 * the computed value of color.
 505 *
 506 * \param style  The style to process
 507 * \return CSS_OK on success
 508 */
 509css_error compute_border_colors(css_computed_style *style)
 510{
 511	css_color color, bcol;
 512	css_error error;
 513
 514	css_computed_color(style, &color);
 515
 516	if (get_border_top_color(style, &bcol) == CSS_BORDER_COLOR_INITIAL) {
 517		error = set_border_top_color(style, 
 518				CSS_BORDER_COLOR_COLOR, color);
 519		if (error != CSS_OK)
 520			return error;
 521	}
 522
 523	if (get_border_right_color(style, &bcol) == CSS_BORDER_COLOR_INITIAL) {
 524		error = set_border_right_color(style, 
 525				CSS_BORDER_COLOR_COLOR, color);
 526		if (error != CSS_OK)
 527			return error;
 528	}
 529
 530	if (get_border_bottom_color(style, &bcol) == CSS_BORDER_COLOR_INITIAL) {
 531		error = set_border_bottom_color(style, 
 532				CSS_BORDER_COLOR_COLOR, color);
 533		if (error != CSS_OK)
 534			return error;
 535	}
 536
 537	if (get_border_left_color(style, &bcol) == CSS_BORDER_COLOR_INITIAL) {
 538		error = set_border_left_color(style, 
 539				CSS_BORDER_COLOR_COLOR, color);
 540		if (error != CSS_OK)
 541			return error;
 542	}
 543
 544	return CSS_OK;
 545}
 546
 547/**
 548 * Compute absolute border widths
 549 *
 550 * \param style      Style to process
 551 * \param ex_size    Ex size in ems
 552 * \return CSS_OK on success
 553 */
 554css_error compute_absolute_border_width(css_computed_style *style,
 555		const css_hint_length *ex_size)
 556{
 557	css_error error;
 558
 559	error = compute_absolute_border_side_width(style, ex_size,
 560			get_border_top_width, 
 561			set_border_top_width);
 562	if (error != CSS_OK)
 563		return error;
 564
 565	error = compute_absolute_border_side_width(style, ex_size,
 566			get_border_right_width, 
 567			set_border_right_width);
 568	if (error != CSS_OK)
 569		return error;
 570
 571	error = compute_absolute_border_side_width(style, ex_size,
 572			get_border_bottom_width, 
 573			set_border_bottom_width);
 574	if (error != CSS_OK)
 575		return error;
 576
 577	error = compute_absolute_border_side_width(style, ex_size,
 578			get_border_left_width, 
 579			set_border_left_width);
 580	if (error != CSS_OK)
 581		return error;
 582
 583	return CSS_OK;
 584}
 585
 586/**
 587 * Compute an absolute border side width
 588 *
 589 * \param style      Style to process
 590 * \param ex_size    Ex size, in ems
 591 * \param get        Function to read length
 592 * \param set        Function to write length
 593 * \return CSS_OK on success
 594 */
 595css_error compute_absolute_border_side_width(css_computed_style *style,
 596		const css_hint_length *ex_size,
 597		uint8_t (*get)(const css_computed_style *style, 
 598				css_fixed *len, css_unit *unit),
 599		css_error (*set)(css_computed_style *style, uint8_t type,
 600				css_fixed len, css_unit unit))
 601{
 602	css_fixed length;
 603	css_unit unit;
 604	uint8_t type;
 605
 606	type = get(style, &length, &unit);
 607	if (type == CSS_BORDER_WIDTH_THIN) {
 608		length = INTTOFIX(1);
 609		unit = CSS_UNIT_PX;
 610	} else if (type == CSS_BORDER_WIDTH_MEDIUM) {
 611		length = INTTOFIX(2);
 612		unit = CSS_UNIT_PX;
 613	} else if (type == CSS_BORDER_WIDTH_THICK) {
 614		length = INTTOFIX(4);
 615		unit = CSS_UNIT_PX;
 616	}
 617
 618	if (unit == CSS_UNIT_EX) {
 619		length = FMUL(length, ex_size->value);
 620		unit = ex_size->unit;
 621	}
 622
 623	return set(style, CSS_BORDER_WIDTH_WIDTH, length, unit);
 624}
 625
 626/**
 627 * Compute absolute clip
 628 *
 629 * \param style      Style to process
 630 * \param ex_size    Ex size in ems
 631 * \return CSS_OK on success
 632 */
 633css_error compute_absolute_clip(css_computed_style *style,
 634		const css_hint_length *ex_size)
 635{
 636	css_computed_clip_rect rect = { 0, 0, 0, 0, CSS_UNIT_PX, CSS_UNIT_PX,
 637			CSS_UNIT_PX, CSS_UNIT_PX, false, false, false, false };
 638	css_error error;
 639
 640	if (get_clip(style, &rect) == CSS_CLIP_RECT) {
 641		if (rect.top_auto == false) {
 642			if (rect.tunit == CSS_UNIT_EX) {
 643				rect.top = FMUL(rect.top, ex_size->value);
 644				rect.tunit = ex_size->unit;
 645			}
 646		}
 647
 648		if (rect.right_auto == false) {
 649			if (rect.runit == CSS_UNIT_EX) {
 650				rect.right = FMUL(rect.right, ex_size->value);
 651				rect.runit = ex_size->unit;
 652			}
 653		}
 654
 655		if (rect.bottom_auto == false) {
 656			if (rect.bunit == CSS_UNIT_EX) {
 657				rect.bottom = FMUL(rect.bottom, ex_size->value);
 658				rect.bunit = ex_size->unit;
 659			}
 660		}
 661
 662		if (rect.left_auto == false) {
 663			if (rect.lunit == CSS_UNIT_EX) {
 664				rect.left = FMUL(rect.left, ex_size->value);
 665				rect.lunit = ex_size->unit;
 666			}
 667		}
 668
 669		error = set_clip(style, CSS_CLIP_RECT, &rect);
 670		if (error != CSS_OK)
 671			return error;
 672	}
 673
 674	return CSS_OK;
 675}
 676
 677/**
 678 * Compute absolute line-height
 679 *
 680 * \param style      Style to process
 681 * \param ex_size    Ex size, in ems
 682 * \return CSS_OK on success
 683 */
 684css_error compute_absolute_line_height(css_computed_style *style,
 685		const css_hint_length *ex_size)
 686{
 687	css_fixed length = 0;
 688	css_unit unit = CSS_UNIT_PX;
 689	uint8_t type;
 690	css_error error;
 691
 692	type = get_line_height(style, &length, &unit);
 693
 694	if (type == CSS_LINE_HEIGHT_DIMENSION) {
 695		if (unit == CSS_UNIT_EX) {
 696			length = FMUL(length, ex_size->value);
 697			unit = ex_size->unit;
 698		}
 699
 700		error = set_line_height(style, type, length, unit);
 701		if (error != CSS_OK)
 702			return error;
 703	}
 704
 705	return CSS_OK;
 706}
 707
 708/**
 709 * Compute the absolute values of {top,right,bottom,left}
 710 *
 711 * \param style      Style to process
 712 * \param ex_size    Ex size, in ems
 713 * \return CSS_OK on success
 714 */
 715css_error compute_absolute_sides(css_computed_style *style,
 716		const css_hint_length *ex_size)
 717{
 718	css_error error;
 719
 720	/* Calculate absolute lengths for sides */
 721	error = compute_absolute_length_auto(style, ex_size, get_top, set_top);
 722	if (error != CSS_OK)
 723		return error;
 724
 725	error = compute_absolute_length_auto(style, ex_size,
 726			get_right, set_right);
 727	if (error != CSS_OK)
 728		return error;
 729
 730	error = compute_absolute_length_auto(style, ex_size,
 731			get_bottom, set_bottom);
 732	if (error != CSS_OK)
 733		return error;
 734
 735	error = compute_absolute_length_auto(style, ex_size,
 736			get_left, set_left);
 737	if (error != CSS_OK)
 738		return error;
 739
 740	return CSS_OK;
 741}
 742
 743/**
 744 * Compute absolute margins
 745 *
 746 * \param style      Style to process
 747 * \param ex_size    Ex size, in ems
 748 * \return CSS_OK on success
 749 */
 750css_error compute_absolute_margins(css_computed_style *style,
 751		const css_hint_length *ex_size)
 752{
 753	css_error error;
 754
 755	error = compute_absolute_length_auto(style, ex_size,
 756			get_margin_top, set_margin_top);
 757	if (error != CSS_OK)
 758		return error;
 759
 760	error = compute_absolute_length_auto(style, ex_size,
 761			get_margin_right, set_margin_right);
 762	if (error != CSS_OK)
 763		return error;
 764
 765	error = compute_absolute_length_auto(style, ex_size,
 766			get_margin_bottom, set_margin_bottom);
 767	if (error != CSS_OK)
 768		return error;
 769
 770	error = compute_absolute_length_auto(style, ex_size,
 771			get_margin_left, set_margin_left);
 772	if (error != CSS_OK)
 773		return error;
 774	
 775	return CSS_OK;
 776}
 777
 778/**
 779 * Compute absolute padding
 780 *
 781 * \param style      Style to process
 782 * \param ex_size    Ex size, in ems
 783 * \return CSS_OK on success
 784 */
 785css_error compute_absolute_padding(css_computed_style *style,
 786		const css_hint_length *ex_size)
 787{
 788	css_error error;
 789
 790	error = compute_absolute_length(style, ex_size,
 791			get_padding_top, set_padding_top);
 792	if (error != CSS_OK)
 793		return error;
 794
 795	error = compute_absolute_length(style, ex_size,
 796			get_padding_right, set_padding_right);
 797	if (error != CSS_OK)
 798		return error;
 799
 800	error = compute_absolute_length(style, ex_size,
 801			get_padding_bottom, set_padding_bottom);
 802	if (error != CSS_OK)
 803		return error;
 804
 805	error = compute_absolute_length(style, ex_size,
 806			get_padding_left, set_padding_left);
 807	if (error != CSS_OK)
 808		return error;
 809	
 810	return CSS_OK;
 811}
 812
 813/**
 814 * Compute absolute vertical-align
 815 *
 816 * \param style      Style to process
 817 * \param ex_size    Ex size, in ems
 818 * \return CSS_OK on success
 819 */
 820css_error compute_absolute_vertical_align(css_computed_style *style,
 821		const css_hint_length *ex_size)
 822{
 823	css_fixed length = 0;
 824	css_unit unit = CSS_UNIT_PX;
 825	uint8_t type;
 826	css_error error;
 827
 828	type = get_vertical_align(style, &length, &unit);
 829
 830	if (type == CSS_VERTICAL_ALIGN_SET) {
 831		if (unit == CSS_UNIT_EX) {
 832			length = FMUL(length, ex_size->value);
 833			unit = ex_size->unit;
 834		}
 835
 836		error = set_vertical_align(style, type, length, unit);
 837		if (error != CSS_OK)
 838			return error;
 839	}
 840
 841	return CSS_OK;
 842}
 843
 844/**
 845 * Compute the absolute value of length
 846 *
 847 * \param style      Style to process
 848 * \param ex_size    Ex size, in ems
 849 * \param get        Function to read length
 850 * \param set        Function to write length
 851 * \return CSS_OK on success
 852 */
 853css_error compute_absolute_length(css_computed_style *style,
 854		const css_hint_length *ex_size,
 855		uint8_t (*get)(const css_computed_style *style, 
 856				css_fixed *len, css_unit *unit),
 857		css_error (*set)(css_computed_style *style, uint8_t type,
 858				css_fixed len, css_unit unit))
 859{
 860	css_fixed length;
 861	css_unit unit;
 862	uint8_t type;
 863
 864	type = get(style, &length, &unit);
 865
 866	if (unit == CSS_UNIT_EX) {
 867		length = FMUL(length, ex_size->value);
 868		unit = ex_size->unit;
 869	}
 870
 871	return set(style, type, length, unit);
 872}
 873
 874/**
 875 * Compute the absolute value of length or auto
 876 *
 877 * \param style      Style to process
 878 * \param ex_size    Ex size, in ems
 879 * \param get        Function to read length
 880 * \param set        Function to write length
 881 * \return CSS_OK on success
 882 */
 883css_error compute_absolute_length_auto(css_computed_style *style,
 884		const css_hint_length *ex_size,
 885		uint8_t (*get)(const css_computed_style *style, 
 886				css_fixed *len, css_unit *unit),
 887		css_error (*set)(css_computed_style *style, uint8_t type,
 888				css_fixed len, css_unit unit))
 889{
 890	css_fixed length;
 891	css_unit unit;
 892	uint8_t type;
 893
 894	type = get(style, &length, &unit);
 895	if (type != CSS_BOTTOM_AUTO) {
 896		if (unit == CSS_UNIT_EX) {
 897			length = FMUL(length, ex_size->value);
 898			unit = ex_size->unit;
 899		}
 900
 901		return set(style, CSS_BOTTOM_SET, length, unit);
 902	}
 903
 904	return set(style, CSS_BOTTOM_AUTO, 0, CSS_UNIT_PX);
 905}
 906
 907/**
 908 * Compute the absolute value of length or none
 909 *
 910 * \param style      Style to process
 911 * \param ex_size    Ex size, in ems
 912 * \param get        Function to read length
 913 * \param set        Function to write length
 914 * \return CSS_OK on success
 915 */
 916css_error compute_absolute_length_none(css_computed_style *style,
 917		const css_hint_length *ex_size,
 918		uint8_t (*get)(const css_computed_style *style, 
 919				css_fixed *len, css_unit *unit),
 920		css_error (*set)(css_computed_style *style, uint8_t type,
 921				css_fixed len, css_unit unit))
 922{
 923	css_fixed length;
 924	css_unit unit;
 925	uint8_t type;
 926
 927	type = get(style, &length, &unit);
 928	if (type != CSS_MAX_HEIGHT_NONE) {
 929		if (unit == CSS_UNIT_EX) {
 930			length = FMUL(length, ex_size->value);
 931			unit = ex_size->unit;
 932		}
 933
 934		return set(style, CSS_MAX_HEIGHT_SET, length, unit);
 935	}
 936
 937	return set(style, CSS_MAX_HEIGHT_NONE, 0, CSS_UNIT_PX);
 938}
 939
 940/**
 941 * Compute the absolute value of length or normal
 942 *
 943 * \param style      Style to process
 944 * \param ex_size    Ex size, in ems
 945 * \param get        Function to read length
 946 * \param set        Function to write length
 947 * \return CSS_OK on success
 948 */
 949css_error compute_absolute_length_normal(css_computed_style *style,
 950		const css_hint_length *ex_size,
 951		uint8_t (*get)(const css_computed_style *style, 
 952				css_fixed *len, css_unit *unit),
 953		css_error (*set)(css_computed_style *style, uint8_t type,
 954				css_fixed len, css_unit unit))
 955{
 956	css_fixed length;
 957	css_unit unit;
 958	uint8_t type;
 959
 960	type = get(style, &length, &unit);
 961	if (type != CSS_LETTER_SPACING_NORMAL) {
 962		if (unit == CSS_UNIT_EX) {
 963			length = FMUL(length, ex_size->value);
 964			unit = ex_size->unit;
 965		}
 966
 967		return set(style, CSS_LETTER_SPACING_SET, length, unit);
 968	}
 969
 970	return set(style, CSS_LETTER_SPACING_NORMAL, 0, CSS_UNIT_PX);
 971}
 972
 973/**
 974 * Compute the absolute value of length pair
 975 *
 976 * \param style      Style to process
 977 * \param ex_size    Ex size, in ems
 978 * \param get        Function to read length
 979 * \param set        Function to write length
 980 * \return CSS_OK on success
 981 */
 982css_error compute_absolute_length_pair(css_computed_style *style,
 983		const css_hint_length *ex_size,
 984		uint8_t (*get)(const css_computed_style *style, 
 985				css_fixed *len1, css_unit *unit1,
 986				css_fixed *len2, css_unit *unit2),
 987		css_error (*set)(css_computed_style *style, uint8_t type,
 988				css_fixed len1, css_unit unit1,
 989				css_fixed len2, css_unit unit2))
 990{
 991	css_fixed length1, length2;
 992	css_unit unit1, unit2;
 993	uint8_t type;
 994
 995	type = get(style, &length1, &unit1, &length2, &unit2);
 996
 997	if (unit1 == CSS_UNIT_EX) {
 998		length1 = FMUL(length1, ex_size->value);
 999		unit1 = ex_size->unit;
1000	}
1001
1002	if (unit2 == CSS_UNIT_EX) {
1003		length2 = FMUL(length2, ex_size->value);
1004		unit2 = ex_size->unit;
1005	}
1006
1007	return set(style, type, length1, unit1, length2, unit2);
1008}
1009