From f00b898dd13b85e510188714f6b9d9a349d23ed2 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 10 Jul 2006 21:04:30 +0000 Subject: New backend to support impress slides. Fixes bug #30867. 2006-07-11 Bastien Nocera * Makefile.am: * backend/Makefile.am: * backend/ev-document-factory.c: (ev_document_factory_add_filters): * backend/ev-document-factory.h: * configure.ac: * impress/.cvsignore: * impress/Makefile.am: * impress/common.h: * impress/document.c: (_imp_load_xml), (imp_open), (imp_nr_pages), (imp_get_page), (imp_next_page), (imp_prev_page), (imp_get_page_no), (imp_get_page_name), (imp_get_xml), (imp_close): * impress/f_oasis.c: (render_object), (render_page), (get_geometry), (_imp_oasis_load): * impress/f_oo13.c: (render_object), (render_page), (get_geometry), (_imp_oo13_load): * impress/iksemel.c: (iks_malloc), (iks_free), (iks_set_mem_funcs), (iks_strdup), (iks_strcat), (iks_strcmp), (iks_strcasecmp), (iks_strncmp), (iks_strncasecmp), (iks_strlen), (iks_escape), (iks_unescape), (find_space), (iks_stack_new), (iks_stack_alloc), (iks_stack_strdup), (iks_stack_strcat), (iks_stack_stat), (iks_stack_delete), (iks_sax_new), (iks_sax_extend), (iks_parser_stack), (iks_user_data), (iks_nr_bytes), (iks_nr_lines), (stack_init), (stack_expand), (sax_core), (iks_parse), (iks_parser_reset), (iks_parser_delete), (iks_new), (iks_new_within), (iks_insert), (iks_insert_cdata), (iks_insert_attrib), (iks_insert_node), (iks_hide), (iks_delete), (iks_next), (iks_next_tag), (iks_prev), (iks_prev_tag), (iks_parent), (iks_root), (iks_child), (iks_first_tag), (iks_attrib), (iks_find), (iks_find_cdata), (iks_find_attrib), (iks_find_with_attrib), (iks_stack), (iks_type), (iks_name), (iks_cdata), (iks_cdata_size), (iks_has_children), (iks_has_attribs), (escape_size), (my_strcat), (escape), (iks_string), (iks_copy_within), (iks_copy), (tagHook), (cdataHook), (deleteHook), (iks_dom_new), (iks_set_size_hint), (iks_tree), (iks_load), (iks_save): * impress/iksemel.h: * impress/imposter.h: * impress/impress-document.c: (G_DEFINE_TYPE_WITH_CODE), (imp_render_draw_bezier_real), (imp_render_get_size), (imp_render_set_fg_color), (imp_render_draw_line), (imp_render_draw_rect), (imp_render_draw_polygon), (imp_render_draw_arc), (imp_render_draw_bezier), (imp_render_open_image), (imp_render_get_image_size), (imp_render_scale_image), (imp_render_draw_image), (imp_render_close_image), (imp_render_markup), (imp_render_get_text_size), (imp_render_draw_text), (impress_document_load), (impress_document_save), (impress_document_get_n_pages), (impress_document_get_page_size), (imp_render_get_from_drawable), (impress_document_render_pixbuf), (impress_document_finalize), (impress_document_class_init), (impress_document_can_get_text), (impress_document_get_info), (impress_document_document_iface_init), (impress_document_thumbnails_get_thumbnail), (impress_document_thumbnails_get_dimensions), (impress_document_document_thumbnails_iface_init), (impress_document_init): * impress/impress-document.h: * impress/internal.h: * impress/r_back.c: (_imp_fill_back): * impress/r_draw.c: (_imp_draw_rect), (_imp_draw_line_end), (_imp_draw_image), (_imp_tile_image): * impress/r_geometry.c: (r_parse_color), (r_get_color), (fg_color), (r_get_x), (r_get_y), (r_get_angle), (r_get_viewbox), (r_polygon), (r_polyline): * impress/r_gradient.c: (poly_rotate), (r_draw_gradient_simple), (r_draw_gradient_complex), (r_draw_gradient): * impress/r_style.c: (get_style), (r_get_style), (get_style_x), (r_get_bullet): * impress/r_text.c: (add_line), (add_span), (calc_sizes), (calc_pos), (_imp_draw_layout), (text_span), (text_p), (text_list), (r_text): * impress/render.c: (imp_create_context), (imp_context_set_page), (imp_context_set_step), (imp_render), (imp_delete_context): * impress/render.h: * impress/zip.c: (zip_error), (find_cd), (get_long), (get_word), (list_files), (zip_open), (zip_close), (find_file), (seek_file), (zip_load_xml), (zip_get_size), (zip_load): * impress/zip.h: * shell/ev-utils.c: New backend to support impress slides. Fixes bug #30867. --- (limited to 'impress/r_gradient.c') diff --git a/impress/r_gradient.c b/impress/r_gradient.c new file mode 100644 index 0000000..f6b9af2 --- /dev/null +++ b/impress/r_gradient.c @@ -0,0 +1,386 @@ +/* imposter (OO.org Impress viewer) +** Copyright (C) 2003-2005 Gurer Ozen +** This code is free software; you can redistribute it and/or +** modify it under the terms of GNU General Public License. +*/ + +#include "common.h" +#include "internal.h" +#include + +#define GRAD_LINEAR 0 +#define GRAD_AXIAL 1 +#define GRAD_SQUARE 2 +#define GRAD_RECTANGULAR 3 +#define GRAD_RADIAL 4 +#define GRAD_ELLIPTICAL 5 + +typedef struct Gradient_s { + int type; + ImpColor start; + int start_intensity; + ImpColor end; + int end_intensity; + int angle; + int border; + int steps; + int offset_x; + int offset_y; +} Gradient; + +typedef struct Rectangle_s { + int Left; + int Top; + int Right; + int Bottom; +} Rectangle; + +static void +poly_rotate (ImpPoint *poly, int n, int cx, int cy, double fAngle) +{ + int i; + long nX, nY; + + for (i = 0; i < n; i++) { + nX = poly->x - cx; + nY = poly->y - cy; + poly->x = (cos(fAngle) * nX + sin(fAngle) * nY) + cx; + poly->y = - (sin(fAngle)* nX - cos(fAngle) * nY) + cy; + poly++; + } +} + +static void +r_draw_gradient_simple (ImpRenderCtx *ctx, void *drw_data, Gradient *grad) +{ + Rectangle rRect = { 0, 0, ctx->pix_w - 1, ctx->pix_h - 1 }; + Rectangle aRect, aFullRect; + ImpPoint poly[4], tempoly[2]; + ImpColor gcol; + double fW, fH, fDX, fDY, fAngle; + double fScanLine, fScanInc; + long redSteps, greenSteps, blueSteps; + long nBorder; + int i, nSteps, nSteps2; + int cx, cy; + + cx = rRect.Left + (rRect.Right - rRect.Left) / 2; + cy = rRect.Top + (rRect.Bottom - rRect.Top) / 2; + + aRect = rRect; + aRect.Top--; aRect.Left--; aRect.Bottom++; aRect.Right++; + fW = rRect.Right - rRect.Left; + fH = rRect.Bottom - rRect.Top; + fAngle = (((double) grad->angle) * 3.14 / 1800.0); + fDX = fW * fabs (cos (fAngle)) + fH * fabs (sin (fAngle)); + fDY = fH * fabs (cos (fAngle)) + fW * fabs (sin (fAngle)); + fDX = (fDX - fW) * 0.5 - 0.5; + fDY = (fDY - fH) * 0.5 - 0.5; + aRect.Left -= fDX; + aRect.Right += fDX; + aRect.Top -= fDY; + aRect.Bottom += fDY; + aFullRect = aRect; + + nBorder = grad->border * (aRect.Bottom - aRect.Top) / 100; + if (grad->type == GRAD_LINEAR) { + aRect.Top += nBorder; + } else { + nBorder >>= 1; + aRect.Top += nBorder; + aRect.Bottom -= nBorder; + } + + if (aRect.Top > (aRect.Bottom - 1)) + aRect.Top = aRect.Bottom - 1; + + poly[0].x = aFullRect.Left; + poly[0].y = aFullRect.Top; + poly[1].x = aFullRect.Right; + poly[1].y = aFullRect.Top; + poly[2].x = aRect.Right; + poly[2].y = aRect.Top; + poly[3].x = aRect.Left; + poly[3].y = aRect.Top; + poly_rotate (&poly[0], 4, cx, cy, fAngle); + + redSteps = grad->end.red - grad->start.red; + greenSteps = grad->end.green - grad->start.green; + blueSteps = grad->end.blue - grad->start.blue; + nSteps = grad->steps; + if (nSteps == 0) { + long mr; + mr = aRect.Bottom - aRect.Top; + if (mr < 50) + nSteps = mr / 2; + else + nSteps = mr / 4; + mr = abs(redSteps); + if (abs(greenSteps) > mr) mr = abs(greenSteps); + if (abs(blueSteps) > mr) mr = abs(blueSteps); + if (mr < nSteps) nSteps = mr; + } + + if (grad->type == GRAD_AXIAL) { + if (nSteps & 1) nSteps++; + nSteps2 = nSteps + 2; + gcol = grad->end; + redSteps <<= 1; + greenSteps <<= 1; + blueSteps <<= 1; + } else { + nSteps2 = nSteps + 1; + gcol = grad->start; + } + + fScanLine = aRect.Top; + fScanInc = (double)(aRect.Bottom - aRect.Top) / (double)nSteps; + + for (i = 0; i < nSteps2; i++) { + // draw polygon + ctx->drw->set_fg_color(drw_data, &gcol); + ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4); + // calc next polygon + aRect.Top = (long)(fScanLine += fScanInc); + if (i == nSteps) { + tempoly[0].x = aFullRect.Left; + tempoly[0].y = aFullRect.Bottom; + tempoly[1].x = aFullRect.Right; + tempoly[1].y = aFullRect.Bottom; + } else { + tempoly[0].x = aRect.Left; + tempoly[0].y = aRect.Top; + tempoly[1].x = aRect.Right; + tempoly[1].y = aRect.Top; + } + poly_rotate (&tempoly[0], 2, cx, cy, fAngle); + poly[0] = poly[3]; + poly[1] = poly[2]; + poly[2] = tempoly[1]; + poly[3] = tempoly[0]; + // calc next color + if (grad->type == GRAD_LINEAR) { + gcol.red = grad->start.red + ((redSteps * i) / nSteps2); + gcol.green = grad->start.green + ((greenSteps * i) / nSteps2); + gcol.blue = grad->start.blue + ((blueSteps * i) / nSteps2); + } else { + if (i >= nSteps) { + gcol.red = grad->end.red; + gcol.green = grad->end.green; + gcol.blue = grad->end.blue; + } else { + if (i <= (nSteps / 2)) { + gcol.red = grad->end.red - ((redSteps * i) / nSteps2); + gcol.green = grad->end.green - ((greenSteps * i) / nSteps2); + gcol.blue = grad->end.blue - ((blueSteps * i) / nSteps2); + } else { + int i2 = i - nSteps / 2; + gcol.red = grad->start.red + ((redSteps * i2) / nSteps2); + gcol.green = grad->start.green + ((greenSteps * i2) / nSteps2); + gcol.blue = grad->start.blue + ((blueSteps * i2) / nSteps2); + } + } + } + } +} + +static void +r_draw_gradient_complex (ImpRenderCtx *ctx, void *drw_data, Gradient *grad) +{ + Rectangle rRect = { 0, 0, ctx->pix_w - 1, ctx->pix_h - 1 }; + Rectangle aRect = rRect; + ImpColor gcol; + ImpPoint poly[4]; + double fAngle = (((double) grad->angle) * 3.14 / 1800.0); + long redSteps, greenSteps, blueSteps; + long nZW, nZH; + long bX, bY; + long sW, sH; + long cx, cy; + int i; + long nSteps; + double sTop, sLeft, sRight, sBottom, sInc; + int minRect; + + redSteps = grad->end.red - grad->start.red; + greenSteps = grad->end.green - grad->start.green; + blueSteps = grad->end.blue - grad->start.blue; + + if (grad->type == GRAD_SQUARE || grad->type == GRAD_RECTANGULAR) { + double fW = aRect.Right - aRect.Left; + double fH = aRect.Bottom - aRect.Top; + double fDX = fW * fabs (cos (fAngle)) + fH * fabs (sin (fAngle)); + double fDY = fH * fabs (cos (fAngle)) + fW * fabs (sin (fAngle)); + fDX = (fDX - fW) * 0.5 - 0.5; + fDY = (fDY - fH) * 0.5 - 0.5; + aRect.Left -= fDX; + aRect.Right += fDX; + aRect.Top -= fDY; + aRect.Bottom += fDY; + } + + sW = aRect.Right - aRect.Left; + sH = aRect.Bottom - aRect.Top; + + if (grad->type == GRAD_SQUARE) { + if (sW > sH) sH = sW; else sW = sH; + } else if (grad->type == GRAD_RADIAL) { + sW = 0.5 + sqrt ((double)sW*(double)sW + (double)sH*(double)sH); + sH = sW; + } else if (grad->type == GRAD_ELLIPTICAL) { + sW = 0.5 + (double)sW * 1.4142; + sH = 0.5 + (double)sH * 1.4142; + } + + nZW = (aRect.Right - aRect.Left) * grad->offset_x / 100; + nZH = (aRect.Bottom - aRect.Top) * grad->offset_y / 100; + bX = grad->border * sW / 100; + bY = grad->border * sH / 100; + cx = aRect.Left + nZW; + cy = aRect.Top + nZH; + + sW -= bX; + sH -= bY; + + aRect.Left = cx - ((aRect.Right - aRect.Left) >> 1); + aRect.Top = cy - ((aRect.Bottom - aRect.Top) >> 1); + + nSteps = grad->steps; + minRect = aRect.Right - aRect.Left; + if (aRect.Bottom - aRect.Top < minRect) minRect = aRect.Bottom - aRect.Top; + if (nSteps == 0) { + long mr; + if (minRect < 50) + nSteps = minRect / 2; + else + nSteps = minRect / 4; + mr = abs(redSteps); + if (abs(greenSteps) > mr) mr = abs(greenSteps); + if (abs(blueSteps) > mr) mr = abs(blueSteps); + if (mr < nSteps) nSteps = mr; + } + + sLeft = aRect.Left; + sTop = aRect.Top; + sRight = aRect.Right; + sBottom = aRect.Bottom; + sInc = (double) minRect / (double) nSteps * 0.5; + + gcol = grad->start; + poly[0].x = rRect.Left; + poly[0].y = rRect.Top; + poly[1].x = rRect.Right; + poly[1].y = rRect.Top; + poly[2].x = rRect.Right; + poly[2].y = rRect.Bottom; + poly[3].x = rRect.Left; + poly[3].y = rRect.Bottom; + ctx->drw->set_fg_color(drw_data, &gcol); + ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4); + + for (i = 0; i < nSteps; i++) { + aRect.Left = (long) (sLeft += sInc); + aRect.Top = (long) (sTop += sInc); + aRect.Right = (long) (sRight -= sInc); + aRect.Bottom = (long) (sBottom -= sInc); + if (aRect.Bottom - aRect.Top < 2 || aRect.Right - aRect.Left < 2) + break; + + gcol.red = grad->start.red + (redSteps * (i+1) / nSteps); + gcol.green = grad->start.green + (greenSteps * (i+1) / nSteps); + gcol.blue = grad->start.blue + (blueSteps * (i+1) / nSteps); + ctx->drw->set_fg_color(drw_data, &gcol); + + if (grad->type == GRAD_RADIAL || grad->type == GRAD_ELLIPTICAL) { + ctx->drw->draw_arc(drw_data, 1, aRect.Left, aRect.Top, + aRect.Right - aRect.Left, aRect.Bottom - aRect.Top, + 0, 360); + } else { + poly[0].x = aRect.Left; + poly[0].y = aRect.Top; + poly[1].x = aRect.Right; + poly[1].y = aRect.Top; + poly[2].x = aRect.Right; + poly[2].y = aRect.Bottom; + poly[3].x = aRect.Left; + poly[3].y = aRect.Bottom; + poly_rotate (&poly[0], 4, cx, cy, fAngle); + ctx->drw->draw_polygon(drw_data, 1, &poly[0], 4); + } + } +} + +void +r_draw_gradient (ImpRenderCtx *ctx, void *drw_data, iks *node) +{ +// GdkGC *gc; + Gradient grad; + char *stil, *tmp; + iks *x; + + stil = r_get_style (ctx, node, "draw:fill-gradient-name"); + x = iks_find_with_attrib (iks_find (ctx->styles, "office:styles"), + "draw:gradient", "draw:name", stil); + if (x) { + memset (&grad, 0, sizeof (Gradient)); + grad.type = -1; + grad.offset_x = 50; + grad.offset_y = 50; + + tmp = iks_find_attrib (x, "draw:start-color"); + if (tmp) r_parse_color (tmp, &grad.start); + tmp = iks_find_attrib (x, "draw:start-intensity"); + if (tmp) { + int val = atoi (tmp); + grad.start.red = grad.start.red * val / 100; + grad.start.green = grad.start.green * val / 100; + grad.start.blue = grad.start.blue * val / 100; + } + tmp = iks_find_attrib (x, "draw:end-color"); + if (tmp) r_parse_color (tmp, &grad.end); + tmp = iks_find_attrib (x, "draw:end-intensity"); + if (tmp) { + int val = atoi (tmp); + grad.end.red = grad.end.red * val / 100; + grad.end.green = grad.end.green * val / 100; + grad.end.blue = grad.end.blue * val / 100; + } + tmp = iks_find_attrib (x, "draw:angle"); + if (tmp) grad.angle = atoi(tmp) % 3600; + tmp = iks_find_attrib (x, "draw:border"); + if (tmp) grad.border = atoi(tmp); + tmp = r_get_style (ctx, node, "draw:gradient-step-count"); + if (tmp) grad.steps = atoi (tmp); + tmp = iks_find_attrib (x, "draw:cx"); + if (tmp) grad.offset_x = atoi (tmp); + tmp = iks_find_attrib (x, "draw:cy"); + if (tmp) grad.offset_y = atoi (tmp); + tmp = iks_find_attrib (x, "draw:style"); + if (iks_strcmp (tmp, "linear") == 0) + grad.type = GRAD_LINEAR; + else if (iks_strcmp (tmp, "axial") == 0) + grad.type = GRAD_AXIAL; + else if (iks_strcmp (tmp, "radial") == 0) + grad.type = GRAD_RADIAL; + else if (iks_strcmp (tmp, "rectangular") == 0) + grad.type = GRAD_RECTANGULAR; + else if (iks_strcmp (tmp, "ellipsoid") == 0) + grad.type = GRAD_ELLIPTICAL; + else if (iks_strcmp (tmp, "square") == 0) + grad.type = GRAD_SQUARE; + + if (grad.type == -1) return; + +// gc = ctx->gc; +// ctx->gc = gdk_gc_new (ctx->d); +// gdk_gc_copy (ctx->gc, gc); + + if (grad.type == GRAD_LINEAR || grad.type == GRAD_AXIAL) + r_draw_gradient_simple (ctx, drw_data, &grad); + else + r_draw_gradient_complex (ctx, drw_data, &grad); + +// gdk_gc_unref (ctx->gc); +// ctx->gc = gc; + } +} -- cgit v0.9.1