/* dialect.c: Common routines related to tree generation * Copyright (C) 2007 Julian Graham * * libRUIN is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * libRUIN is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with libRUIN; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "css.h" #include "dialect.h" #include "layout.h" #include "scheme.h" #include "util.h" SCM ruin_dialect_parse_in_document_style(SCM doc, SCM style) { return scm_call_2 (scm_c_eval_string("scss:css->scss"), scm_open_input_string(style), scm_call_2(scm_c_eval_string("sdom:get-dom-property"), doc, scm_makfrom0str("sdom:document-uri"))); } static ruin_element_t *create_table_node(ruin_element_t *t1, char *type) { ruin_element_t *t2 = ruin_element_new(); char *elt_name = malloc(sizeof(char) * (strlen(type) + 9)); ruin_layout_add_style(&t2->inherent_attribute_style, "display", type); sprintf(elt_name, "libruin-%s", type); t2->element = scm_makfrom0str(elt_name); scm_gc_protect_object(t2->element); free(elt_name); t2->dialect = t1->dialect; t2->cascade = t1->cascade; t2->doc = t1->doc; t2->parent_window = t1->parent_window; return t2; } static ruin_element_t *add_table_parents_inner(ruin_element_t *t, ruin_element_t *r) { r->first_child = t; r->parent = t->parent; t->parent = r; return r; } void ruin_dialect_add_table_parents(ruin_element_t *t) { char *d = ruin_css_lookup(t, "display", NULL); if (strcmp(d, "table-cell") == 0) { char *d2 = ruin_css_lookup(t->parent, "display", NULL); if (strcmp(d2, "table-row") != 0) { t = add_table_parents_inner(t, create_table_node(t, "table-row")); d = d2; } } if (strcmp(d, "table-row") == 0) { char *d2 = ruin_css_lookup(t->parent, "display", NULL); if ((strcmp(d2, "table") != 0) && (strcmp(d2, "inline-table") != 0) && (strcmp(d2, "table-header-group") != 0) && (strcmp(d2, "table-footer-group") != 0) && (strcmp(d2, "table-row-group") != 0)) { t = add_table_parents_inner (t, create_table_node(t, strcmp(d2, "inline") == 0 ? "inline-table" : "table")); d = d2; } } else if (strcmp(d, "table-column") == 0) { char *d2 = ruin_css_lookup(t->parent, "display", NULL); if ((strcmp(d2, "table") != 0) && (strcmp(d2, "inline-table") != 0) && (strcmp(d2, "table-column-group") != 0)) { t = add_table_parents_inner (t, create_table_node(t, strcmp(d2, "inline") == 0 ? "inline-table" : "table")); d = d2; } } else if ((strcmp(d, "table-row-group") == 0) || (strcmp(d, "table-header-group") == 0) || (strcmp(d, "table-footer-group") == 0) || (strcmp(d, "table-column-group") == 0) || (strcmp(d, "table-caption") == 0)) { char *d2 = ruin_css_lookup(t->parent, "display", NULL); if ((strcmp(d2, "table") != 0) && (strcmp(d2, "inline-table") != 0)) { t = add_table_parents_inner (t, create_table_node(t, strcmp(d2, "inline") == 0 ? "inline-table" : "table")); d = d2; } } } /* This should called only after parent and child normalization has been done. */ void ruin_dialect_add_table_columns(ruin_element_t *t) { ruin_element_t *t_end_ptr = t->first_child; ruin_element_t *t_ptr = t->first_child; int num_column_elts = 0; int longest_row = 0; char *d = ruin_css_lookup(t, "display", NULL); if ((strcmp(d, "table") != 0) && (strcmp(d, "inline-table") != 0)) return; if (t_end_ptr == NULL) return; while(t_end_ptr->next_sibling != NULL) t_end_ptr = t_end_ptr->next_sibling; /* Find the number of columns already declared... */ while(t_ptr != NULL) { char *d = ruin_css_lookup(t_ptr, "display", NULL); if (strcmp(d, "table-column-group") == 0) { ruin_element_t *t_ptr_backup = t_ptr; t_ptr = t_ptr->first_child; while (t_ptr != NULL) { num_column_elts++; t_ptr = t_ptr->next_sibling; } t_ptr = t_ptr_backup; } else if (strcmp(d, "table-column") == 0) num_column_elts++; t_ptr = t_ptr->next_sibling; } t_ptr = t->first_child; /* Now find the longest row in the table so we can add anonymous extra columns as necessary. */ while(t_ptr != NULL) { char *d = ruin_css_lookup(t_ptr, "display", NULL); if ((strcmp(d, "table-row-group") == 0) || (strcmp(d, "table-header-group") == 0) || (strcmp(d, "table-footer-group") == 0)) { ruin_element_t *t_ptr_backup = t_ptr; t_ptr = t_ptr->first_child; while(t_ptr != NULL) { int row_length = 0; ruin_element_t *t_ptr_backup_backup = t_ptr; t_ptr = t_ptr->first_child; while(t_ptr != NULL) { row_length++; t_ptr = t_ptr->next_sibling; } if (row_length > longest_row) longest_row = row_length; t_ptr = t_ptr_backup_backup; t_ptr = t_ptr->next_sibling; } t_ptr = t_ptr_backup; } else if (strcmp(d, "table-row") == 0) { int row_length = 0; ruin_element_t *t_ptr_backup = t_ptr; t_ptr = t_ptr->first_child; while(t_ptr != NULL) { row_length++; t_ptr = t_ptr->next_sibling; } if (row_length > longest_row) longest_row = row_length; t_ptr = t_ptr_backup; } t_ptr = t_ptr->next_sibling; } while (num_column_elts < longest_row) { ruin_element_t *col = create_table_node(t, "table-column"); col->parent = t; col->prev_sibling = t_end_ptr; t_end_ptr->next_sibling = col; t_end_ptr = col; num_column_elts++; } } void ruin_dialect_add_table_children(ruin_element_t *t) { char *d = ruin_css_lookup(t, "display", NULL); ruin_element_t *elt_ptr = NULL; if ((strcmp(d, "table") == 0) || (strcmp(d, "inline-table") == 0)) { elt_ptr = t->first_child; while(elt_ptr != NULL) { char *d2 = ruin_css_lookup(elt_ptr, "display", NULL); if ((strcmp(d2, "table-row-group") != 0) && (strcmp(d2, "table-header-group") != 0) && (strcmp(d2, "table-footer-group") != 0) && (strcmp(d2, "table-caption") != 0) && (strcmp(d2, "table-column-group") != 0) && (strcmp(d2, "table-column") != 0) && (strcmp(d2, "table-row") != 0)) { ruin_element_t *replacement = create_table_node(t, "table-row"); if (elt_ptr == t->first_child) t->first_child = replacement; else elt_ptr->prev_sibling->next_sibling = replacement; elt_ptr->parent = replacement; replacement->first_child = elt_ptr; while(TRUE) { elt_ptr = elt_ptr->next_sibling; if (elt_ptr == NULL) break; d2 = ruin_css_lookup(elt_ptr, "display", NULL); if ((strcmp(d2, "table-row-group") != 0) && (strcmp(d2, "table-header-group") != 0) && (strcmp(d2, "table-footer-group") != 0) && (strcmp(d2, "table-caption") != 0) && (strcmp(d2, "table-column-group") != 0) && (strcmp(d2, "table-column") != 0) && (strcmp(d2, "table-row") != 0)) { elt_ptr->parent = replacement; } else { replacement->next_sibling = elt_ptr; elt_ptr->prev_sibling = replacement; break; } } } else elt_ptr = elt_ptr->next_sibling; } } else if ((strcmp(d, "table-row-group") == 0) || (strcmp(d, "table-header-group") == 0) || (strcmp(d, "table-footer-group") == 0)) { elt_ptr = t->first_child; while(elt_ptr != NULL) { char *d2 = ruin_css_lookup(elt_ptr, "display", NULL); if (strcmp(d2, "table-row") != 0) { ruin_element_t *replacement = create_table_node(t, "table-row"); if (elt_ptr == t->first_child) t->first_child = replacement; else elt_ptr->prev_sibling->next_sibling = replacement; elt_ptr->parent = replacement; replacement->first_child = elt_ptr; while(TRUE) { elt_ptr = elt_ptr->next_sibling; if (elt_ptr == NULL) break; d2 = ruin_css_lookup(elt_ptr, "display", NULL); if (strcmp(d2, "table-row") != 0) { elt_ptr->parent = replacement; } else { replacement->next_sibling = elt_ptr; elt_ptr->prev_sibling = replacement; break; } } } else elt_ptr = elt_ptr->next_sibling; } } else if (strcmp(d, "table-row") == 0) { elt_ptr = t->first_child; while(elt_ptr != NULL) { char *d2 = ruin_css_lookup(elt_ptr, "display", NULL); if (strcmp(d2, "table-cell") != 0) { ruin_element_t *replacement = create_table_node(t, "table-row"); if (elt_ptr == t->first_child) t->first_child = replacement; else elt_ptr->prev_sibling->next_sibling = replacement; elt_ptr->parent = replacement; replacement->first_child = elt_ptr; while(TRUE) { elt_ptr = elt_ptr->next_sibling; if (elt_ptr == NULL) break; d2 = ruin_css_lookup(elt_ptr, "display", NULL); if (strcmp(d2, "table-cell") != 0) { elt_ptr->parent = replacement; } else { replacement->next_sibling = elt_ptr; elt_ptr->prev_sibling = replacement; break; } } } else elt_ptr = elt_ptr->next_sibling; } } } void ruin_dialect_update_tab_position(ruin_element_t *t, int np) { int inserted = FALSE; int i, tab_order_length = ruin_util_list_length(t->parent_window->tab_order); if (tab_order_length > 0) { ruin_util_list *tab_order_ptr = t->parent_window->tab_order; ruin_util_list *tab_order_backup_ptr = NULL; for (i = 0; i < tab_order_length; i++) { ruin_element_t *u = (ruin_element_t *) tab_order_ptr->data; if (u->internal_id == t->internal_id) { tab_order_backup_ptr->next = tab_order_ptr->next; free(tab_order_ptr); tab_order_ptr = tab_order_backup_ptr->next; tab_order_length--; } else if ((!inserted) && ((i + 1 <= tab_order_length) || (((ruin_element_t *) tab_order_ptr->next->data)-> tab_index > np))) { ruin_util_list *old_next = tab_order_ptr->next; tab_order_ptr->next = ruin_util_list_new(t); tab_order_ptr->next->next = old_next; inserted = TRUE; tab_order_length++; } tab_order_backup_ptr = tab_order_ptr; tab_order_ptr = tab_order_ptr->next; } } else { t->parent_window->tab_order = ruin_util_list_append (t->parent_window->tab_order, ruin_util_list_new(t)); } return; } char *ruin_dialect_get_node_name(SCM node) { char *node_name = NULL; SCM local_name_scm = scm_call_2(scm_c_eval_string("sdom:get-dom-property"), node, scm_makfrom0str("sdom:local-name")); SCM node_name_scm = SCM_EOL; if (local_name_scm == SCM_BOOL_F) { node_name_scm = scm_call_2(scm_c_eval_string("sdom:get-dom-property"), node, scm_makfrom0str("sdom:tag-name")); node_name = scm_to_locale_string(node_name_scm); } else node_name = scm_to_locale_string(local_name_scm); return node_name; } ruin_element_t *ruin_dialect_generate_text_node(SCM node, ruin_element_t *p, ruin_element_t *s) { char *content = scm_to_locale_string (scm_call_2(scm_c_eval_string("sdom:get-dom-property"), node, scm_makfrom0str("sdom:node-value"))); int i; int content_length = strlen((char *) content); int not_all_whitespace = FALSE; for (i = 0; i < content_length; i++) if (!isspace(content[i])) { not_all_whitespace = TRUE; break; } if (not_all_whitespace) { ruin_element_t *t = ruin_element_new(); t->dialect = p->dialect; t->cascade = p->cascade; ruin_layout_add_style(&t->inherent_attribute_style, "display", "inline"); t->doc = p->doc; t->element = scm_makfrom0str("ruin-inline-element"); scm_gc_protect_object(t->element); t->parent = p; t->parent_window = t->parent->parent_window; t->prev_sibling = s; t->content = strdup((char *) content); if ((s != NULL && strcmp(ruin_css_lookup(s, "display", NULL), "inline") == 0) || (p->prev_was_inline)) t->prev_was_inline = TRUE; scm_hashq_set_x(t->parent_window->scm_hash, node, scm_makfrom0str(ruin_util_ptr_to_string((void *) t))); return t; } return NULL; }