/** * Compute an absolute border side width * * \param style Style to process * \param ex_size Ex size, in ems * \param get Function to read length * \param set Function to write length * \return CSS_OK on success */ css_error compute_absolute_border_side_width(css_computed_style *style, const css_hint_length *ex_size, uint8_t (*get)(const css_computed_style *style, css_fixed *len, css_unit *unit), css_error (*set)(css_computed_style *style, uint8_t type, css_fixed len, css_unit unit)) { css_fixed length; css_unit unit; uint8_t type; type = get(style, &length, &unit); if (type == CSS_BORDER_WIDTH_THIN) { length = INTTOFIX(1); unit = CSS_UNIT_PX; } else if (type == CSS_BORDER_WIDTH_MEDIUM) { length = INTTOFIX(2); unit = CSS_UNIT_PX; } else if (type == CSS_BORDER_WIDTH_THICK) { length = INTTOFIX(4); unit = CSS_UNIT_PX; } if (unit == CSS_UNIT_EX) { length = FMUL(length, ex_size->value); unit = ex_size->unit; } return set(style, CSS_BORDER_WIDTH_WIDTH, length, unit); }
/* exported function documented in render/font_internal.h */ void font_plot_style_from_css(const css_computed_style *css, plot_font_style_t *fstyle) { lwc_string **families; css_fixed length = 0; css_unit unit = CSS_UNIT_PX; css_color col; fstyle->family = plot_font_generic_family( css_computed_font_family(css, &families)); css_computed_font_size(css, &length, &unit); fstyle->size = FIXTOINT(FMUL(nscss_len2pt(length, unit), INTTOFIX(FONT_SIZE_SCALE))); /* Clamp font size to configured minimum */ if (fstyle->size < (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10) fstyle->size = (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10; fstyle->weight = plot_font_weight(css_computed_font_weight(css)); fstyle->flags = plot_font_flags(css_computed_font_style(css), css_computed_font_variant(css)); css_computed_color(css, &col); fstyle->foreground = nscss_color_to_ns(col); fstyle->background = 0; }
/** * Convert an absolute CSS length to points. * * \param length Length to convert * \param unit Corresponding unit * \return length in points */ css_fixed nscss_len2pt(css_fixed length, css_unit unit) { /* Length must not be relative */ assert(unit != CSS_UNIT_EM && unit != CSS_UNIT_EX); switch (unit) { /* We assume the screen and any other output has the same dpi */ /* 1in = DPIpx => 1px = (72/DPI)pt */ case CSS_UNIT_PX: return FDIV(FMUL(length, F_72), nscss_screen_dpi); /* 1in = 72pt */ case CSS_UNIT_IN: return FMUL(length, F_72); /* 1in = 2.54cm => 1cm = (72/2.54)pt */ case CSS_UNIT_CM: return FMUL(length, FDIV(F_72, FLTTOFIX(2.54))); /* 1in = 25.4mm => 1mm = (72/25.4)pt */ case CSS_UNIT_MM: return FMUL(length, FDIV(F_72, FLTTOFIX(25.4))); case CSS_UNIT_PT: return length; /* 1pc = 12pt */ case CSS_UNIT_PC: return FMUL(length, INTTOFIX(12)); default: break; } return 0; }
/** * Dump a numeric value to the stream in a textual form. * * \param stream Stream to write to * \param val Value to write */ void dump_css_number(FILE *stream, css_fixed val) { if (INTTOFIX(FIXTOINT(val)) == val) fprintf(stream, "%d", FIXTOINT(val)); else dump_css_fixed(stream, val); }
void ami_font_setdevicedpi(int id) { DisplayInfoHandle dih; struct DisplayInfo dinfo; ULONG ydpi = option_amiga_ydpi; ULONG xdpi = option_amiga_ydpi; nscss_screen_dpi = INTTOFIX(option_amiga_ydpi); if(id && (option_monitor_aspect_x != 0) && (option_monitor_aspect_y != 0)) { if(dih = FindDisplayInfo(id)) { if(GetDisplayInfoData(dih, &dinfo, sizeof(struct DisplayInfo), DTAG_DISP, 0)) { int xres = dinfo.Resolution.x; int yres = dinfo.Resolution.y; if((option_monitor_aspect_x != 4) || (option_monitor_aspect_y != 3)) { /* AmigaOS sees 4:3 modes as square in the DisplayInfo database, * so we correct other modes to "4:3 equiv" here. */ xres = (xres * option_monitor_aspect_x) / 4; yres = (yres * option_monitor_aspect_y) / 3; } xdpi = (yres * ydpi) / xres; LOG(("XDPI = %ld, YDPI = %ld (DisplayInfo resolution %ld x %ld, corrected %ld x %ld)", xdpi, ydpi, dinfo.Resolution.x, dinfo.Resolution.y, xres, yres)); } } } ami_xdpi = xdpi; ami_devicedpi = (xdpi << 16) | ydpi; }
css_error css__initial_orphans(css_select_state *state) { return set_orphans(state->computed, CSS_ORPHANS_SET, INTTOFIX(2)); }
/** * Parse a colour specifier * * \param c Parsing context * \param vector Vector of tokens to process * \param ctx Pointer to vector iteration context * \param value Pointer to location to receive value * \param result Pointer to location to receive result (AARRGGBB) * \return CSS_OK on success, * CSS_INVALID if the input is invalid * * Post condition: \a *ctx is updated with the next token to process * If the input is invalid, then \a *ctx remains unchanged. */ css_error css__parse_colour_specifier(css_language *c, const parserutils_vector *vector, int *ctx, uint16_t *value, uint32_t *result) { int orig_ctx = *ctx; const css_token *token; bool match; css_error error; consumeWhitespace(vector, ctx); /* IDENT(<colour name>) | * HASH(rgb | rrggbb) | * FUNCTION(rgb) [ [ NUMBER | PERCENTAGE ] ',' ] {3} ')' * FUNCTION(rgba) [ [ NUMBER | PERCENTAGE ] ',' ] {4} ')' * FUNCTION(hsl) ANGLE ',' PERCENTAGE ',' PERCENTAGE ')' * FUNCTION(hsla) ANGLE ',' PERCENTAGE ',' PERCENTAGE ',' NUMBER ')' * * For quirks, NUMBER | DIMENSION | IDENT, too * I.E. "123456" -> NUMBER, "1234f0" -> DIMENSION, "f00000" -> IDENT */ token = parserutils_vector_iterate(vector, ctx); if (token == NULL || (token->type != CSS_TOKEN_IDENT && token->type != CSS_TOKEN_HASH && token->type != CSS_TOKEN_FUNCTION)) { if (c->sheet->quirks_allowed == false || token == NULL || (token->type != CSS_TOKEN_NUMBER && token->type != CSS_TOKEN_DIMENSION)) goto invalid; } if (token->type == CSS_TOKEN_IDENT) { if ((lwc_string_caseless_isequal( token->idata, c->strings[TRANSPARENT], &match) == lwc_error_ok && match)) { *value = COLOR_TRANSPARENT; *result = 0; /* black transparent */ return CSS_OK; } else if ((lwc_string_caseless_isequal( token->idata, c->strings[CURRENTCOLOR], &match) == lwc_error_ok && match)) { *value = COLOR_CURRENT_COLOR; *result = 0; return CSS_OK; } error = css__parse_named_colour(c, token->idata, result); if (error != CSS_OK && c->sheet->quirks_allowed) { error = css__parse_hash_colour(token->idata, result); if (error == CSS_OK) c->sheet->quirks_used = true; } if (error != CSS_OK) goto invalid; } else if (token->type == CSS_TOKEN_HASH) { error = css__parse_hash_colour(token->idata, result); if (error != CSS_OK) goto invalid; } else if (c->sheet->quirks_allowed && token->type == CSS_TOKEN_NUMBER) { error = css__parse_hash_colour(token->idata, result); if (error == CSS_OK) c->sheet->quirks_used = true; else goto invalid; } else if (c->sheet->quirks_allowed && token->type == CSS_TOKEN_DIMENSION) { error = css__parse_hash_colour(token->idata, result); if (error == CSS_OK) c->sheet->quirks_used = true; else goto invalid; } else if (token->type == CSS_TOKEN_FUNCTION) { uint8_t r = 0, g = 0, b = 0, a = 0xff; int colour_channels = 0; if ((lwc_string_caseless_isequal( token->idata, c->strings[RGB], &match) == lwc_error_ok && match)) { colour_channels = 3; } else if ((lwc_string_caseless_isequal( token->idata, c->strings[RGBA], &match) == lwc_error_ok && match)) { colour_channels = 4; } if ((lwc_string_caseless_isequal( token->idata, c->strings[HSL], &match) == lwc_error_ok && match)) { colour_channels = 5; } else if ((lwc_string_caseless_isequal( token->idata, c->strings[HSLA], &match) == lwc_error_ok && match)) { colour_channels = 6; } if (colour_channels == 3 || colour_channels == 4) { int i; css_token_type valid = CSS_TOKEN_NUMBER; uint8_t *components[4] = { &r, &g, &b, &a }; for (i = 0; i < colour_channels; i++) { uint8_t *component; css_fixed num; size_t consumed = 0; int32_t intval; bool int_only; component = components[i]; consumeWhitespace(vector, ctx); token = parserutils_vector_peek(vector, *ctx); if (token == NULL || (token->type != CSS_TOKEN_NUMBER && token->type != CSS_TOKEN_PERCENTAGE)) goto invalid; if (i == 0) valid = token->type; else if (i < 3 && token->type != valid) goto invalid; /* The alpha channel may be a float */ if (i < 3) int_only = (valid == CSS_TOKEN_NUMBER); else int_only = false; num = css__number_from_lwc_string(token->idata, int_only, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; if (valid == CSS_TOKEN_NUMBER) { if (i == 3) { /* alpha channel */ intval = FIXTOINT( FMUL(num, F_255)); } else { /* colour channels */ intval = FIXTOINT(num); } } else { intval = FIXTOINT( FDIV(FMUL(num, F_255), F_100)); } if (intval > 255) *component = 255; else if (intval < 0) *component = 0; else *component = intval; parserutils_vector_iterate(vector, ctx); consumeWhitespace(vector, ctx); token = parserutils_vector_peek(vector, *ctx); if (token == NULL) goto invalid; if (i != (colour_channels - 1) && tokenIsChar(token, ',')) { parserutils_vector_iterate(vector, ctx); } else if (i == (colour_channels - 1) && tokenIsChar(token, ')')) { parserutils_vector_iterate(vector, ctx); } else { goto invalid; } } } else if (colour_channels == 5 || colour_channels == 6) { /* hue - saturation - lightness */ size_t consumed = 0; css_fixed hue, sat, lit; int32_t alpha = 255; /* hue is a number without a unit representing an * angle (0-360) degrees */ consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER)) goto invalid; hue = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ /* Normalise hue to the range [0, 360) */ while (hue < 0) hue += F_360; while (hue >= F_360) hue -= F_360; consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (!tokenIsChar(token, ',')) goto invalid; /* saturation */ consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_PERCENTAGE)) goto invalid; sat = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ /* Normalise saturation to the range [0, 100] */ if (sat < INTTOFIX(0)) sat = INTTOFIX(0); else if (sat > INTTOFIX(100)) sat = INTTOFIX(100); consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (!tokenIsChar(token, ',')) goto invalid; /* lightness */ consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_PERCENTAGE)) goto invalid; lit = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ /* Normalise lightness to the range [0, 100] */ if (lit < INTTOFIX(0)) lit = INTTOFIX(0); else if (lit > INTTOFIX(100)) lit = INTTOFIX(100); consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if (colour_channels == 6) { /* alpha */ if (!tokenIsChar(token, ',')) goto invalid; consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); if ((token == NULL) || (token->type != CSS_TOKEN_NUMBER)) goto invalid; alpha = css__number_from_lwc_string(token->idata, false, &consumed); if (consumed != lwc_string_length(token->idata)) goto invalid; /* failed to consume the whole string as a number */ alpha = FIXTOINT(FMUL(alpha, F_255)); consumeWhitespace(vector, ctx); token = parserutils_vector_iterate(vector, ctx); } if (!tokenIsChar(token, ')')) goto invalid; /* have a valid HSV entry, convert to RGB */ HSL_to_RGB(hue, sat, lit, &r, &g, &b); /* apply alpha */ if (alpha > 255) a = 255; else if (alpha < 0) a = 0; else a = alpha; } else { goto invalid; } *result = (a << 24) | (r << 16) | (g << 8) | b; } *value = COLOR_SET; return CSS_OK; invalid: *ctx = orig_ctx; return CSS_INVALID; }
/** * Convert Hue Saturation Lightness value to RGB. * * \param hue Hue in degrees 0..360 * \param sat Saturation value in percent 0..100 * \param lit Lightness value in percent 0..100 * \param r red component * \param g green component * \param b blue component */ static void HSL_to_RGB(css_fixed hue, css_fixed sat, css_fixed lit, uint8_t *r, uint8_t *g, uint8_t *b) { css_fixed min_rgb, max_rgb, chroma; css_fixed relative_hue, scaled_hue, mid1, mid2; int sextant; #define ORGB(R, G, B) \ *r = FIXTOINT(FDIV(FMUL((R), F_255), F_100)); \ *g = FIXTOINT(FDIV(FMUL((G), F_255), F_100)); \ *b = FIXTOINT(FDIV(FMUL((B), F_255), F_100)) /* If saturation is zero there is no hue and r = g = b = lit */ if (sat == INTTOFIX(0)) { ORGB(lit, lit, lit); return; } /* Compute max(r,g,b) */ if (lit <= INTTOFIX(50)) { max_rgb = FDIV(FMUL(lit, FADD(sat, F_100)), F_100); } else { max_rgb = FDIV(FSUB(FMUL(FADD(lit, sat), F_100), FMUL(lit, sat)), F_100); } /* Compute min(r,g,b) */ min_rgb = FSUB(FMUL(lit, INTTOFIX(2)), max_rgb); /* We know that the value of at least one of the components is * max(r,g,b) and that the value of at least one of the other * components is min(r,g,b). * * We can determine which components have these values by * considering which the sextant of the hexcone the hue lies * in: * * Sextant: max(r,g,b): min(r,g,b): * * 0 r b * 1 g b * 2 g r * 3 b r * 4 b g * 5 r g * * Thus, we need only compute the value of the third component */ /* Chroma is the difference between min and max */ chroma = FSUB(max_rgb, min_rgb); /* Compute which sextant the hue lies in (truncates result) */ hue = FDIV(FMUL(hue, INTTOFIX(6)), F_360); sextant = FIXTOINT(hue); /* Compute offset of hue from start of sextant */ relative_hue = FSUB(hue, INTTOFIX(sextant)); /* Scale offset by chroma */ scaled_hue = FMUL(relative_hue, chroma); /* Compute potential values of the third colour component */ mid1 = FADD(min_rgb, scaled_hue); mid2 = FSUB(max_rgb, scaled_hue); /* Populate result */ switch (sextant) { case 0: ORGB(max_rgb, mid1, min_rgb); break; case 1: ORGB(mid2, max_rgb, min_rgb); break; case 2: ORGB(min_rgb, max_rgb, mid1); break; case 3: ORGB(min_rgb, mid2, max_rgb); break; case 4: ORGB(mid1, min_rgb, max_rgb); break; case 5: ORGB(max_rgb, min_rgb, mid2); break; } #undef ORGB }
/** * Convert a CSS length to pixels. * * \param length Length to convert * \param unit Corresponding unit * \param style Computed style applying to length. May be NULL if unit is * neither em nor ex * \return length in pixels */ css_fixed nscss_len2px(css_fixed length, css_unit unit, const css_computed_style *style) { /* We assume the screen and ay other output has the same dpi */ css_fixed px_per_unit; assert(style != NULL || (unit != CSS_UNIT_EM && unit != CSS_UNIT_EX)); switch (unit) { case CSS_UNIT_EM: case CSS_UNIT_EX: { css_fixed font_size = 0; css_unit font_unit = CSS_UNIT_PT; css_computed_font_size(style, &font_size, &font_unit); /* Convert to points */ font_size = nscss_len2pt(font_size, font_unit); /* Clamp to configured minimum */ if (font_size < FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10)) { font_size = FDIV(INTTOFIX(nsoption_int(font_min_size)), F_10); } /* Convert to pixels (manually, to maximise precision) * 1in = 72pt => 1pt = (DPI/72)px */ px_per_unit = FDIV(FMUL(font_size, nscss_screen_dpi), F_72); /* Scale ex units: we use a fixed ratio of 1ex = 0.6em */ if (unit == CSS_UNIT_EX) px_per_unit = FMUL(px_per_unit, FLTTOFIX(0.6)); } break; case CSS_UNIT_PX: px_per_unit = F_1; break; /* 1in = DPIpx */ case CSS_UNIT_IN: px_per_unit = nscss_screen_dpi; break; /* 1in = 2.54cm => 1cm = (DPI/2.54)px */ case CSS_UNIT_CM: px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(2.54)); break; /* 1in = 25.4mm => 1mm = (DPI/25.4)px */ case CSS_UNIT_MM: px_per_unit = FDIV(nscss_screen_dpi, FLTTOFIX(25.4)); break; /* 1in = 72pt => 1pt = (DPI/72)px */ case CSS_UNIT_PT: px_per_unit = FDIV(nscss_screen_dpi, F_72); break; /* 1pc = 12pt => 1in = 6pc => 1pc = (DPI/6)px */ case CSS_UNIT_PC: px_per_unit = FDIV(nscss_screen_dpi, INTTOFIX(6)); break; default: px_per_unit = 0; break; } /* Ensure we round px_per_unit to the nearest whole number of pixels: * the use of FIXTOINT() below will truncate. */ px_per_unit += F_0_5; /* Calculate total number of pixels */ return FMUL(length, TRUNCATEFIX(px_per_unit)); }
/** * Generates one of the predefined print settings sets. * * \param configuration the requested configuration * \param filename the filename or NULL * \param font_func font handling functions * \return print_settings in case if successful, NULL if unknown * configuration or lack of memory. */ struct print_settings *print_make_settings(print_configuration configuration, const char *filename, const struct font_functions *font_func) { struct print_settings *settings; css_fixed length = 0; css_unit unit = CSS_UNIT_MM; switch (configuration){ case PRINT_DEFAULT: settings = (struct print_settings*) malloc(sizeof(struct print_settings)); if (settings == NULL) return NULL; settings->page_width = DEFAULT_PAGE_WIDTH; settings->page_height = DEFAULT_PAGE_HEIGHT; settings->copies = DEFAULT_COPIES; settings->scale = DEFAULT_EXPORT_SCALE; length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM); settings->margins[MARGINLEFT] = nscss_len2px(length, unit, NULL); length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM); settings->margins[MARGINRIGHT] = nscss_len2px(length, unit, NULL); length = INTTOFIX(DEFAULT_MARGIN_TOP_MM); settings->margins[MARGINTOP] = nscss_len2px(length, unit, NULL); length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM); settings->margins[MARGINBOTTOM] = nscss_len2px(length, unit, NULL); break; /* use settings from the Export options tab */ case PRINT_OPTIONS: settings = (struct print_settings*) malloc(sizeof(struct print_settings)); if (settings == NULL) return NULL; settings->page_width = DEFAULT_PAGE_WIDTH; settings->page_height = DEFAULT_PAGE_HEIGHT; settings->copies = DEFAULT_COPIES; settings->scale = (float)nsoption_int(export_scale) / 100; length = INTTOFIX(nsoption_int(margin_left)); settings->margins[MARGINLEFT] = nscss_len2px(length, unit, NULL); length = INTTOFIX(nsoption_int(margin_right)); settings->margins[MARGINRIGHT] = nscss_len2px(length, unit, NULL); length = INTTOFIX(nsoption_int(margin_top)); settings->margins[MARGINTOP] = nscss_len2px(length, unit, NULL); length = INTTOFIX(nsoption_int(margin_bottom)); settings->margins[MARGINBOTTOM] = nscss_len2px(length, unit, NULL); break; default: return NULL; } /* Set font functions */ settings->font_func = font_func; /* Output filename, or NULL if printing */ if (filename != NULL) { settings->output = strdup(filename); if (settings->output == NULL) { free(settings); return NULL; } } else settings->output = NULL; return settings; }
/** * Compute the absolute values of a style * * \param parent Parent style, or NULL for tree root * \param style Computed style to process * \param compute_font_size Callback to calculate an absolute font-size * \param pw Private word for callback * \return CSS_OK on success. */ css_error compute_absolute_values(const css_computed_style *parent, css_computed_style *style, css_error (*compute_font_size)(void *pw, const css_hint *parent, css_hint *size), void *pw) { css_hint psize, size, ex_size; css_error error; /* Ensure font-size is absolute */ if (parent != NULL) { psize.status = get_font_size(parent, &psize.data.length.value, &psize.data.length.unit); } size.status = get_font_size(style, &size.data.length.value, &size.data.length.unit); error = compute_font_size(pw, parent != NULL ? &psize : NULL, &size); if (error != CSS_OK) return error; error = set_font_size(style, size.status, size.data.length.value, size.data.length.unit); if (error != CSS_OK) return error; /* Compute the size of an ex unit */ ex_size.status = CSS_FONT_SIZE_DIMENSION; ex_size.data.length.value = INTTOFIX(1); ex_size.data.length.unit = CSS_UNIT_EX; error = compute_font_size(pw, &size, &ex_size); if (error != CSS_OK) return error; /* Convert ex size into ems */ if (size.data.length.value != 0) ex_size.data.length.value = FDIV(ex_size.data.length.value, size.data.length.value); else ex_size.data.length.value = 0; ex_size.data.length.unit = CSS_UNIT_EM; /* Fix up background-position */ error = compute_absolute_length_pair(style, &ex_size.data.length, get_background_position, set_background_position); if (error != CSS_OK) return error; /* Fix up border-{top,right,bottom,left}-color */ error = compute_border_colors(style); if (error != CSS_OK) return error; /* Fix up border-{top,right,bottom,left}-width */ error = compute_absolute_border_width(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up sides */ error = compute_absolute_sides(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up height */ error = compute_absolute_length_auto(style, &ex_size.data.length, get_height, set_height); if (error != CSS_OK) return error; /* Fix up line-height (must be before vertical-align) */ error = compute_absolute_line_height(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up margins */ error = compute_absolute_margins(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up max-height */ error = compute_absolute_length_none(style, &ex_size.data.length, get_max_height, set_max_height); if (error != CSS_OK) return error; /* Fix up max-width */ error = compute_absolute_length_none(style, &ex_size.data.length, get_max_width, set_max_width); if (error != CSS_OK) return error; /* Fix up min-height */ error = compute_absolute_length(style, &ex_size.data.length, get_min_height, set_min_height); if (error != CSS_OK) return error; /* Fix up min-width */ error = compute_absolute_length(style, &ex_size.data.length, get_min_width, set_min_width); if (error != CSS_OK) return error; /* Fix up padding */ error = compute_absolute_padding(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up text-indent */ error = compute_absolute_length(style, &ex_size.data.length, get_text_indent, set_text_indent); if (error != CSS_OK) return error; /* Fix up vertical-align */ error = compute_absolute_vertical_align(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up width */ error = compute_absolute_length_auto(style, &ex_size.data.length, get_width, set_width); if (error != CSS_OK) return error; /* Uncommon properties */ if (style->uncommon != NULL) { /* Fix up border-spacing */ error = compute_absolute_length_pair(style, &ex_size.data.length, get_border_spacing, set_border_spacing); if (error != CSS_OK) return error; /* Fix up clip */ error = compute_absolute_clip(style, &ex_size.data.length); if (error != CSS_OK) return error; /* Fix up letter-spacing */ error = compute_absolute_length_normal(style, &ex_size.data.length, get_letter_spacing, set_letter_spacing); if (error != CSS_OK) return error; /* Fix up outline-width */ error = compute_absolute_border_side_width(style, &ex_size.data.length, get_outline_width, set_outline_width); if (error != CSS_OK) return error; /* Fix up word spacing */ error = compute_absolute_length_normal(style, &ex_size.data.length, get_word_spacing, set_word_spacing); if (error != CSS_OK) return error; } return CSS_OK; }
css_error css__initial_opacity(css_select_state *state) { return set_opacity(state->computed, CSS_OPACITY_SET, INTTOFIX(1)); }
/** * Font size computation callback for libcss * * \param pw Computation context * \param parent Parent font size (absolute) * \param size Font size to compute * \return CSS_OK on success * * \post \a size will be an absolute font size */ css_error nscss_compute_font_size(void *pw, const css_hint *parent, css_hint *size) { /** * Table of font-size keyword scale factors * * These are multiplied by the configured default font size * to produce an absolute size for the relevant keyword */ static const css_fixed factors[] = { FLTTOFIX(0.5625), /* xx-small */ FLTTOFIX(0.6250), /* x-small */ FLTTOFIX(0.8125), /* small */ FLTTOFIX(1.0000), /* medium */ FLTTOFIX(1.1250), /* large */ FLTTOFIX(1.5000), /* x-large */ FLTTOFIX(2.0000) /* xx-large */ }; css_hint_length parent_size; /* Grab parent size, defaulting to medium if none */ if (parent == NULL) { parent_size.value = FDIV(FMUL(factors[CSS_FONT_SIZE_MEDIUM - 1], INTTOFIX(nsoption_int(font_size))), INTTOFIX(10)); parent_size.unit = CSS_UNIT_PT; } else { assert(parent->status == CSS_FONT_SIZE_DIMENSION); assert(parent->data.length.unit != CSS_UNIT_EM); assert(parent->data.length.unit != CSS_UNIT_EX); assert(parent->data.length.unit != CSS_UNIT_PCT); parent_size = parent->data.length; } assert(size->status != CSS_FONT_SIZE_INHERIT); if (size->status < CSS_FONT_SIZE_LARGER) { /* Keyword -- simple */ size->data.length.value = FDIV(FMUL(factors[size->status - 1], INTTOFIX(nsoption_int(font_size))), F_10); size->data.length.unit = CSS_UNIT_PT; } else if (size->status == CSS_FONT_SIZE_LARGER) { /** \todo Step within table, if appropriate */ size->data.length.value = FMUL(parent_size.value, FLTTOFIX(1.2)); size->data.length.unit = parent_size.unit; } else if (size->status == CSS_FONT_SIZE_SMALLER) { /** \todo Step within table, if appropriate */ size->data.length.value = FDIV(parent_size.value, FLTTOFIX(1.2)); size->data.length.unit = parent_size.unit; } else if (size->data.length.unit == CSS_UNIT_EM || size->data.length.unit == CSS_UNIT_EX || size->data.length.unit == CSS_UNIT_CAP || size->data.length.unit == CSS_UNIT_CH || size->data.length.unit == CSS_UNIT_IC) { size->data.length.value = FMUL(size->data.length.value, parent_size.value); switch (size->data.length.unit) { case CSS_UNIT_EX: /* 1ex = 0.6em in NetSurf */ size->data.length.value = FMUL(size->data.length.value, FLTTOFIX(0.6)); break; case CSS_UNIT_CAP: /* Height of captals. 1cap = 0.9em in NetSurf. */ size->data.length.value = FMUL(size->data.length.value, FLTTOFIX(0.9)); break; case CSS_UNIT_CH: /* Width of '0'. 1ch = 0.4em in NetSurf. */ size->data.length.value = FMUL(size->data.length.value, FLTTOFIX(0.4)); break; case CSS_UNIT_IC: /* Width of U+6C43. 1ic = 1.1em in NetSurf. */ size->data.length.value = FMUL(size->data.length.value, FLTTOFIX(1.1)); break; default: /* No scaling required for EM. */ break; } size->data.length.unit = parent_size.unit; } else if (size->data.length.unit == CSS_UNIT_PCT) { size->data.length.value = FDIV(FMUL(size->data.length.value, parent_size.value), INTTOFIX(100)); size->data.length.unit = parent_size.unit; } else if (size->data.length.unit == CSS_UNIT_REM) { nscss_select_ctx *ctx = pw; if (parent == NULL) { size->data.length.value = parent_size.value; size->data.length.unit = parent_size.unit; } else { css_computed_font_size(ctx->root_style, &parent_size.value, &size->data.length.unit); size->data.length.value = FMUL( size->data.length.value, parent_size.value); } } else if (size->data.length.unit == CSS_UNIT_RLH) { /** TODO: Convert root element line-height to absolute value. */ size->data.length.value = FMUL(size->data.length.value, FDIV( INTTOFIX(nsoption_int(font_size)), INTTOFIX(10))); size->data.length.unit = CSS_UNIT_PT; } size->status = CSS_FONT_SIZE_DIMENSION; return CSS_OK; }
static nserror html_object_callback(hlcache_handle *object, const hlcache_event *event, void *pw) { struct content_html_object *o = pw; html_content *c = (html_content *) o->parent; int x, y; struct box *box; assert(c->base.status != CONTENT_STATUS_ERROR); box = o->box; if (box == NULL && event->type != CONTENT_MSG_ERROR) { return NSERROR_OK; } switch (event->type) { case CONTENT_MSG_LOADING: if (c->base.status != CONTENT_STATUS_LOADING && c->bw != NULL) content_open(object, c->bw, &c->base, box->object_params); break; case CONTENT_MSG_READY: if (content_can_reformat(object)) { /* TODO: avoid knowledge of box internals here */ content_reformat(object, false, box->max_width != UNKNOWN_MAX_WIDTH ? box->width : 0, box->max_width != UNKNOWN_MAX_WIDTH ? box->height : 0); /* Adjust parent content for new object size */ html_object_done(box, object, o->background); if (c->base.status == CONTENT_STATUS_READY || c->base.status == CONTENT_STATUS_DONE) content__reformat(&c->base, false, c->base.available_width, c->base.height); } break; case CONTENT_MSG_DONE: c->base.active--; LOG("%d fetches active", c->base.active); html_object_done(box, object, o->background); if (c->base.status != CONTENT_STATUS_LOADING && box->flags & REPLACE_DIM) { union content_msg_data data; if (!box_visible(box)) break; box_coords(box, &x, &y); data.redraw.x = x + box->padding[LEFT]; data.redraw.y = y + box->padding[TOP]; data.redraw.width = box->width; data.redraw.height = box->height; data.redraw.full_redraw = true; content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); } break; case CONTENT_MSG_ERROR: hlcache_handle_release(object); o->content = NULL; if (box != NULL) { c->base.active--; LOG("%d fetches active", c->base.active); content_add_error(&c->base, "?", 0); html_object_failed(box, c, o->background); } break; case CONTENT_MSG_REDRAW: if (c->base.status != CONTENT_STATUS_LOADING) { union content_msg_data data = event->data; if (!box_visible(box)) break; box_coords(box, &x, &y); if (object == box->background) { /* Redraw request is for background */ css_fixed hpos = 0, vpos = 0; css_unit hunit = CSS_UNIT_PX; css_unit vunit = CSS_UNIT_PX; int width = box->padding[LEFT] + box->width + box->padding[RIGHT]; int height = box->padding[TOP] + box->height + box->padding[BOTTOM]; int t, h, l, w; /* Need to know background-position */ css_computed_background_position(box->style, &hpos, &hunit, &vpos, &vunit); w = content_get_width(box->background); if (hunit == CSS_UNIT_PCT) { l = (width - w) * hpos / INTTOFIX(100); } else { l = FIXTOINT(nscss_len2px(hpos, hunit, box->style)); } h = content_get_height(box->background); if (vunit == CSS_UNIT_PCT) { t = (height - h) * vpos / INTTOFIX(100); } else { t = FIXTOINT(nscss_len2px(vpos, vunit, box->style)); } /* Redraw area depends on background-repeat */ switch (css_computed_background_repeat( box->style)) { case CSS_BACKGROUND_REPEAT_REPEAT: data.redraw.x = 0; data.redraw.y = 0; data.redraw.width = box->width; data.redraw.height = box->height; break; case CSS_BACKGROUND_REPEAT_REPEAT_X: data.redraw.x = 0; data.redraw.y += t; data.redraw.width = box->width; break; case CSS_BACKGROUND_REPEAT_REPEAT_Y: data.redraw.x += l; data.redraw.y = 0; data.redraw.height = box->height; break; case CSS_BACKGROUND_REPEAT_NO_REPEAT: data.redraw.x += l; data.redraw.y += t; break; default: break; } data.redraw.object_width = box->width; data.redraw.object_height = box->height; /* Add offset to box */ data.redraw.x += x; data.redraw.y += y; data.redraw.object_x += x; data.redraw.object_y += y; content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); break; } else { /* Non-background case */ if (hlcache_handle_get_content(object) == event->data.redraw.object) { int w = content_get_width(object); int h = content_get_height(object); if (w != 0) { data.redraw.x = data.redraw.x * box->width / w; data.redraw.width = data.redraw.width * box->width / w; } if (h != 0) { data.redraw.y = data.redraw.y * box->height / h; data.redraw.height = data.redraw.height * box->height / h; } data.redraw.object_width = box->width; data.redraw.object_height = box->height; } data.redraw.x += x + box->padding[LEFT]; data.redraw.y += y + box->padding[TOP]; data.redraw.object_x += x + box->padding[LEFT]; data.redraw.object_y += y + box->padding[TOP]; } content_broadcast(&c->base, CONTENT_MSG_REDRAW, data); } break; case CONTENT_MSG_REFRESH: if (content_get_type(object) == CONTENT_HTML) { /* only for HTML objects */ guit->misc->schedule(event->data.delay * 1000, html_object_refresh, o); } break; case CONTENT_MSG_LINK: /* Don't care about favicons that aren't on top level content */ break; case CONTENT_MSG_GETCTX: *(event->data.jscontext) = NULL; break; case CONTENT_MSG_SCROLL: if (box->scroll_x != NULL) scrollbar_set(box->scroll_x, event->data.scroll.x0, false); if (box->scroll_y != NULL) scrollbar_set(box->scroll_y, event->data.scroll.y0, false); break; case CONTENT_MSG_DRAGSAVE: { union content_msg_data msg_data; if (event->data.dragsave.content == NULL) msg_data.dragsave.content = object; else msg_data.dragsave.content = event->data.dragsave.content; content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, msg_data); } break; case CONTENT_MSG_SAVELINK: case CONTENT_MSG_POINTER: case CONTENT_MSG_SELECTMENU: case CONTENT_MSG_GADGETCLICK: /* These messages are for browser window layer. * we're not interested, so pass them on. */ content_broadcast(&c->base, event->type, event->data); break; case CONTENT_MSG_CARET: { union html_focus_owner focus_owner; focus_owner.content = box; switch (event->data.caret.type) { case CONTENT_CARET_REMOVE: case CONTENT_CARET_HIDE: html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner, true, 0, 0, 0, NULL); break; case CONTENT_CARET_SET_POS: html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner, false, event->data.caret.pos.x, event->data.caret.pos.y, event->data.caret.pos.height, event->data.caret.pos.clip); break; } } break; case CONTENT_MSG_DRAG: { html_drag_type drag_type = HTML_DRAG_NONE; union html_drag_owner drag_owner; drag_owner.content = box; switch (event->data.drag.type) { case CONTENT_DRAG_NONE: drag_type = HTML_DRAG_NONE; drag_owner.no_owner = true; break; case CONTENT_DRAG_SCROLL: drag_type = HTML_DRAG_CONTENT_SCROLL; break; case CONTENT_DRAG_SELECTION: drag_type = HTML_DRAG_CONTENT_SELECTION; break; } html_set_drag_type(c, drag_type, drag_owner, event->data.drag.rect); } break; case CONTENT_MSG_SELECTION: { html_selection_type sel_type; union html_selection_owner sel_owner; if (event->data.selection.selection) { sel_type = HTML_SELECTION_CONTENT; sel_owner.content = box; } else { sel_type = HTML_SELECTION_NONE; sel_owner.none = true; } html_set_selection(c, sel_type, sel_owner, event->data.selection.read_only); } break; default: break; } if (c->base.status == CONTENT_STATUS_READY && c->base.active == 0 && (event->type == CONTENT_MSG_LOADING || event->type == CONTENT_MSG_DONE || event->type == CONTENT_MSG_ERROR)) { /* all objects have arrived */ content__reformat(&c->base, false, c->base.available_width, c->base.height); content_set_done(&c->base); } /* If 1) the configuration option to reflow pages while objects are * fetched is set * 2) an object is newly fetched & converted, * 3) the box's dimensions need to change due to being replaced * 4) the object's parent HTML is ready for reformat, * 5) the time since the previous reformat is more than the * configured minimum time between reformats * then reformat the page to display newly fetched objects */ else if (nsoption_bool(incremental_reflow) && event->type == CONTENT_MSG_DONE && box != NULL && !(box->flags & REPLACE_DIM) && (c->base.status == CONTENT_STATUS_READY || c->base.status == CONTENT_STATUS_DONE) && (wallclock() > c->base.reformat_time)) { content__reformat(&c->base, false, c->base.available_width, c->base.height); } return NSERROR_OK; }