Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
  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. #include <assert.h>
  20.  
  21. #include <libwapcaplet/libwapcaplet.h>
  22. #include <dom/dom.h>
  23.  
  24. #include "content/content_protected.h"
  25. #include "content/fetch.h"
  26. #include "content/hlcache.h"
  27. #include "css/css.h"
  28. #include "css/internal.h"
  29. #include "desktop/gui.h"
  30. #include "render/html.h"
  31. #include "utils/utils.h"
  32. #include "utils/http.h"
  33. #include "utils/log.h"
  34. #include "utils/messages.h"
  35.  
  36. /* Define to trace import fetches */
  37. #undef NSCSS_IMPORT_TRACE
  38.  
  39. /**
  40.  * CSS content data
  41.  */
  42. typedef struct nscss_content
  43. {
  44.         struct content base;            /**< Underlying content object */
  45.  
  46.         struct content_css_data data;   /**< CSS data */
  47. } nscss_content;
  48.  
  49. /**
  50.  * Context for import fetches
  51.  */
  52. typedef struct {
  53.         struct content_css_data *css;           /**< Object containing import */
  54.         uint32_t index;                         /**< Index into parent sheet's
  55.                                                  *   imports array */
  56. } nscss_import_ctx;
  57.  
  58. static nserror nscss_create(const content_handler *handler,
  59.                 lwc_string *imime_type, const http_parameter *params,
  60.                 llcache_handle *llcache, const char *fallback_charset,
  61.                 bool quirks, struct content **c);
  62. static bool nscss_process_data(struct content *c, const char *data,
  63.                 unsigned int size);
  64. static bool nscss_convert(struct content *c);
  65. static void nscss_destroy(struct content *c);
  66. static nserror nscss_clone(const struct content *old, struct content **newc);
  67. static bool nscss_matches_quirks(const struct content *c, bool quirks);
  68. static content_type nscss_content_type(void);
  69.  
  70. static void nscss_content_done(struct content_css_data *css, void *pw);
  71. static css_error nscss_handle_import(void *pw, css_stylesheet *parent,
  72.                 lwc_string *url, uint64_t media);
  73. static nserror nscss_import(hlcache_handle *handle,
  74.                 const hlcache_event *event, void *pw);
  75. static css_error nscss_import_complete(nscss_import_ctx *ctx);
  76.  
  77. static css_error nscss_register_imports(struct content_css_data *c);
  78. static css_error nscss_register_import(struct content_css_data *c,
  79.                 const hlcache_handle *import);
  80.  
  81.  
  82. static lwc_string *css_charset;
  83. static css_stylesheet *blank_import;
  84.  
  85.  
  86. /**
  87.  * Initialise a CSS content
  88.  *
  89.  * \param c       Content to initialise
  90.  * \param params  Content-Type parameters
  91.  * \return true on success, false on failure
  92.  */
  93. nserror nscss_create(const content_handler *handler,
  94.                 lwc_string *imime_type, const http_parameter *params,
  95.                 llcache_handle *llcache, const char *fallback_charset,
  96.                 bool quirks, struct content **c)
  97. {
  98.         nscss_content *result;
  99.         const char *charset = NULL;
  100.         lwc_string *charset_value = NULL;
  101.         union content_msg_data msg_data;
  102.         nserror error;
  103.  
  104.         result = calloc(1, sizeof(nscss_content));
  105.         if (result == NULL)
  106.                 return NSERROR_NOMEM;
  107.  
  108.         error = content__init(&result->base, handler, imime_type,
  109.                         params, llcache, fallback_charset, quirks);
  110.         if (error != NSERROR_OK) {
  111.                 free(result);
  112.                 return error;
  113.         }
  114.  
  115.         /* Find charset specified on HTTP layer, if any */
  116.         error = http_parameter_list_find_item(params, css_charset,
  117.                         &charset_value);
  118.         if (error != NSERROR_OK || lwc_string_length(charset_value) == 0) {
  119.                 /* No charset specified, use fallback, if any */
  120.                 /** \todo libcss will take this as gospel, which is wrong */
  121.                 charset = fallback_charset;
  122.         } else {
  123.                 charset = lwc_string_data(charset_value);
  124.         }
  125.  
  126.         error = nscss_create_css_data(&result->data,
  127.                         nsurl_access(content_get_url(&result->base)),
  128.                         charset, result->base.quirks,
  129.                         nscss_content_done, result);
  130.         if (error != NSERROR_OK) {
  131.                 msg_data.error = messages_get("NoMemory");
  132.                 content_broadcast(&result->base, CONTENT_MSG_ERROR, msg_data);
  133.                 if (charset_value != NULL)
  134.                         lwc_string_unref(charset_value);
  135.                 free(result);
  136.                 return error;
  137.         }
  138.  
  139.         if (charset_value != NULL)
  140.                 lwc_string_unref(charset_value);
  141.  
  142.         *c = (struct content *) result;
  143.  
  144.         return NSERROR_OK;
  145. }
  146.  
  147. /**
  148.  * Create a struct content_css_data, creating a stylesheet object
  149.  *
  150.  * \param c        Struct to populate
  151.  * \param url      URL of stylesheet
  152.  * \param charset  Stylesheet charset
  153.  * \param quirks   Stylesheet quirks mode
  154.  * \param done     Callback to call when content has completed
  155.  * \param pw       Client data for \a done
  156.  * \return NSERROR_OK on success, NSERROR_NOMEM on memory exhaustion
  157.  */
  158. nserror nscss_create_css_data(struct content_css_data *c,
  159.                 const char *url, const char *charset, bool quirks,
  160.                 nscss_done_callback done, void *pw)
  161. {
  162.         css_error error;
  163.         css_stylesheet_params params;
  164.  
  165.         c->pw = pw;
  166.         c->done = done;
  167.         c->next_to_register = (uint32_t) -1;
  168.         c->import_count = 0;
  169.         c->imports = NULL;
  170.         if (charset != NULL)
  171.                 c->charset = strdup(charset);
  172.         else
  173.                 c->charset = NULL;
  174.  
  175.         params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
  176.         params.level = CSS_LEVEL_DEFAULT;
  177.         params.charset = charset;
  178.         params.url = url;
  179.         params.title = NULL;
  180.         params.allow_quirks = quirks;
  181.         params.inline_style = false;
  182.         params.resolve = nscss_resolve_url;
  183.         params.resolve_pw = NULL;
  184.         params.import = nscss_handle_import;
  185.         params.import_pw = c;
  186.         params.color = gui_system_colour;
  187.         params.color_pw = NULL;
  188.         params.font = NULL;
  189.         params.font_pw = NULL;
  190.  
  191.         error = css_stylesheet_create(&params, ns_realloc, NULL, &c->sheet);
  192.         if (error != CSS_OK) {
  193.                 return NSERROR_NOMEM;
  194.         }
  195.  
  196.         return NSERROR_OK;
  197. }
  198.  
  199. /**
  200.  * Process CSS source data
  201.  *
  202.  * \param c     Content structure
  203.  * \param data  Data to process
  204.  * \param size  Number of bytes to process
  205.  * \return true on success, false on failure
  206.  */
  207. bool nscss_process_data(struct content *c, const char *data, unsigned int size)
  208. {
  209.         nscss_content *css = (nscss_content *) c;
  210.         union content_msg_data msg_data;
  211.         css_error error;
  212.  
  213.         error = nscss_process_css_data(&css->data, data, size);
  214.         if (error != CSS_OK && error != CSS_NEEDDATA) {
  215.                 msg_data.error = "?";
  216.                 content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
  217.         }
  218.  
  219.         return (error == CSS_OK || error == CSS_NEEDDATA);
  220. }
  221.  
  222. /**
  223.  * Process CSS data
  224.  *
  225.  * \param c     CSS content object
  226.  * \param data  Data to process
  227.  * \param size  Number of bytes to process
  228.  * \return CSS_OK on success, appropriate error otherwise
  229.  */
  230. css_error nscss_process_css_data(struct content_css_data *c, const char *data,
  231.                 unsigned int size)
  232. {
  233.         return css_stylesheet_append_data(c->sheet,
  234.                         (const uint8_t *) data, size);
  235. }
  236.  
  237. /**
  238.  * Convert a CSS content ready for use
  239.  *
  240.  * \param c  Content to convert
  241.  * \return true on success, false on failure
  242.  */
  243. bool nscss_convert(struct content *c)
  244. {
  245.         nscss_content *css = (nscss_content *) c;
  246.         union content_msg_data msg_data;
  247.         css_error error;
  248.  
  249.         error = nscss_convert_css_data(&css->data);
  250.         if (error != CSS_OK) {
  251.                 msg_data.error = "?";
  252.                 content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
  253.                 return false;
  254.         }
  255.  
  256.         return true;
  257. }
  258.  
  259. /**
  260.  * Convert CSS data ready for use
  261.  *
  262.  * \param c  CSS data to convert
  263.  * \return CSS error
  264.  */
  265. css_error nscss_convert_css_data(struct content_css_data *c)
  266. {
  267.         css_error error;
  268.  
  269.         error = css_stylesheet_data_done(c->sheet);
  270.  
  271.         /* Process pending imports */
  272.         if (error == CSS_IMPORTS_PENDING) {
  273.                 /* We must not have registered any imports yet */
  274.                 assert(c->next_to_register == (uint32_t) -1);
  275.  
  276.                 /* Start registering, until we find one that
  277.                  * hasn't finished fetching */
  278.                 c->next_to_register = 0;
  279.                 error = nscss_register_imports(c);
  280.         } else if (error == CSS_OK) {
  281.                 /* No imports, and no errors, so complete conversion */
  282.                 c->done(c, c->pw);
  283.         } else {
  284.                 const char *url;
  285.  
  286.                 if (css_stylesheet_get_url(c->sheet, &url) == CSS_OK) {
  287.                         LOG(("Failed converting %p %s (%d)", c, url, error));
  288.                 } else {
  289.                         LOG(("Failed converting %p (%d)", c, error));
  290.                 }
  291.         }
  292.  
  293.         return error;
  294. }
  295.  
  296. /**
  297.  * Clean up a CSS content
  298.  *
  299.  * \param c  Content to clean up
  300.  */
  301. void nscss_destroy(struct content *c)
  302. {
  303.         nscss_content *css = (nscss_content *) c;
  304.  
  305.         nscss_destroy_css_data(&css->data);
  306. }
  307.  
  308. /**
  309.  * Clean up CSS data
  310.  *
  311.  * \param c  CSS data to clean up
  312.  */
  313. void nscss_destroy_css_data(struct content_css_data *c)
  314. {
  315.         uint32_t i;
  316.  
  317.         for (i = 0; i < c->import_count; i++) {
  318.                 if (c->imports[i].c != NULL) {
  319.                         hlcache_handle_release(c->imports[i].c);
  320.                 }
  321.                 c->imports[i].c = NULL;
  322.         }
  323.  
  324.         free(c->imports);
  325.  
  326.         if (c->sheet != NULL) {
  327.                 css_stylesheet_destroy(c->sheet);
  328.                 c->sheet = NULL;
  329.         }
  330.  
  331.         free(c->charset);
  332. }
  333.  
  334. nserror nscss_clone(const struct content *old, struct content **newc)
  335. {
  336.         const nscss_content *old_css = (const nscss_content *) old;
  337.         nscss_content *new_css;
  338.         const char *data;
  339.         unsigned long size;
  340.         nserror error;
  341.  
  342.         new_css = calloc(1, sizeof(nscss_content));
  343.         if (new_css == NULL)
  344.                 return NSERROR_NOMEM;
  345.  
  346.         /* Clone content */
  347.         error = content__clone(old, &new_css->base);
  348.         if (error != NSERROR_OK) {
  349.                 content_destroy(&new_css->base);
  350.                 return error;
  351.         }
  352.  
  353.         /* Simply replay create/process/convert */
  354.         error = nscss_create_css_data(&new_css->data,
  355.                         nsurl_access(content_get_url(&new_css->base)),
  356.                         old_css->data.charset,
  357.                         new_css->base.quirks,
  358.                         nscss_content_done, new_css);
  359.         if (error != NSERROR_OK) {
  360.                 content_destroy(&new_css->base);
  361.                 return error;
  362.         }
  363.  
  364.         data = content__get_source_data(&new_css->base, &size);
  365.         if (size > 0) {
  366.                 if (nscss_process_data(&new_css->base, data, size) == false) {
  367.                         content_destroy(&new_css->base);
  368.                         return NSERROR_CLONE_FAILED;
  369.                 }
  370.         }
  371.  
  372.         if (old->status == CONTENT_STATUS_READY ||
  373.                         old->status == CONTENT_STATUS_DONE) {
  374.                 if (nscss_convert(&new_css->base) == false) {
  375.                         content_destroy(&new_css->base);
  376.                         return NSERROR_CLONE_FAILED;
  377.                 }
  378.         }
  379.  
  380.         *newc = (struct content *) new_css;
  381.  
  382.         return NSERROR_OK;
  383. }
  384.  
  385. bool nscss_matches_quirks(const struct content *c, bool quirks)
  386. {
  387.         return c->quirks == quirks;
  388. }
  389.  
  390. /**
  391.  * Retrieve the stylesheet object associated with a CSS content
  392.  *
  393.  * \param h  Stylesheet content
  394.  * \return Pointer to stylesheet object
  395.  */
  396. css_stylesheet *nscss_get_stylesheet(struct hlcache_handle *h)
  397. {
  398.         nscss_content *c = (nscss_content *) hlcache_handle_get_content(h);
  399.  
  400.         assert(c != NULL);
  401.  
  402.         return c->data.sheet;
  403. }
  404.  
  405. /**
  406.  * Retrieve imported stylesheets
  407.  *
  408.  * \param h  Stylesheet containing imports
  409.  * \param n  Pointer to location to receive number of imports
  410.  * \return Pointer to array of imported stylesheets
  411.  */
  412. struct nscss_import *nscss_get_imports(hlcache_handle *h, uint32_t *n)
  413. {
  414.         nscss_content *c = (nscss_content *) hlcache_handle_get_content(h);
  415.  
  416.         assert(c != NULL);
  417.         assert(n != NULL);
  418.  
  419.         *n = c->data.import_count;
  420.  
  421.         return c->data.imports;
  422. }
  423.  
  424. /**
  425.  * Compute the type of a content
  426.  *
  427.  * \return CONTENT_CSS
  428.  */
  429. content_type nscss_content_type(void)
  430. {
  431.         return CONTENT_CSS;
  432. }
  433.  
  434. /*****************************************************************************
  435.  * Object completion                                                         *
  436.  *****************************************************************************/
  437.  
  438. /**
  439.  * Handle notification that a CSS object is done
  440.  *
  441.  * \param css  CSS object
  442.  * \param pw   Private data
  443.  */
  444. void nscss_content_done(struct content_css_data *css, void *pw)
  445. {
  446.         union content_msg_data msg_data;
  447.         struct content *c = pw;
  448.         uint32_t i;
  449.         size_t size;
  450.         css_error error;
  451.  
  452.         /* Retrieve the size of this sheet */
  453.         error = css_stylesheet_size(css->sheet, &size);
  454.         if (error != CSS_OK) {
  455.                 msg_data.error = "?";
  456.                 content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
  457.                 content_set_error(c);
  458.                 return;
  459.         }
  460.         c->size += size;
  461.  
  462.         /* Add on the size of the imported sheets */
  463.         for (i = 0; i < css->import_count; i++) {
  464.                 if (css->imports[i].c != NULL) {
  465.                         struct content *import = hlcache_handle_get_content(
  466.                                         css->imports[i].c);
  467.  
  468.                         if (import != NULL) {
  469.                                 c->size += import->size;
  470.                         }
  471.                 }
  472.         }
  473.  
  474.         /* Finally, catch the content's users up with reality */
  475.         content_set_ready(c);
  476.         content_set_done(c);
  477. }
  478.  
  479. /*****************************************************************************
  480.  * Import handling                                                           *
  481.  *****************************************************************************/
  482.  
  483. /**
  484.  * Handle notification of the need for an imported stylesheet
  485.  *
  486.  * \param pw      CSS object requesting the import
  487.  * \param parent  Stylesheet requesting the import
  488.  * \param url     URL of the imported sheet
  489.  * \param media   Applicable media for the imported sheet
  490.  * \return CSS_OK on success, appropriate error otherwise
  491.  */
  492. css_error nscss_handle_import(void *pw, css_stylesheet *parent,
  493.                 lwc_string *url, uint64_t media)
  494. {
  495.         content_type accept = CONTENT_CSS;
  496.         struct content_css_data *c = pw;
  497.         nscss_import_ctx *ctx;
  498.         hlcache_child_context child;
  499.         struct nscss_import *imports;
  500.         const char *referer;
  501.         css_error error;
  502.         nserror nerror;
  503.  
  504.         nsurl *ns_url;
  505.         nsurl *ns_ref;
  506.  
  507.         assert(parent == c->sheet);
  508.  
  509.         error = css_stylesheet_get_url(c->sheet, &referer);
  510.         if (error != CSS_OK) {
  511.                 return error;
  512.         }
  513.  
  514.         ctx = malloc(sizeof(*ctx));
  515.         if (ctx == NULL)
  516.                 return CSS_NOMEM;
  517.  
  518.         ctx->css = c;
  519.         ctx->index = c->import_count;
  520.  
  521.         /* Increase space in table */
  522.         imports = realloc(c->imports, (c->import_count + 1) *
  523.                         sizeof(struct nscss_import));
  524.         if (imports == NULL) {
  525.                 free(ctx);
  526.                 return CSS_NOMEM;
  527.         }
  528.         c->imports = imports;
  529.  
  530.         /** \todo fallback charset */
  531.         child.charset = NULL;
  532.         error = css_stylesheet_quirks_allowed(c->sheet, &child.quirks);
  533.         if (error != CSS_OK) {
  534.                 free(ctx);
  535.                 return error;
  536.         }
  537.  
  538.         /* Create content */
  539.         c->imports[c->import_count].media = media;
  540.  
  541.         /* TODO: Why aren't we getting a relative url part, to join? */
  542.         nerror = nsurl_create(lwc_string_data(url), &ns_url);
  543.         if (nerror != NSERROR_OK) {
  544.                 free(ctx);
  545.                 return CSS_NOMEM;
  546.         }
  547.  
  548.         /* TODO: Constructing nsurl for referer here is silly, avoid */
  549.         nerror = nsurl_create(referer, &ns_ref);
  550.         if (nerror != NSERROR_OK) {
  551.                 nsurl_unref(ns_url);
  552.                 free(ctx);
  553.                 return CSS_NOMEM;
  554.         }
  555.  
  556.         /* Avoid importing ourself */
  557.         if (nsurl_compare(ns_url, ns_ref, NSURL_COMPLETE)) {
  558.                 c->imports[c->import_count].c = NULL;
  559.                 /* No longer require context as we're not fetching anything */
  560.                 free(ctx);
  561.                 ctx = NULL;
  562.         } else {
  563.                 nerror = hlcache_handle_retrieve(ns_url,
  564.                                 0, ns_ref, NULL, nscss_import, ctx,
  565.                                 &child, accept,
  566.                                 &c->imports[c->import_count].c);
  567.                 if (nerror != NSERROR_OK) {
  568.                         free(ctx);
  569.                         return CSS_NOMEM;
  570.                 }
  571.         }
  572.  
  573.         nsurl_unref(ns_url);
  574.         nsurl_unref(ns_ref);
  575.  
  576. #ifdef NSCSS_IMPORT_TRACE
  577.         LOG(("Import %d '%s' -> (handle: %p ctx: %p)",
  578.                         c->import_count, lwc_string_data(url),
  579.                         c->imports[c->import_count].c, ctx));
  580. #endif
  581.  
  582.         c->import_count++;
  583.  
  584.         return CSS_OK;
  585. }
  586.  
  587. /**
  588.  * Handler for imported stylesheet events
  589.  *
  590.  * \param handle  Handle for stylesheet
  591.  * \param event   Event object
  592.  * \param pw      Callback context
  593.  * \return NSERROR_OK on success, appropriate error otherwise
  594.  */
  595. nserror nscss_import(hlcache_handle *handle,
  596.                 const hlcache_event *event, void *pw)
  597. {
  598.         nscss_import_ctx *ctx = pw;
  599.         css_error error = CSS_OK;
  600.  
  601. #ifdef NSCSS_IMPORT_TRACE
  602.         LOG(("Event %d for %p (%p)", event->type, handle, ctx));
  603. #endif
  604.  
  605.         assert(ctx->css->imports[ctx->index].c == handle);
  606.  
  607.         switch (event->type) {
  608.         case CONTENT_MSG_LOADING:
  609.                 break;
  610.         case CONTENT_MSG_READY:
  611.                 break;
  612.         case CONTENT_MSG_DONE:
  613.                 error = nscss_import_complete(ctx);
  614.                 break;
  615.         case CONTENT_MSG_ERROR:
  616.                 hlcache_handle_release(handle);
  617.                 ctx->css->imports[ctx->index].c = NULL;
  618.  
  619.                 error = nscss_import_complete(ctx);
  620.                 /* Already released handle */
  621.                 break;
  622.         case CONTENT_MSG_STATUS:
  623.                 break;
  624.         default:
  625.                 assert(0);
  626.         }
  627.  
  628.         /* Preserve out-of-memory. Anything else is OK */
  629.         return error == CSS_NOMEM ? NSERROR_NOMEM : NSERROR_OK;
  630. }
  631.  
  632. /**
  633.  * Handle an imported stylesheet completing
  634.  *
  635.  * \param ctx  Import context
  636.  * \return CSS_OK on success, appropriate error otherwise
  637.  */
  638. css_error nscss_import_complete(nscss_import_ctx *ctx)
  639. {
  640.         css_error error = CSS_OK;
  641.  
  642.         /* If this import is the next to be registered, do so */
  643.         if (ctx->css->next_to_register == ctx->index)
  644.                 error = nscss_register_imports(ctx->css);
  645.  
  646. #ifdef NSCSS_IMPORT_TRACE
  647.         LOG(("Destroying import context %p for %d", ctx, ctx->index));
  648. #endif
  649.  
  650.         /* No longer need import context */
  651.         free(ctx);
  652.  
  653.         return error;
  654. }
  655.  
  656. /*****************************************************************************
  657.  * Import registration                                                       *
  658.  *****************************************************************************/
  659.  
  660. /**
  661.  * Register imports with a stylesheet
  662.  *
  663.  * \param c  CSS object containing the imports
  664.  * \return CSS_OK on success, appropriate error otherwise
  665.  */
  666. css_error nscss_register_imports(struct content_css_data *c)
  667. {
  668.         uint32_t index;
  669.         css_error error;
  670.  
  671.         assert(c->next_to_register != (uint32_t) -1);
  672.         assert(c->next_to_register < c->import_count);
  673.  
  674.         /* Register imported sheets */
  675.         for (index = c->next_to_register; index < c->import_count; index++) {
  676.                 /* Stop registering if we encounter one whose fetch hasn't
  677.                  * completed yet. We'll resume at this point when it has
  678.                  * completed.
  679.                  */
  680.                 if (c->imports[index].c != NULL &&
  681.                         content_get_status(c->imports[index].c) !=
  682.                                 CONTENT_STATUS_DONE) {
  683.                         break;
  684.                 }
  685.  
  686.                 error = nscss_register_import(c, c->imports[index].c);
  687.                 if (error != CSS_OK)
  688.                         return error;
  689.         }
  690.  
  691.         /* Record identity of the next import to register */
  692.         c->next_to_register = (uint32_t) index;
  693.  
  694.         if (c->next_to_register == c->import_count) {
  695.                 /* No more imports: notify parent that we're DONE */
  696.                 c->done(c, c->pw);
  697.         }
  698.  
  699.         return CSS_OK;
  700. }
  701.  
  702.  
  703. /**
  704.  * Register an import with a stylesheet
  705.  *
  706.  * \param c       CSS object that requested the import
  707.  * \param import  Cache handle of import, or NULL for blank
  708.  * \return CSS_OK on success, appropriate error otherwise
  709.  */
  710. css_error nscss_register_import(struct content_css_data *c,
  711.                 const hlcache_handle *import)
  712. {
  713.         css_stylesheet *sheet;
  714.         css_error error;
  715.  
  716.         if (import != NULL) {
  717.                 nscss_content *s =
  718.                         (nscss_content *) hlcache_handle_get_content(import);
  719.                 sheet = s->data.sheet;
  720.         } else {
  721.                 /* Create a blank sheet if needed. */
  722.                 if (blank_import == NULL) {
  723.                         css_stylesheet_params params;
  724.  
  725.                         params.params_version = CSS_STYLESHEET_PARAMS_VERSION_1;
  726.                         params.level = CSS_LEVEL_DEFAULT;
  727.                         params.charset = NULL;
  728.                         params.url = "";
  729.                         params.title = NULL;
  730.                         params.allow_quirks = false;
  731.                         params.inline_style = false;
  732.                         params.resolve = nscss_resolve_url;
  733.                         params.resolve_pw = NULL;
  734.                         params.import = NULL;
  735.                         params.import_pw = NULL;
  736.                         params.color = gui_system_colour;
  737.                         params.color_pw = NULL;
  738.                         params.font = NULL;
  739.                         params.font_pw = NULL;
  740.  
  741.                         error = css_stylesheet_create(&params,
  742.                                         ns_realloc, NULL,
  743.                                         &blank_import);
  744.                         if (error != CSS_OK) {
  745.                                 return error;
  746.                         }
  747.  
  748.                         error = css_stylesheet_data_done(blank_import);
  749.                         if (error != CSS_OK) {
  750.                                 css_stylesheet_destroy(blank_import);
  751.                                 return error;
  752.                         }
  753.                 }
  754.  
  755.                 sheet = blank_import;
  756.         }
  757.  
  758.         error = css_stylesheet_register_import(c->sheet, sheet);
  759.         if (error != CSS_OK) {
  760.                 return error;
  761.         }
  762.  
  763.         return error;
  764. }
  765.  
  766. /**
  767.  * Clean up after the CSS content handler
  768.  */
  769. static void nscss_fini(void)
  770. {
  771.         if (css_charset != NULL) {
  772.                 lwc_string_unref(css_charset);
  773.                 css_charset = NULL;
  774.         }
  775.  
  776.         if (blank_import != NULL) {
  777.                 css_stylesheet_destroy(blank_import);
  778.                 blank_import = NULL;
  779.         }
  780. }
  781.  
  782. static const content_handler css_content_handler = {
  783.         .fini = nscss_fini,
  784.         .create = nscss_create,
  785.         .process_data = nscss_process_data,
  786.         .data_complete = nscss_convert,
  787.         .destroy = nscss_destroy,
  788.         .clone = nscss_clone,
  789.         .matches_quirks = nscss_matches_quirks,
  790.         .type = nscss_content_type,
  791.         .no_share = false,
  792. };
  793.  
  794. /**
  795.  * Initialise the CSS content handler
  796.  */
  797. nserror nscss_init(void)
  798. {
  799.         lwc_error lerror;
  800.         nserror error;
  801.  
  802.         lerror = lwc_intern_string("charset", SLEN("charset"), &css_charset);
  803.         if (lerror != lwc_error_ok) {
  804.                 error = NSERROR_NOMEM;
  805.                 goto error;
  806.         }
  807.  
  808.         error = content_factory_register_handler("text/css",
  809.                         &css_content_handler);
  810.         if (error != NSERROR_OK)
  811.                 goto error;
  812.  
  813.         return NSERROR_OK;
  814.  
  815. error:
  816.         nscss_fini();
  817.  
  818.         return error;
  819. }
  820.