Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2007-2008 James Bursa <bursa@users.sourceforge.net>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.  * Content for image/svg (implementation).
  21.  */
  22.  
  23. #include <assert.h>
  24. #include <limits.h>
  25. #include <string.h>
  26.  
  27. #include <svgtiny.h>
  28.  
  29. #include "content/content_protected.h"
  30. #include "css/css.h"
  31. #include "desktop/plotters.h"
  32. #include "image/svg.h"
  33. #include "utils/messages.h"
  34. #include "utils/utils.h"
  35.  
  36. typedef struct svg_content {
  37.         struct content base;
  38.  
  39.         struct svgtiny_diagram *diagram;
  40.  
  41.         int current_width;
  42.         int current_height;
  43. } svg_content;
  44.  
  45.  
  46.  
  47. static nserror svg_create_svg_data(svg_content *c)
  48. {
  49.         union content_msg_data msg_data;
  50.  
  51.         c->diagram = svgtiny_create();
  52.         if (c->diagram == NULL)
  53.                 goto no_memory;
  54.  
  55.         c->current_width = INT_MAX;
  56.         c->current_height = INT_MAX;
  57.  
  58.         return NSERROR_OK;
  59.  
  60. no_memory:
  61.         msg_data.error = messages_get("NoMemory");
  62.         content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data);
  63.         return NSERROR_NOMEM;
  64. }
  65.  
  66.  
  67. /**
  68.  * Create a CONTENT_SVG.
  69.  */
  70.  
  71. static nserror svg_create(const content_handler *handler,
  72.                 lwc_string *imime_type, const http_parameter *params,
  73.                 llcache_handle *llcache, const char *fallback_charset,
  74.                 bool quirks, struct content **c)
  75. {
  76.         svg_content *svg;
  77.         nserror error;
  78.  
  79.         svg = calloc(1, sizeof(svg_content));
  80.         if (svg == NULL)
  81.                 return NSERROR_NOMEM;
  82.  
  83.         error = content__init(&svg->base, handler, imime_type, params,
  84.                         llcache, fallback_charset, quirks);
  85.         if (error != NSERROR_OK) {
  86.                 free(svg);
  87.                 return error;
  88.         }
  89.  
  90.         error = svg_create_svg_data(svg);
  91.         if (error != NSERROR_OK) {
  92.                 free(svg);
  93.                 return error;
  94.         }
  95.  
  96.         *c = (struct content *) svg;
  97.  
  98.         return NSERROR_OK;
  99. }
  100.  
  101.  
  102.  
  103. /**
  104.  * Convert a CONTENT_SVG for display.
  105.  */
  106.  
  107. static bool svg_convert(struct content *c)
  108. {
  109.         /*c->title = malloc(100);
  110.         if (c->title)
  111.                 snprintf(c->title, 100, messages_get("svgTitle"),
  112.                                 width, height, c->source_size);*/
  113.         //c->size += ?;
  114.         content_set_ready(c);
  115.         content_set_done(c);
  116.         /* Done: update status bar */
  117.         content_set_status(c, "");
  118.  
  119.         return true;
  120. }
  121.  
  122. /**
  123.  * Reformat a CONTENT_SVG.
  124.  */
  125.  
  126. static void svg_reformat(struct content *c, int width, int height)
  127. {
  128.         svg_content *svg = (svg_content *) c;
  129.         const char *source_data;
  130.         unsigned long source_size;
  131.  
  132.         assert(svg->diagram);
  133.  
  134.         /* Avoid reformats to same width/height as we already reformatted to */
  135.         if (width != svg->current_width || height != svg->current_height) {
  136.                 source_data = content__get_source_data(c, &source_size);
  137.  
  138.                 svgtiny_parse(svg->diagram, source_data, source_size,
  139.                                 nsurl_access(content_get_url(c)),
  140.                                 width, height);
  141.  
  142.                 svg->current_width = width;
  143.                 svg->current_height = height;
  144.         }
  145.  
  146.         c->width = svg->diagram->width;
  147.         c->height = svg->diagram->height;
  148. }
  149.  
  150.  
  151. /**
  152.  * Redraw a CONTENT_SVG.
  153.  */
  154.  
  155. static bool svg_redraw_internal(struct content *c, int x, int y,
  156.                 int width, int height, const struct rect *clip,
  157.                 const struct redraw_context *ctx, float scale,
  158.                 colour background_colour)
  159. {
  160.         svg_content *svg = (svg_content *) c;
  161.         float transform[6];
  162.         struct svgtiny_diagram *diagram = svg->diagram;
  163.         bool ok;
  164.         int px, py;
  165.         unsigned int i;
  166.         plot_font_style_t fstyle = *plot_style_font;
  167.  
  168.         assert(diagram);
  169.  
  170.         transform[0] = (float) width / (float) c->width;
  171.         transform[1] = 0;
  172.         transform[2] = 0;
  173.         transform[3] = (float) height / (float) c->height;
  174.         transform[4] = x;
  175.         transform[5] = y;
  176.  
  177. #define BGR(c) ((c) == svgtiny_TRANSPARENT ? NS_TRANSPARENT :           \
  178.                 ((svgtiny_RED((c))) |                                   \
  179.                  (svgtiny_GREEN((c)) << 8) |                            \
  180.                  (svgtiny_BLUE((c)) << 16)))
  181.  
  182.         for (i = 0; i != diagram->shape_count; i++) {
  183.                 if (diagram->shape[i].path) {
  184.                         ok = ctx->plot->path(diagram->shape[i].path,
  185.                                         diagram->shape[i].path_length,
  186.                                         BGR(diagram->shape[i].fill),
  187.                                         diagram->shape[i].stroke_width,
  188.                                         BGR(diagram->shape[i].stroke),
  189.                                         transform);
  190.                         if (!ok)
  191.                                 return false;
  192.  
  193.                 } else if (diagram->shape[i].text) {
  194.                         px = transform[0] * diagram->shape[i].text_x +
  195.                                 transform[2] * diagram->shape[i].text_y +
  196.                                 transform[4];
  197.                         py = transform[1] * diagram->shape[i].text_x +
  198.                                 transform[3] * diagram->shape[i].text_y +
  199.                                 transform[5];
  200.  
  201.                         fstyle.background = 0xffffff;
  202.                         fstyle.foreground = 0x000000;
  203.                         fstyle.size = (8 * FONT_SIZE_SCALE) * scale;
  204.  
  205.                         ok = ctx->plot->text(px, py,
  206.                                         diagram->shape[i].text,
  207.                                         strlen(diagram->shape[i].text),
  208.                                         &fstyle);
  209.                         if (!ok)
  210.                                 return false;
  211.                 }
  212.         }
  213.  
  214. #undef BGR
  215.  
  216.         return true;
  217. }
  218.  
  219.  
  220. /**
  221.  * Redraw a CONTENT_SVG.
  222.  */
  223.  
  224. static bool svg_redraw(struct content *c, struct content_redraw_data *data,
  225.                 const struct rect *clip, const struct redraw_context *ctx)
  226. {
  227.         int x = data->x;
  228.         int y = data->y;
  229.  
  230.         if ((data->width <= 0) && (data->height <= 0)) {
  231.                 /* No point trying to plot SVG if it does not occupy a valid
  232.                  * area */
  233.                 return true;
  234.         }
  235.  
  236.         if ((data->repeat_x == false) && (data->repeat_y == false)) {
  237.                 /* Simple case: SVG is not tiled */
  238.                 return svg_redraw_internal(c, x, y,
  239.                                 data->width, data->height,
  240.                                 clip, ctx, data->scale,
  241.                                 data->background_colour);
  242.         } else {
  243.                 /* Tiled redraw required.  SVG repeats to extents of clip
  244.                  * rectangle, in x, y or both directions */
  245.                 int x0, y0, x1, y1;
  246.  
  247.                 /* Find the redraw boundaries to loop within */
  248.                 x0 = x;
  249.                 if (data->repeat_x) {
  250.                         for (; x0 > clip->x0; x0 -= data->width);
  251.                         x1 = clip->x1;
  252.                 } else {
  253.                         x1 = x + 1;
  254.                 }
  255.                 y0 = y;
  256.                 if (data->repeat_y) {
  257.                         for (; y0 > clip->y0; y0 -= data->height);
  258.                         y1 = clip->y1;
  259.                 } else {
  260.                         y1 = y + 1;
  261.                 }
  262.  
  263.                 /* Repeatedly plot the SVG across the area */
  264.                 for (y = y0; y < y1; y += data->height) {
  265.                         for (x = x0; x < x1; x += data->width) {
  266.                                 if (!svg_redraw_internal(c, x, y,
  267.                                                 data->width, data->height,
  268.                                                 clip, ctx, data->scale,
  269.                                                 data->background_colour)) {
  270.                                         return false;
  271.                                 }
  272.                         }
  273.                 }
  274.         }
  275.  
  276.         return true;
  277. }
  278.  
  279.  
  280. /**
  281.  * Destroy a CONTENT_SVG and free all resources it owns.
  282.  */
  283.  
  284. static void svg_destroy(struct content *c)
  285. {
  286.         svg_content *svg = (svg_content *) c;
  287.  
  288.         if (svg->diagram != NULL)
  289.                 svgtiny_free(svg->diagram);
  290. }
  291.  
  292.  
  293. static nserror svg_clone(const struct content *old, struct content **newc)
  294. {
  295.         svg_content *svg;
  296.         nserror error;
  297.  
  298.         svg = calloc(1, sizeof(svg_content));
  299.         if (svg == NULL)
  300.                 return NSERROR_NOMEM;
  301.  
  302.         error = content__clone(old, &svg->base);
  303.         if (error != NSERROR_OK) {
  304.                 content_destroy(&svg->base);
  305.                 return error;
  306.         }
  307.  
  308.         /* Simply replay create/convert */
  309.         error = svg_create_svg_data(svg);
  310.         if (error != NSERROR_OK) {
  311.                 content_destroy(&svg->base);
  312.                 return error;
  313.         }
  314.  
  315.         if (old->status == CONTENT_STATUS_READY ||
  316.                         old->status == CONTENT_STATUS_DONE) {
  317.                 if (svg_convert(&svg->base) == false) {
  318.                         content_destroy(&svg->base);
  319.                         return NSERROR_CLONE_FAILED;
  320.                 }
  321.         }
  322.  
  323.         *newc = (struct content *) svg;
  324.  
  325.         return NSERROR_OK;
  326. }
  327.  
  328. static content_type svg_content_type(void)
  329. {
  330.         return CONTENT_IMAGE;
  331. }
  332.  
  333. static const content_handler svg_content_handler = {
  334.         .create = svg_create,
  335.         .data_complete = svg_convert,
  336.         .reformat = svg_reformat,
  337.         .destroy = svg_destroy,
  338.         .redraw = svg_redraw,
  339.         .clone = svg_clone,
  340.         .type = svg_content_type,
  341.         .no_share = true
  342. };
  343.  
  344. static const char *svg_types[] = {
  345.         "image/svg",
  346.         "image/svg+xml"
  347. };
  348.  
  349.  
  350. CONTENT_FACTORY_REGISTER_TYPES(svg, svg_types, svg_content_handler);
  351.  
  352.  
  353.