[gnumeric] ods: speed up saving large sheets; reduce file size.



commit 523a6ae76617224b7f70158ceabde5ed687492c1
Author: Morten Welinder <terra gnome org>
Date:   Mon Oct 15 09:45:10 2012 -0400

    ods: speed up saving large sheets; reduce file size.

 NEWS                                  |    1 +
 plugins/openoffice/ChangeLog          |    6 +
 plugins/openoffice/openoffice-write.c |  196 +++++++++++++++++++++++----------
 src/sheet-style.c                     |   45 ++++++++
 src/sheet-style.h                     |    3 +
 5 files changed, 195 insertions(+), 56 deletions(-)
---
diff --git a/NEWS b/NEWS
index d64d044..d05b9a0 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Jean:
 
 Morten:
 	* Fix xlsx save performance problems.  [#662058]  [#685530]
+	* Fix ods save performance problems.  [#662057]
 
 Weng Xuetian:
         * Fix interaction with ibus & fcitx. [#684511]
diff --git a/plugins/openoffice/ChangeLog b/plugins/openoffice/ChangeLog
index 75bf415..2f468a4 100644
--- a/plugins/openoffice/ChangeLog
+++ b/plugins/openoffice/ChangeLog
@@ -1,3 +1,9 @@
+2012-10-15  Morten Welinder  <terra gnome org>
+
+	* openoffice-write.c (odf_write_content_rows): Merge boring rows
+	into one with a repeat count.  Skip cell loop for boring rows.
+	Fixes 662057.
+
 2012-09-11  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* openoffice-read.c (odf_custom_shape_end): only split on "N" that
diff --git a/plugins/openoffice/openoffice-write.c b/plugins/openoffice/openoffice-write.c
index cdd7c57..04dc2a1 100644
--- a/plugins/openoffice/openoffice-write.c
+++ b/plugins/openoffice/openoffice-write.c
@@ -2731,8 +2731,8 @@ odf_expr_conventions_new (void)
 static gboolean
 odf_cell_is_covered (G_GNUC_UNUSED Sheet const *sheet,
 		     G_GNUC_UNUSED GnmCell *current_cell,
-		    int col, int row, GnmRange const *merge_range,
-		    GSList **merge_ranges)
+		     int col, int row, GnmRange const *merge_range,
+		     GSList **merge_ranges)
 {
 	GSList *l;
 
@@ -3415,6 +3415,25 @@ write_row_style (GnmOOExport *state, ColRowInfo const *ci,
 		gsf_xml_out_add_cstr (state->xml, TABLE "style-name", name);
 }
 
+static gboolean
+row_style_eq (GnmOOExport *state, Sheet const *sheet,
+	      ColRowInfo const *ci1, ColRowInfo const *ci2)
+{
+	if (ci1 == ci2)
+		return TRUE;
+	else {
+		char const *n1 =
+			odf_find_row_style (state,
+					    (ci1 == NULL) ? &sheet->rows.default_style: ci1,
+					    FALSE);
+		char const *n2 =
+			odf_find_row_style (state,
+					    (ci2 == NULL) ? &sheet->rows.default_style: ci2,
+					    FALSE);
+		return g_str_equal (n1, n2);
+	}
+}
+
 
 static gint
 finder (gconstpointer a, gconstpointer b)
@@ -3534,20 +3553,66 @@ odf_sheet_objects_get (Sheet const *sheet, GnmCellPos const *pos)
 	return res;
 }
 
+enum {
+	RF_CELL = 1,
+	RF_PAGEBREAK = 2,
+	RF_OBJECT = 4,
+	RF_STYLE = 8
+};
+
 static void
 odf_write_content_rows (GnmOOExport *state, Sheet const *sheet, int from, int to,
 			G_GNUC_UNUSED int col_from, G_GNUC_UNUSED int col_to, int row_length,
-			GSList **sheet_merges, GnmPageBreaks *pb, G_GNUC_UNUSED GnmStyle **col_styles)
+			GSList **sheet_merges, GnmPageBreaks *pb, GnmStyle **col_styles)
 {
-	int col, row;
-	GnmRange fake_extent;
+	int row;
 	GPtrArray *all_cells;
 	guint cno = 0;
+	guint8 *row_flags;
 
-	range_init_rows (&fake_extent, sheet, from, to - 1);
-	all_cells = sheet_cells ((Sheet*)sheet, &fake_extent);
-	/* Add a NULL to simplify code.  */
-	g_ptr_array_add (all_cells, NULL);
+	row_flags = g_new0 (guint8, gnm_sheet_get_max_rows (sheet));
+
+	/* Find out what rows have objects.  */
+	{
+		GSList *ptr;
+
+		for (ptr = sheet->sheet_objects; ptr != NULL ; ptr = ptr->next ) {
+			SheetObject *so = SHEET_OBJECT (ptr->data);
+			SheetObjectAnchor const *anchor = sheet_object_get_anchor (so);
+			int row = anchor->cell_bound.start.row;
+			row_flags[row] |= RF_OBJECT;
+		}
+	}
+
+	/* Find out what rows have page breaks.  */
+	for (row = from; row < to; row++) {
+		if (gnm_page_breaks_get_break (pb, row) != GNM_PAGE_BREAK_NONE)
+			row_flags[row] |= RF_PAGEBREAK;
+	}
+
+	/* Find out what rows have cells.  */
+	{
+		GnmRange fake_extent;
+		unsigned ui;
+		range_init_rows (&fake_extent, sheet, from, to - 1);
+		all_cells = sheet_cells ((Sheet*)sheet, &fake_extent);
+		for (ui = 0; ui < all_cells->len; ui++) {
+			GnmCell *cell = g_ptr_array_index (all_cells, ui);
+			row_flags[cell->pos.row] |= RF_CELL;
+		}
+		/* Add a NULL to simplify code.  */
+		g_ptr_array_add (all_cells, NULL);
+	}
+
+	/* Find out what rows have style not covered by column styles.  */
+	{
+		guint8 *non_defaults_rows =
+			sheet_style_get_nondefault_rows (sheet, col_styles);
+		for (row = from; row < to; row++)
+			if (non_defaults_rows[row])
+				row_flags[row] |= RF_STYLE;
+		g_free (non_defaults_rows);
+	}
 
 	for (row = from; row < to; row++) {
 		ColRowInfo const *ci = sheet_row_get (sheet, row);
@@ -3558,7 +3623,7 @@ odf_write_content_rows (GnmOOExport *state, Sheet const *sheet, int from, int to
 
 		pos.row = row;
 
-		if (gnm_page_breaks_get_break (pb, row) != GNM_PAGE_BREAK_NONE)
+		if (row_flags[row] & RF_PAGEBREAK)
 			gsf_xml_out_simple_element (state->xml,
 						    TEXT "soft-page-break",
 						    NULL);
@@ -3566,59 +3631,77 @@ odf_write_content_rows (GnmOOExport *state, Sheet const *sheet, int from, int to
 		gsf_xml_out_start_element (state->xml, TABLE "table-row");
 		write_row_style (state, ci, sheet);
 
-		for (col = 0; col < row_length; col++) {
-			GnmCell *current_cell;
-			GnmRange const	*merge_range;
-			GSList *objects;
-			GnmStyle const *this_style;
-
-			current_cell = g_ptr_array_index (all_cells, cno);
-			if (current_cell &&
-			    current_cell->pos.row == row &&
-			    current_cell->pos.col == col)
-				cno++;
-			else
-				current_cell = NULL;
+		if (row_flags[row] == 0) {
+			int count = 1;
+			while (row + count < to &&
+			       row_flags[row + count] == 0 &&
+			       row_style_eq (state, sheet, ci, sheet_row_get (sheet, row + count)))
+				count++;
+			if (count > 1) {
+				gsf_xml_out_add_int (state->xml, TABLE "number-rows-repeated",
+						     count);
+				row += (count - 1);
+			}
 
-			pos.col = col;
-			merge_range = gnm_sheet_merge_is_corner (sheet, &pos);
+		} else {
+			int col;
+
+			for (col = 0; col < row_length; col++) {
+				GnmCell *current_cell;
+				GnmRange const	*merge_range;
+				GSList *objects;
+				GnmStyle const *this_style;
+
+				current_cell = g_ptr_array_index (all_cells, cno);
+				if (current_cell &&
+				    current_cell->pos.row == row &&
+				    current_cell->pos.col == col)
+					cno++;
+				else
+					current_cell = NULL;
 
-			if (odf_cell_is_covered (sheet, current_cell, col, row,
-						merge_range, sheet_merges)) {
-				odf_write_empty_cell (state, null_cell, null_style, NULL);
-				null_cell = 0;
-				covered_cell++;
-				continue;
-			}
+				pos.col = col;
+				merge_range = gnm_sheet_merge_is_corner (sheet, &pos);
 
-			objects = odf_sheet_objects_get (sheet, &pos);
-
-			if ((!(current_cell && gnm_cell_has_expr(current_cell))) &&
-			    (merge_range == NULL) && (objects == NULL) &&
-			    gnm_cell_is_empty (current_cell) &&
-			    NULL == gnm_style_get_hlink
-			    ((this_style = sheet_style_get (sheet, pos.col, pos.row)))) {
-				if ((null_cell == 0) || (null_style == this_style)) {
-					null_style = this_style;
-					if (covered_cell > 0)
-						odf_write_covered_cell (state, &covered_cell);
-					null_cell++;
-				} else {
+				if (odf_cell_is_covered (sheet, current_cell, col, row,
+							 merge_range, sheet_merges)) {
 					odf_write_empty_cell (state, null_cell, null_style, NULL);
-					null_style = this_style;
-					null_cell = 1;
+					null_cell = 0;
+					covered_cell++;
+					continue;
+				}
+
+				objects = (row_flags[row] & RF_OBJECT)
+					? odf_sheet_objects_get (sheet, &pos)
+					: NULL;
+
+				if ((!(current_cell && gnm_cell_has_expr(current_cell))) &&
+				    (merge_range == NULL) && (objects == NULL) &&
+				    gnm_cell_is_empty (current_cell) &&
+				    NULL == gnm_style_get_hlink
+				    ((this_style = sheet_style_get (sheet, pos.col, pos.row)))) {
+					if ((null_cell == 0) || (null_style == this_style)) {
+						null_style = this_style;
+						if (covered_cell > 0)
+							odf_write_covered_cell (state, &covered_cell);
+						null_cell++;
+					} else {
+						odf_write_empty_cell (state, null_cell, null_style, NULL);
+						null_style = this_style;
+						null_cell = 1;
+					}
+					continue;
 				}
-				continue;
-			}
 
-			odf_write_empty_cell (state, null_cell, null_style, NULL);
-			null_cell = 0;
-			if (covered_cell > 0)
-				odf_write_covered_cell (state, &covered_cell);
-			odf_write_cell (state, current_cell, merge_range, objects);
+				odf_write_empty_cell (state, null_cell, null_style, NULL);
+				null_cell = 0;
+				if (covered_cell > 0)
+					odf_write_covered_cell (state, &covered_cell);
+				odf_write_cell (state, current_cell, merge_range, objects);
 
-			g_slist_free (objects);
+				g_slist_free (objects);
 
+			}
 		}
 		odf_write_empty_cell (state, null_cell, null_style, NULL);
 		null_cell = 0;
@@ -3629,6 +3712,7 @@ odf_write_content_rows (GnmOOExport *state, Sheet const *sheet, int from, int to
 	}
 
 	g_ptr_array_free (all_cells, TRUE);
+	g_free (row_flags);
 }
 
 static void
diff --git a/src/sheet-style.c b/src/sheet-style.c
index 035c30c..daf84f3 100644
--- a/src/sheet-style.c
+++ b/src/sheet-style.c
@@ -2164,6 +2164,51 @@ sheet_style_is_default (Sheet const *sheet, const GnmRange *r, GnmStyle **col_de
 	return user.res;
 }
 
+struct cb_get_nondefault {
+	guint8 *res;
+	GnmStyle **col_defaults;
+};
+
+static void
+cb_get_nondefault (GnmStyle *style,
+		   int corner_col, G_GNUC_UNUSED int corner_row,
+		   int width, G_GNUC_UNUSED int height,
+		   GnmRange const *apply_to, gpointer user_)
+{
+	struct cb_get_nondefault *user = user_;
+	int i;
+
+	/* The given dimensions refer to the tile, not the area. */
+	width = MIN (width, apply_to->end.col - corner_col + 1);
+	height = MIN (height, apply_to->end.row - corner_row + 1);
+
+	for (i = 0; i < width; i++) {
+		if (style != user->col_defaults[corner_col + i]) {
+			int j;
+			for (j = 0; j < height; j++)
+				user->res[corner_row + j] = 1;
+			break;
+		}
+	}
+}
+
+guint8 * 
+sheet_style_get_nondefault_rows (Sheet const *sheet, GnmStyle **col_defaults)
+{
+	struct cb_get_nondefault user;
+	GnmRange r;
+
+	range_init_full_sheet (&r, sheet);
+
+	user.res = g_new0 (guint8, gnm_sheet_get_max_rows (sheet));
+	user.col_defaults = col_defaults;
+
+	foreach_tile (sheet->style_data->styles,
+		      sheet->tile_top_level, 0, 0, &r,
+		      cb_get_nondefault, &user);
+
+	return user.res;
+}
 
 struct cb_most_common {
 	GHashTable *h;
diff --git a/src/sheet-style.h b/src/sheet-style.h
index 4c1670d..0330352 100644
--- a/src/sheet-style.h
+++ b/src/sheet-style.h
@@ -47,6 +47,9 @@ unsigned int sheet_style_find_conflicts (Sheet const *sheet, GnmRange const *r,
 void	 sheet_style_get_extent		(Sheet const *sheet, GnmRange *r);
 void	 sheet_style_get_nondefault_extent (Sheet const *sheet, GnmRange *extent,
 					    const GnmRange *src, GnmStyle **col_defaults);
+guint8 * sheet_style_get_nondefault_rows (Sheet const *sheet,
+					  GnmStyle **col_defaults);
+					   
 gboolean sheet_style_is_default         (Sheet const *sheet, const GnmRange *r, GnmStyle **col_defaults);
 void     style_row_init			(GnmBorder const * * *prev_vert,
 					 GnmStyleRow *sr, GnmStyleRow *next_sr,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]