style.cpp revision f54dc25ef4a7a1a0ae8ab66e8ec1e33dac5077b7
/**
* @file
* SVG stylesheets implementation.
*/
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* Peter Moulder <pmoulder@mail.csse.monash.edu.au>
* bulia byak <buliabyak@users.sf.net>
* Abhishek Sharma
* Tavmjong Bah <tavmjong@free.fr>
* Kris De Gussem <Kris.DeGussem@gmail.com>
*
* Copyright (C) 2001-2002 Lauris Kaplinski
* Copyright (C) 2001 Ximian, Inc.
* Copyright (C) 2005 Monash University
* Copyright (C) 2012 Kris De Gussem
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstring>
#include <string>
#include "libcroco/cr-sel-eng.h"
#include "xml/croco-node-iface.h"
#include "svg/svg-color.h"
#include "svg/svg-icc-color.h"
#include "display/canvas-bpath.h"
#include "attributes.h"
#include "document.h"
#include "extract-uri.h"
#include "uri-references.h"
#include "uri.h"
#include "sp-paint-server.h"
#include "streq.h"
#include "strneq.h"
#include "style.h"
#include "svg/css-ostringstream.h"
#include "xml/simple-document.h"
#include "unit-constants.h"
#include "macros.h"
#include "preferences.h"
#include "sp-filter-reference.h"
using Inkscape::CSSOStringStream;
#define BMAX 8192
#define SP_CSS_FONT_SIZE_DEFAULT 12.0;
class SPStyleEnum;
/*#########################
## FORWARD DECLARATIONS
#########################*/
static SPTextStyle *sp_text_style_new(void);
static guint sp_text_style_write(gchar *p, guint len, SPTextStyle const *st, guint flags = SP_STYLE_FLAG_IFSET);
static void sp_style_read_ienum(SPIEnum *val, gchar const *str, SPStyleEnum const *dict, bool can_explicitly_inherit);
static void sp_style_read_icolor(SPIPaint *paint, gchar const *str, SPStyle *style, SPDocument *document);
static void sp_style_read_penum(SPIEnum *val, Inkscape::XML::Node *repr, gchar const *key, SPStyleEnum const *dict, bool can_explicitly_inherit);
static void sp_style_read_pbaselineshift(SPIBaselineShift *val, Inkscape::XML::Node *repr, gchar const *key);
static gint sp_style_write_ifloat(gchar *p, gint len, gchar const *key, SPIFloat const *val, SPIFloat const *base, guint flags);
static gint sp_style_write_iscale24(gchar *p, gint len, gchar const *key, SPIScale24 const *val, SPIScale24 const *base, guint flags);
static gint sp_style_write_ienum(gchar *p, gint len, gchar const *key, SPStyleEnum const *dict, SPIEnum const *val, SPIEnum const *base, guint flags);
static gint sp_style_write_istring(gchar *p, gint len, gchar const *key, SPIString const *val, SPIString const *base, guint flags);
static gint sp_style_write_ilength(gchar *p, gint len, gchar const *key, SPILength const *val, SPILength const *base, guint flags);
static gint sp_style_write_ipaint(gchar *b, gint len, gchar const *key, SPIPaint const *paint, SPIPaint const *base, guint flags);
static gint sp_style_write_ifontsize(gchar *p, gint len, gchar const *key, SPIFontSize const *val, SPIFontSize const *base, guint flags);
static gint sp_style_write_ibaselineshift(gchar *p, gint len, gchar const *key, SPIBaselineShift const *val, SPIBaselineShift const *base, guint flags);
static gint sp_style_write_ilengthornormal(gchar *p, gint const len, gchar const *const key, SPILengthOrNormal const *const val, SPILengthOrNormal const *const base, guint const flags);
static gint sp_style_write_itextdecoration(gchar *p, gint const len, gchar const *const key, SPITextDecoration const *const val, SPITextDecoration const *const base, guint const flags);
static gint sp_style_write_ifilter(gchar *b, gint len, gchar const *key, SPIFilter const *filter, SPIFilter const *base, guint flags);
#define SPS_READ_PENUM_IF_UNSET(v,r,k,d,i) if (!(v)->set) {sp_style_read_penum((v), (r), (k), (d), (i));}
#define SPS_READ_IBASELINE_SHIFT_IF_UNSET(v,s) if (!(v)->set) {sp_style_read_ibaselineshift((v), (s));}
#define SPS_READ_PBASELINE_SHIFT_IF_UNSET(v,r,k) if (!(v)->set) {sp_style_read_pbaselineshift((v), (r), (k));}
struct SPStyleEnum {
};
static SPStyleEnum const enum_fill_rule[] = {
{"nonzero", SP_WIND_RULE_NONZERO},
{"evenodd", SP_WIND_RULE_EVENODD},
{NULL, -1}
};
static SPStyleEnum const enum_stroke_linecap[] = {
{"butt", SP_STROKE_LINECAP_BUTT},
{"round", SP_STROKE_LINECAP_ROUND},
{"square", SP_STROKE_LINECAP_SQUARE},
{NULL, -1}
};
static SPStyleEnum const enum_stroke_linejoin[] = {
{"miter", SP_STROKE_LINEJOIN_MITER},
{"round", SP_STROKE_LINEJOIN_ROUND},
{"bevel", SP_STROKE_LINEJOIN_BEVEL},
{NULL, -1}
};
static SPStyleEnum const enum_font_style[] = {
{"normal", SP_CSS_FONT_STYLE_NORMAL},
{"italic", SP_CSS_FONT_STYLE_ITALIC},
{"oblique", SP_CSS_FONT_STYLE_OBLIQUE},
{NULL, -1}
};
static SPStyleEnum const enum_font_size[] = {
{"xx-small", SP_CSS_FONT_SIZE_XX_SMALL},
{"x-small", SP_CSS_FONT_SIZE_X_SMALL},
{"small", SP_CSS_FONT_SIZE_SMALL},
{"medium", SP_CSS_FONT_SIZE_MEDIUM},
{"large", SP_CSS_FONT_SIZE_LARGE},
{"x-large", SP_CSS_FONT_SIZE_X_LARGE},
{"xx-large", SP_CSS_FONT_SIZE_XX_LARGE},
{"smaller", SP_CSS_FONT_SIZE_SMALLER},
{"larger", SP_CSS_FONT_SIZE_LARGER},
{NULL, -1}
};
static SPStyleEnum const enum_font_variant[] = {
{"normal", SP_CSS_FONT_VARIANT_NORMAL},
{"small-caps", SP_CSS_FONT_VARIANT_SMALL_CAPS},
{NULL, -1}
};
static SPStyleEnum const enum_font_weight[] = {
{"100", SP_CSS_FONT_WEIGHT_100},
{"200", SP_CSS_FONT_WEIGHT_200},
{"300", SP_CSS_FONT_WEIGHT_300},
{"400", SP_CSS_FONT_WEIGHT_400},
{"500", SP_CSS_FONT_WEIGHT_500},
{"600", SP_CSS_FONT_WEIGHT_600},
{"700", SP_CSS_FONT_WEIGHT_700},
{"800", SP_CSS_FONT_WEIGHT_800},
{"900", SP_CSS_FONT_WEIGHT_900},
{"normal", SP_CSS_FONT_WEIGHT_NORMAL},
{"bold", SP_CSS_FONT_WEIGHT_BOLD},
{"lighter", SP_CSS_FONT_WEIGHT_LIGHTER},
{"bolder", SP_CSS_FONT_WEIGHT_BOLDER},
{NULL, -1}
};
static SPStyleEnum const enum_font_stretch[] = {
{"ultra-condensed", SP_CSS_FONT_STRETCH_ULTRA_CONDENSED},
{"extra-condensed", SP_CSS_FONT_STRETCH_EXTRA_CONDENSED},
{"condensed", SP_CSS_FONT_STRETCH_CONDENSED},
{"semi-condensed", SP_CSS_FONT_STRETCH_SEMI_CONDENSED},
{"normal", SP_CSS_FONT_STRETCH_NORMAL},
{"semi-expanded", SP_CSS_FONT_STRETCH_SEMI_EXPANDED},
{"expanded", SP_CSS_FONT_STRETCH_EXPANDED},
{"extra-expanded", SP_CSS_FONT_STRETCH_EXTRA_EXPANDED},
{"ultra-expanded", SP_CSS_FONT_STRETCH_ULTRA_EXPANDED},
{"narrower", SP_CSS_FONT_STRETCH_NARROWER},
{"wider", SP_CSS_FONT_STRETCH_WIDER},
{NULL, -1}
};
static SPStyleEnum const enum_text_align[] = {
{"start", SP_CSS_TEXT_ALIGN_START},
{"end", SP_CSS_TEXT_ALIGN_END},
{"left", SP_CSS_TEXT_ALIGN_LEFT},
{"right", SP_CSS_TEXT_ALIGN_RIGHT},
{"center", SP_CSS_TEXT_ALIGN_CENTER},
{"justify", SP_CSS_TEXT_ALIGN_JUSTIFY},
{NULL, -1}
};
static SPStyleEnum const enum_text_transform[] = {
{"capitalize", SP_CSS_TEXT_TRANSFORM_CAPITALIZE},
{"uppercase", SP_CSS_TEXT_TRANSFORM_UPPERCASE},
{"lowercase", SP_CSS_TEXT_TRANSFORM_LOWERCASE},
{"none", SP_CSS_TEXT_TRANSFORM_NONE},
{NULL, -1}
};
static SPStyleEnum const enum_text_anchor[] = {
{"start", SP_CSS_TEXT_ANCHOR_START},
{"middle", SP_CSS_TEXT_ANCHOR_MIDDLE},
{"end", SP_CSS_TEXT_ANCHOR_END},
{NULL, -1}
};
static SPStyleEnum const enum_direction[] = {
{"ltr", SP_CSS_DIRECTION_LTR},
{"rtl", SP_CSS_DIRECTION_RTL},
{NULL, -1}
};
static SPStyleEnum const enum_block_progression[] = {
{"tb", SP_CSS_BLOCK_PROGRESSION_TB},
{"rl", SP_CSS_BLOCK_PROGRESSION_RL},
{"lr", SP_CSS_BLOCK_PROGRESSION_LR},
{NULL, -1}
};
static SPStyleEnum const enum_writing_mode[] = {
/* Note that using the same enumerator for lr as lr-tb means we write as lr-tb even if the
* input file said lr. We prefer writing lr-tb on the grounds that the spec says the initial
* value is lr-tb rather than lr.
*
* ECMA scripts may be surprised to find tb-rl in DOM if they set the attribute to rl, so
* sharing enumerators for different strings may be a bug (once we support ecma script).
*/
{"lr-tb", SP_CSS_WRITING_MODE_LR_TB},
{"rl-tb", SP_CSS_WRITING_MODE_RL_TB},
{"tb-rl", SP_CSS_WRITING_MODE_TB_RL},
{"lr", SP_CSS_WRITING_MODE_LR_TB},
{"rl", SP_CSS_WRITING_MODE_RL_TB},
{"tb", SP_CSS_WRITING_MODE_TB_RL},
{NULL, -1}
};
static SPStyleEnum const enum_baseline_shift[] = {
{"baseline", SP_CSS_BASELINE_SHIFT_BASELINE},
{"sub", SP_CSS_BASELINE_SHIFT_SUB},
{"super", SP_CSS_BASELINE_SHIFT_SUPER},
{NULL, -1}
};
static SPStyleEnum const enum_visibility[] = {
{"hidden", SP_CSS_VISIBILITY_HIDDEN},
{"collapse", SP_CSS_VISIBILITY_COLLAPSE},
{"visible", SP_CSS_VISIBILITY_VISIBLE},
{NULL, -1}
};
static SPStyleEnum const enum_overflow[] = {
{"visible", SP_CSS_OVERFLOW_VISIBLE},
{"hidden", SP_CSS_OVERFLOW_HIDDEN},
{"scroll", SP_CSS_OVERFLOW_SCROLL},
{"auto", SP_CSS_OVERFLOW_AUTO},
{NULL, -1}
};
static SPStyleEnum const enum_display[] = {
{"none", SP_CSS_DISPLAY_NONE},
{"inline", SP_CSS_DISPLAY_INLINE},
{"block", SP_CSS_DISPLAY_BLOCK},
{"list-item", SP_CSS_DISPLAY_LIST_ITEM},
{"run-in", SP_CSS_DISPLAY_RUN_IN},
{"compact", SP_CSS_DISPLAY_COMPACT},
{"marker", SP_CSS_DISPLAY_MARKER},
{"table", SP_CSS_DISPLAY_TABLE},
{"inline-table", SP_CSS_DISPLAY_INLINE_TABLE},
{"table-row-group", SP_CSS_DISPLAY_TABLE_ROW_GROUP},
{"table-header-group", SP_CSS_DISPLAY_TABLE_HEADER_GROUP},
{"table-footer-group", SP_CSS_DISPLAY_TABLE_FOOTER_GROUP},
{"table-row", SP_CSS_DISPLAY_TABLE_ROW},
{"table-column-group", SP_CSS_DISPLAY_TABLE_COLUMN_GROUP},
{"table-column", SP_CSS_DISPLAY_TABLE_COLUMN},
{"table-cell", SP_CSS_DISPLAY_TABLE_CELL},
{"table-caption", SP_CSS_DISPLAY_TABLE_CAPTION},
{NULL, -1}
};
static SPStyleEnum const enum_shape_rendering[] = {
{"auto", 0},
{"optimizeSpeed", 0},
{"crispEdges", 0},
{"geometricPrecision", 0},
{NULL, -1}
};
static SPStyleEnum const enum_color_rendering[] = {
{"auto", 0},
{"optimizeSpeed", 0},
{"optimizeQuality", 0},
{NULL, -1}
};
static SPStyleEnum const enum_text_rendering[] = {
{"auto", 0},
{"optimizeSpeed", 0},
{"optimizeLegibility", 0},
{"geometricPrecision", 0},
{NULL, -1}
};
static SPStyleEnum const enum_enable_background[] = {
{"accumulate", SP_CSS_BACKGROUND_ACCUMULATE},
{"new", SP_CSS_BACKGROUND_NEW},
{NULL, -1}
};
static SPStyleEnum const enum_clip_rule[] = {
{"nonzero", SP_WIND_RULE_NONZERO},
{"evenodd", SP_WIND_RULE_EVENODD},
{NULL, -1}
};
static SPStyleEnum const enum_color_interpolation[] = {
{"auto", SP_CSS_COLOR_INTERPOLATION_AUTO},
{"sRGB", SP_CSS_COLOR_INTERPOLATION_SRGB},
{"linearRGB", SP_CSS_COLOR_INTERPOLATION_LINEARRGB},
{NULL, -1}
};
/**
* Release callback.
*/
static void
{
(void)object; // TODO
}
/**
* Emit style modified signal on style's object if the filter changed.
*/
static void
{
(void)flags; // TODO
{
}
}
}
/**
* Gets called when the filter is (re)attached to the style
*/
static void
{
if (old_ref) {
}
if ( SP_IS_FILTER(ref))
{
}
}
/**
* Emit style modified signal on style's object if server is style's fill
* or stroke paint server.
*/
static void
{
(void)flags; // TODO
{
/** \todo
* fixme: I do not know, whether it is optimal - we are
* forcing reread of everything (Lauris)
*/
/** \todo
* fixme: We have to use object_modified flag, because parent
* flag is only available downstreams.
*/
}
{
/// \todo fixme:
}
} else if (server) {
}
}
/**
* Gets called when the paintserver is (re)attached to the style
*/
static void
{
if (old_ref) {
}
if (SP_IS_PAINT_SERVER(ref)) {
}
}
/**
* Gets called when the paintserver is (re)attached to the style
*/
static void
{
if (old_ref) {
}
if (SP_IS_PAINT_SERVER(ref)) {
}
}
/**
* Returns a new SPStyle object with settings as per sp_style_clear().
*/
SPStyle *
{
return style;
}
/**
* Creates a new SPStyle object, and attaches it to the specified SPObject.
*/
SPStyle *
{
style->release_connection = object->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_style_object_release), style));
}
return style;
}
/**
* Increase refcount of style.
*/
SPStyle *
{
return style;
}
/**
* Decrease refcount of style with possible destruction.
*/
SPStyle *
{
}
}
}
}
return NULL;
}
/**
* Reads the various style parameters for an object from repr.
*/
static void
{
}
/* 1. Style attribute */
}
if (object) {
} else {
/** \todo No stylesheet information. Find out under what circumstances
* this occurs, and handle accordingly. (If we really wanted to, we
* could probably get stylesheets by going through repr->doc.)
*/
}
/* 2. Presentation attributes */
/* CSS2 */
/* Font */
/* Text (css2 chapter 16) */
if (val) {
}
}
if (val) {
}
}
if (val) {
}
}
if (val) {
}
}
SPS_READ_PENUM_IF_UNSET(&style->block_progression, repr, "block_progression", enum_block_progression, true);
/* SVG */
enum_writing_mode, true);
enum_text_anchor, true);
/* opacity */
if (val) {
}
}
/* color */
if (val) {
: NULL ));
}
}
/* color interpolation */
SPS_READ_PENUM_IF_UNSET(&style->color_interpolation, repr, "color_interpolation", enum_color_interpolation, true);
/* color interpolation filters*/
SPS_READ_PENUM_IF_UNSET(&style->color_interpolation_filters, repr, "color_interpolation_filters", enum_color_interpolation, true);
/* fill */
if (val) {
}
}
/* fill-opacity */
if (val) {
}
}
/* fill-rule */
/* stroke */
if (val) {
}
}
SPS_READ_PENUM_IF_UNSET(&style->stroke_linejoin, repr, "stroke-linejoin", enum_stroke_linejoin, true);
/* markers */
if (val) {
}
}
if (val) {
}
}
if (val) {
}
}
if (val) {
}
}
/* stroke-opacity */
if (val) {
}
}
if (!style->stroke_dasharray_set) {
if (val) {
}
}
if (!style->stroke_dashoffset_set) {
} else {
}
}
/* -inkscape-font-specification */
if (val) {
}
}
/* font-family */
if (val) {
}
}
/* filter effects */
if (val) {
}
}
"enable-background", enum_enable_background, true);
/* clip-rule */
/* 3. Merge from parent */
if (object) {
}
} else {
/// \todo fixme: This is not the prettiest thing (Lauris)
}
}
}
/**
* Read style properties from object's repr.
*
* 1. Reset existing object style
* 2. Load current effective object style
* 3. Load i attributes from immediate parent (which has to be up-to-date)
*/
void
{
}
/**
* Read style properties from preferences.
* @param style The style to write to
* @param path Preferences directory from which the style should be read
*/
void
{
// not optimal: we reconstruct the node based on the prefs, then pass it to
// sp_style_read for actual processing.
for (std::vector<Inkscape::Preferences::Entry>::iterator i = attrs.begin(); i != attrs.end(); ++i) {
}
delete tempdoc;
}
/**
*
*/
static void
{
}
/**
* Merge property into style.
*
* Should be called in order of highest to lowest precedence.
* E.g. for a single style string, call from the last declaration to the first,
* as CSS says that later declarations override earlier ones.
*
* \pre val != NULL.
*/
static void
{
switch (id) {
}
break;
/* CSS2 */
/* Font */
case SP_PROP_FONT_FAMILY:
}
break;
case SP_PROP_FONT_SIZE:
break;
case SP_PROP_FONT_SIZE_ADJUST:
}
break;
case SP_PROP_FONT_STYLE:
break;
case SP_PROP_FONT_VARIANT:
break;
case SP_PROP_FONT_WEIGHT:
break;
case SP_PROP_FONT_STRETCH:
break;
case SP_PROP_FONT:
// Break string into white space separated tokens
// CSS is case insensitive but we're comparing against lowercase strings
if (lparam == "/") {
// Eat the line-height for the moment as it is not an SVG property.
// lparam = param.lowercase();
// sp_style_read_ilengthornormal(&style->line_height, lparam);
} else {
// Skip if "normal" as that is the default (and we don't know which attribute it applies to).
if (lparam == "normal") continue;
// Check each property in turn
// font-style
// Read once to see if param is valid style. If valid, .set will be TRUE.
// If valid style parameter
if (test_style.set) {
// If not previously set
}
continue; // Next parameter.
}
// font-variant (small-caps)
// If valid variant parameter
if (test_variant.set) {
// If not previously set
}
continue; // Next parameter.
}
// font-weight
// If valid weight parameter
if (test_weight.set) {
// If not previously set
}
continue; // Next parameter
}
// Font-size
// Read once to see if param is valid size.
// If valid size parameter
// If not previously set
}
continue;
}
// No valid property value found.
break;
}
} // params
// The rest must be font-family...
}
// Set all properties to their default values per CSS 2.1 spec if not already set
// Line height is not an SVG property but Inkscape uses it for multi-line text.
// sp_style_read_ilengthornormal(&style->line_height, "normal");
}
break;
/* Text */
case SP_PROP_TEXT_INDENT:
break;
case SP_PROP_TEXT_ALIGN:
break;
case SP_PROP_TEXT_DECORATION:
}
break;
case SP_PROP_LINE_HEIGHT:
}
break;
case SP_PROP_LETTER_SPACING:
}
break;
case SP_PROP_WORD_SPACING:
}
break;
case SP_PROP_TEXT_TRANSFORM:
break;
/* Text (css3) */
case SP_PROP_DIRECTION:
break;
break;
case SP_PROP_WRITING_MODE:
break;
case SP_PROP_TEXT_ANCHOR:
break;
case SP_PROP_BASELINE_SHIFT:
break;
/* Text (unimplemented) */
case SP_PROP_TEXT_RENDERING: {
/* Ignore the hint. */
break;
}
break;
break;
break;
break;
case SP_PROP_KERNING:
break;
/* Misc */
case SP_PROP_CLIP:
break;
case SP_PROP_COLOR:
}
break;
case SP_PROP_CURSOR:
break;
case SP_PROP_DISPLAY:
break;
case SP_PROP_OVERFLOW:
/** \todo
* FIXME: not supported properly yet, we just read and write it,
* but act as if it is always "display".
*/
break;
case SP_PROP_VISIBILITY:
break;
/* SVG */
case SP_PROP_CLIP_PATH:
/** \todo
* This is a workaround. Inkscape only supports 'clip-path' as SVG attribute, not as
* style property. By having both CSS and SVG attribute set, editing of clip-path
* will fail, since CSS always overwrites SVG attributes.
* Fixes Bug #324849
*/
g_warning("attribute 'clip-path' given as CSS");
//XML Tree being directly used here.
break;
case SP_PROP_CLIP_RULE:
}
break;
case SP_PROP_MASK:
/** \todo
* See comment for SP_PROP_CLIP_PATH
*/
g_warning("attribute 'mask' given as CSS");
//XML Tree being directly used here.
break;
case SP_PROP_OPACITY:
}
break;
enum_enable_background, true);
break;
/* Filter */
case SP_PROP_FILTER:
}
break;
case SP_PROP_FLOOD_COLOR:
break;
case SP_PROP_FLOOD_OPACITY:
break;
case SP_PROP_LIGHTING_COLOR:
break;
/* Gradient */
case SP_PROP_STOP_COLOR:
break;
case SP_PROP_STOP_OPACITY:
break;
/* Interactivity */
case SP_PROP_POINTER_EVENTS:
break;
/* Paint */
// We read it but issue warning
g_warning("Inkscape currently only supports color-interpolation = sRGB");
}
break;
// We read it but issue warning
g_warning("Inkscape currently only supports color-interpolation-filters = sRGB");
}
break;
case SP_PROP_COLOR_PROFILE:
break;
case SP_PROP_COLOR_RENDERING: {
/* Ignore the hint. */
break;
}
case SP_PROP_FILL:
}
break;
case SP_PROP_FILL_OPACITY:
}
break;
case SP_PROP_FILL_RULE:
}
break;
case SP_PROP_IMAGE_RENDERING: {
/* Ignore the hint. */
break;
}
case SP_PROP_MARKER:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
/* style->marker[SP_MARKER_LOC] = g_quark_from_string(val); */
}
break;
case SP_PROP_MARKER_START:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
}
break;
case SP_PROP_MARKER_MID:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
}
break;
case SP_PROP_MARKER_END:
/* TODO: Call sp_uri_reference_resolve(SPDocument *document, guchar const *uri) */
}
break;
case SP_PROP_SHAPE_RENDERING: {
/* Ignore the hint. */
break;
}
case SP_PROP_STROKE:
}
break;
case SP_PROP_STROKE_WIDTH:
break;
case SP_PROP_STROKE_DASHARRAY:
if (!style->stroke_dasharray_set) {
}
break;
if (!style->stroke_dashoffset_set) {
} else {
}
}
break;
case SP_PROP_STROKE_LINECAP:
}
break;
case SP_PROP_STROKE_LINEJOIN:
}
break;
}
break;
case SP_PROP_STROKE_OPACITY:
}
break;
default:
break;
}
}
static void
{
/** \todo Ensure that property is lcased, as per
* Should probably be done in libcroco.
*/
if (prop_idx != SP_ATTR_INVALID) {
/** \todo
* effic: Test whether the property is already set before trying to
* convert to string. Alternatively, set from CRTerm directly rather
* than converting to string.
*/
}
}
static void
{
#if 0 /* forwards */
}
#else /* in reverse order, as we need later declarations to take precedence over earlier ones. */
if (props) {
}
#endif
}
/**
* \pre decl_list != NULL
*/
static void
{
// read the decls from end to start, using head recursion, so that latter declarations override
// (Ref: http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order point 4.)
// because sp_style_merge_style_from_decl only sets properties that are unset
}
}
static CRSelEng *
{
/** \todo
* Check whether we need to register any pseudo-class handlers.
* libcroco has its own default handlers for first-child and lang.
*
* We probably want handlers for link and arguably visited (though
* inkscape can't visit links at the time of writing). hover etc.
* more useful in inkview than the editor inkscape.
*
* http://www.w3.org/TR/SVG11/styling.html#StylingWithCSS says that
* the following should be honoured, at least by inkview:
* :hover, :active, :focus, :visited, :link.
*/
return ret;
}
static void
{
if (!sel_eng) {
sel_eng = sp_repr_sel_eng();
}
//XML Tree being directly used here while it shouldn't be.
&props);
/// \todo Check what errors can occur, and handle them properly.
if (props) {
}
}
/**
* Parses a style="..." string and merges it with an existing SPStyle.
*/
void
{
/*
* Reference: http://www.w3.org/TR/SVG11/styling.html#StyleAttribute:
* ``When CSS styling is used, CSS inline style is specified by including
* semicolon-separated property declarations of the form "name : value"
* within the style attribute''.
*
* That's fairly ambiguous. Is a `value' allowed to contain semicolons?
* Why does it say "including", what else is allowed in the style
* attribute value?
*/
CRDeclaration *const decl_list
if (decl_list) {
}
}
/** Indexed by SP_CSS_FONT_SIZE_blah. */
static void
{
/* 'font-size' */
/* Inherit the computed value. Reference: http://www.w3.org/TR/SVG11/styling.html#Inheritance */
/** \todo
* fixme: SVG and CSS do not specify clearly, whether we should use
* user or screen coordinates (Lauris)
*/
} else {
/* Illegal value */
}
/* Unlike most other lengths, percentage for font size is relative to parent computed value
* rather than viewport. */
case SP_CSS_UNIT_EM:
/* Relative to parent font size */
break;
case SP_CSS_UNIT_EX:
/* Relative to parent font size */
break;
default:
/* No change */
break;
}
}
}
// Some shifts are defined relative to parent.
static void
SPIFontSize const &pfont_size)
{
/* 'baseline-shift' */
/* Inherit the computed value. Reference: http://www.w3.org/TR/SVG11/styling.html#Inheritance */
// Should use subscript position from font relative to alphabetic baseline
// OpenOffice, Adobe: -0.33, Word -0.14, LaTex about -0.2.
// Should use superscript position from font relative to alphabetic baseline
// OpenOffice, Adobe: 0.33, Word 0.35, LaTex about 0.45.
} else {
/* Illegal value */
}
// Percentage for baseline shift is relative to computed "line-height"
// which is just font-size (see SVG1.1 'font').
case SP_CSS_UNIT_EM:
break;
case SP_CSS_UNIT_EX:
break;
default:
/* No change */
break;
}
}
// baseline-shifts are relative to parent baseline
}
/**
* Sets computed values in \a style, which may involve inheriting from (or in some other way
* calculating from) corresponding computed values of \a parent.
*
* References: http://www.w3.org/TR/SVG11/propidx.html shows what properties inherit by default.
* http://www.w3.org/TR/SVG11/styling.html#Inheritance gives general rules as to what it means to
* inherit a value. http://www.w3.org/TR/REC-CSS2/cascade.html#computed-value is more precise
* about what the computed value is (not obvious for lengths).
*
* \pre \a parent's computed values are already up-to-date.
*/
void
{
/** \todo
* fixme: Check for existing callers that might pass null parent.
* This should probably be g_return_if_fail, or else we should make a
* best attempt to set computed values correctly without having a parent
* (i.e., by assuming parent has initial values).
*/
if (!parent)
return;
/* CSS2 */
/* Font */
/* 'font-style' */
}
/* 'font-variant' */
}
/* 'font-weight' */
/** \todo
* fixme: This is unconditional, i.e., happens even if parent not
* present.
*/
g_assert(SP_CSS_FONT_WEIGHT_100 == 0);
// strictly, 'bolder' and 'lighter' should go to the next weight
// expressible in the current font family, but that's difficult to
// find out, so jumping by 3 seems an appropriate approximation
? (unsigned)SP_CSS_FONT_WEIGHT_100
: parent_val - 3);
? (unsigned)SP_CSS_FONT_WEIGHT_900
: parent_val + 3);
}
/* 'font-stretch' */
: parent_val - 1);
: parent_val + 1);
}
/* text (css2) */
}
}
}
}
}
}
}
}
}
}
}
/* Baseline Shift... Some shifts are relative to parent. */
}
/* Color */
}
}
}
/* Fill */
}
}
}
/* Stroke */
}
} else {
/* Update computed value for any change in font inherited from parent. */
}
}
}
}
}
memcpy(style->stroke_dash.dash, parent->stroke_dash.dash, style->stroke_dash.n_dash * sizeof(gdouble));
}
}
}
}
}
}
}
}
/* Markers - Free the old value and make copy of the new */
for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
}
}
/* Filter effects */
}
}
/* Clipping */
}
}
template <typename T>
static void
{
{
}
}
/**
* Copy SPIString from parent to child.
*/
static void
{
{
}
}
static void
{
/** \todo
* I haven't given this much attention. See comments below about
* currentColor, colorProfile, and relative URIs.
*/
}
}
static void
unsigned const max_computed_val,
unsigned const smaller_val)
{
/* We assume that min computed val is 0, contiguous up to max_computed_val,
then zero or more other absolute values, then smaller_val then larger_val. */
unsigned const min_computed_val = 0;
/* Child has absolute value: leave as is. */
{
/*
* Note that this can result in a change in computed value in the
* rare case that the parent's setting was a no-op (i.e. if the
* parent's parent's computed value was already ultra-condensed or
* ultra-expanded). However, I'd guess that the change is for the
* better: I'd guess that if the properties were specified
* relatively, then the intent is to counteract parent's effect.
* I.e. I believe this is the best code even in that case.
*/
/* Leave as is. */
/** \todo
* It's unclear what to do if style and parent specify the same
* relative directive (narrower or wider). We can either convert
* to absolute specification or coalesce to a single relative
* request (of half the strength of the original pair).
*
* Converting to a single level of relative specification is a
* better choice if the newly-unlinked clone is itself cloned to
* other contexts (inheriting different font stretchiness): it
* would preserve the effect that it will be narrower than
* the inherited context in each case. The disadvantage is that
* it will ~certainly affect the computed value of the
* newly-unlinked clone.
*/
} else {
? ( parent_val == min_computed_val
: parent_val - 1 )
: ( parent_val == max_computed_val
: parent_val + 1 ) );
}
}
}
template <typename LengthT>
static void
double const parent_child_em_ratio)
{
{
case SP_CSS_UNIT_EM:
case SP_CSS_UNIT_EX:
/** \todo
* fixme: Have separate ex ratio parameter.
* Get x height from libnrtype or pango.
*/
}
break;
default:
break;
}
}
}
static double
{
case SP_FONT_SIZE_LITERAL: {
case SP_CSS_FONT_SIZE_SMALLER:
return 5.0 / 6.0;
case SP_CSS_FONT_SIZE_LARGER:
return 6.0 / 5.0;
default:
}
}
case SP_FONT_SIZE_PERCENTAGE:
case SP_FONT_SIZE_LENGTH: {
case SP_CSS_UNIT_EM:
case SP_CSS_UNIT_EX:
default:
}
}
}
}
/**
* Combine \a style and \a parent style specifications into a single style specification that
* preserves (as much as possible) the effect of the existing \a style being a child of \a parent.
*
* Called when the parent repr is to be removed (e.g. the parent is a \<use\> element that is being
* trying to retain the same visual appearance once the parent is removed. Interesting cases are
* when there is unusual interaction with the parent's value (opacity, display) or when the value
* can be specified as relative to the parent computed value (font-size, font-weight etc.).
*
* Doesn't update computed values of \a style. For correctness, you should subsequently call
* sp_style_merge_from_parent against the new parent (presumably \a parent's parent) even if \a
* style was previously up-to-date wrt \a parent.
*
* \pre \a parent's computed values are already up-to-date.
* (\a style's computed values needn't be up-to-date.)
*/
void
{
/** \note
* The general rule for each property is as follows:
*
* If style is set to an absolute value, then leave it as is.
*
* Otherwise (i.e. if style has a relative value):
*
* If parent is set to an absolute value, then set style to the computed value.
*
* Otherwise, calculate the combined relative value (e.g. multiplying the two percentages).
*/
/* We do font-size first, to ensure that em size is up-to-date. */
/** \todo
* fixme: We'll need to have more font-related things up the top once
* we're getting x-height from pango or libnrtype.
*/
/* Some things that allow relative specifications. */
{
/* font-size. Note that we update the computed font-size of style,
to assist in em calculations later in this function. */
/* Parent has defined font-size */
/* font_size inherits the computed value, so we can use the parent value
* verbatim. */
/* Child already has absolute size (stored in computed value), so do nothing. */
/* Child already has absolute size, but we ensure that the computed value
is up-to-date. */
} else {
/* Child has relative size. */
/* Absolute value. */
} else {
/* Relative value. */
} else {
}
}
}
}
/* 'font-stretch' */
/* font-weight */
}
/* Enum values that don't have any relative settings (other than `inherit'). */
{
//nyi: SPStyle::color_rendering,
//nyi: SPStyle::image_rendering,
//nyi: SPStyle::pointer_events,
//nyi: SPStyle::shape_rendering,
//nyi: &SPStyle::text_rendering,
};
for (unsigned i = 0; i < G_N_ELEMENTS(fields); ++i) {
}
}
/* A few other simple inheritance properties. */
{
sp_style_merge_prop_from_dying_parent<SPIFloat>(style->stroke_miterlimit, parent->stroke_miterlimit);
/** \todo
* We currently treat text-decoration as if it were a simple inherited
* property (fixme). This code may need changing once we do the
*/
//nyi: font-size-adjust, // <number> | none | inherit
//nyi: glyph-orientation-horizontal,
//nyi: glyph-orientation-vertical,
}
/* Properties that involve length but are easy in other respects. */
{
/* The difficulty with lengths is that font-relative units need adjusting if the font
* varies between parent & child.
*
* Lengths specified in the existing child can stay as they are: its computed font
* specification should stay unchanged, so em & ex lengths should continue to mean the same
* size.
*
* Lengths specified in the dying parent in em or ex need to be scaled according to the
* ratio of em or ex size between parent & child.
*/
};
for (unsigned i = 0; i < G_N_ELEMENTS(lfields); ++i) {
}
};
for (unsigned i = 0; i < G_N_ELEMENTS(nfields); ++i) {
}
//nyi: &SPStyle::kerning: length or `auto'
/* fixme: Move stroke-dash and stroke-dash-offset here once they
can accept units. */
}
/* Properties that involve a URI but are easy in other respects. */
{
/** \todo
* Could cause problems if original object was in another document
* and it used a relative URL. (At the time of writing, we don't
* allow hrefs to other documents, so this isn't a problem yet.)
* Paint properties also allow URIs.
*/
//nyi: cursor, // may involve change in effect, but we can't do much better
//nyi: color-profile,
// Markers (marker-start, marker-mid, marker-end).
for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
}
}
/* CSS2 */
/* Font */
}
/* Properties that don't inherit by default. Most of these need special handling. */
{
/*
* opacity's effect is cumulative; we set the new value to the combined effect. The
* default value for opacity is 1.0, not inherit. (Note that stroke-opacity and
* fill-opacity are quite different from opacity, and don't need any special handling.)
*
* Cases:
* - parent & child were each previously unset, in which case the effective
* opacity value is 1.0, and style should remain unset.
* - parent was previously unset (so computed opacity value of 1.0)
* and child was set to inherit. The merged child should
* get a value of 1.0, and shouldn't inherit (lest the new parent
* has a different opacity value). Given that opacity's default
* value is 1.0 (rather than inherit), we might as well have the
* merged child's opacity be unset.
* - parent was previously unset (so opacity 1.0), and child was set to a number.
* The merged child should retain its existing settings (though it doesn't matter
* if we make it unset if that number was 1.0).
* - parent was inherit and child was unset. Merged child should be set to inherit.
* - parent was inherit and child was inherit. (We can't in general reproduce this
* effect (short of introducing a new group), but setting opacity to inherit is rare.)
* If the inherited value was strictly between 0.0 and 1.0 (exclusive) then the merged
* child's value should be set to the product of the two, i.e. the square of the
* inherited value, and should not be marked as inherit. (This decision assumes that it
* is more important to retain the effective opacity than to retain the inheriting
* effect, and assumes that the inheriting effect either isn't important enough to create
* a group or isn't common enough to bother maintaining the code to create a group.) If
* the inherited value was 0.0 or 1.0, then marking the merged child as inherit comes
* closer to maintaining the effect.
* - parent was inherit and child was set to a numerical value. If the child's value
* was 1.0, then the merged child should have the same settings as the parent.
* If the child's value was 0, then the merged child should also be set to 0.
* case above: have the merged child set to the product of the two opacities and not
* marked as inherit, for the same reasons as for that case.
* - parent was set to a value, and child was unset. The merged child should have
* parent's settings.
* - parent was set to a value, and child was inherit. The merged child should
* be set to the product, i.e. the square of the parent's value.
* - parent & child are each set to a value. The merged child should be set to the
* product.
*/
{
} else {
/* Ensure that style's computed value is up-to-date. */
}
/* Multiplication of opacities occurs even if a child's opacity is set to inherit. */
}
/* display is in principle similar to opacity, but implementation is easier. */
} else {
/* Leave as is. (display doesn't inherit by default.) */
}
/* enable-background - this is rather complicated, because
* it is valid only when applied to container elements.
* Let's check a simple case anyhow. */
{
}
{
}
/** \todo
* fixme: Check that we correctly handle all properties that don't
* inherit by default (as shown in
* http://www.w3.org/TR/SVG11/propidx.html for most SVG 1.1 properties).
*/
}
/* SPIPaint properties (including color). */
{
/** \todo
* Think about the issues involved if specified as currentColor or
* if specified relative to colorProfile, and if the currentColor or
* colorProfile differs between parent \& child. See also comments
* elsewhere in this function about URIs.
*/
};
for (unsigned i = 0; i < G_N_ELEMENTS(fields); ++i) {
}
}
/* Things from SVG 1.2 or CSS3. */
{
/* Note: If we ever support setting string values for text-align then we'd need strdup
* handling here. */
sp_style_merge_prop_from_dying_parent<SPIEnum>(style->block_progression, parent->block_progression);
}
/* Note: this will need length handling once dasharray supports units. */
{
memcpy(style->stroke_dash.dash, parent->stroke_dash.dash, style->stroke_dash.n_dash * sizeof(gdouble));
}
}
/* Note: this will need length handling once dasharray_offset supports units. */
if ((!style->stroke_dashoffset_set || style->stroke_dashoffset_inherit) && parent->stroke_dashoffset_set && !parent->stroke_dashoffset_inherit) {
/* TODO: Try to
* represent it as a normal SPILength; though will need to do something about existing
* users of stroke_dash.offset and stroke_dashoffset_set. */
}
}
static void
sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI *uri, SPDocument *document)
{
// it may be that this style's SPIPaint has not yet created its URIReference;
// now that we have a document, we can create it here
paint->value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun((paint == &style->fill)? sp_style_fill_paint_server_ref_changed : sp_style_stroke_paint_server_ref_changed), style));
}
}
}
try {
} catch (Inkscape::BadURIException &e) {
}
}
}
static void
{
try {
} catch (...) {
}
}
void
{
}
gchar const *
{
// specify px by default, see inkscape bug 1221626, mozilla bug 234789
switch (unit) {
case SP_CSS_UNIT_NONE: return "px";
case SP_CSS_UNIT_PX: return "px";
case SP_CSS_UNIT_PT: return "pt";
case SP_CSS_UNIT_PC: return "pc";
case SP_CSS_UNIT_MM: return "mm";
case SP_CSS_UNIT_CM: return "cm";
case SP_CSS_UNIT_IN: return "in";
case SP_CSS_UNIT_EM: return "em";
case SP_CSS_UNIT_EX: return "ex";
case SP_CSS_UNIT_PERCENT: return "%";
default: return "px";
}
return "px";
}
/*
* Convert a size in pixels into another CSS unit size
*/
double
{
switch (unit) {
default:
break;
}
return unit_size;
}
/*
* Convert a size in a CSS unit size to pixels
*/
double
{
if (unit == SP_CSS_UNIT_PX) {
return size;
}
//g_message("sp_style_css_size_units_to_px %f %d = %f px", size, unit, out);
}
/**
*
*/
static void
{
return;
}
if ( parent->isPaintserver() ) {
sp_style_set_ipaint_to_uri(style, paint, parent->value.href->getURI(), parent->value.href->getOwnerDocument());
} else {
g_warning("Expected paint server not found.");
}
//
} else {
}
}
/**
* Merge filter style from parent.
* Filter effects do not inherit by default
*/
static void
{
// FIXME:
// instead of just copying over, we need to _really merge_ the two filters by combining their
// filter primitives
}
}
else{
// it may be that this style has not yet created its SPFilterReference
style->filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
}
}
}
try {
} catch (Inkscape::BadURIException &e) {
}
}
}
}
/**
* Dumps the style to a CSS string, with either SP_STYLE_FLAG_IFSET or
* SP_STYLE_FLAG_ALWAYS flags. Used with Always for copying an object's
* complete cascaded style to style_clipboard. When you need a CSS string
* for an object in the document tree, you normally call
* sp_style_write_difference instead to take into account the object's parent.
*
* \pre style != NULL.
* \pre flags in {IFSET, ALWAYS}.
* \post ret != NULL.
*/
gchar *
{
/** \todo
* Merge with write_difference, much duplicate code!
*/
(flags == SP_STYLE_FLAG_ALWAYS) ),
NULL);
gchar *p = c;
*p = '\0';
p += sp_style_write_ienum(p, c + BMAX - p, "font-style", enum_font_style, &style->font_style, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "font-variant", enum_font_variant, &style->font_variant, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "font-weight", enum_font_weight, &style->font_weight, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "font-stretch", enum_font_stretch, &style->font_stretch, NULL, flags);
/* Text */
p += sp_style_write_ienum(p, c + BMAX - p, "text-align", enum_text_align, &style->text_align, NULL, flags);
p += sp_style_write_itextdecoration(p, c + BMAX - p, "text-decoration", &style->text_decoration, NULL, flags);
p += sp_style_write_ilengthornormal(p, c + BMAX - p, "line-height", &style->line_height, NULL, flags);
p += sp_style_write_ilengthornormal(p, c + BMAX - p, "letter-spacing", &style->letter_spacing, NULL, flags);
p += sp_style_write_ilengthornormal(p, c + BMAX - p, "word-spacing", &style->word_spacing, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "text-transform", enum_text_transform, &style->text_transform, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "direction", enum_direction, &style->direction, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "block-progression", enum_block_progression, &style->block_progression, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "writing-mode", enum_writing_mode, &style->writing_mode, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "text-anchor", enum_text_anchor, &style->text_anchor, NULL, flags);
p += sp_style_write_ibaselineshift(p, c + BMAX - p, "baseline-shift", &style->baseline_shift, NULL, flags);
/// \todo fixme: Per type methods need default flag too (lauris)
}
}
p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation", enum_color_interpolation, &style->color_interpolation, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation-filters", enum_color_interpolation, &style->color_interpolation_filters, NULL, flags);
// if fill:none, skip writing fill properties
p += sp_style_write_ienum(p, c + BMAX - p, "fill-rule", enum_fill_rule, &style->fill_rule, NULL, flags);
}
// stroke width affects markers, so write it if there's stroke OR any markers
}
// if stroke:none, skip writing stroke properties
p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linecap", enum_stroke_linecap, &style->stroke_linecap, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "stroke-linejoin", enum_stroke_linejoin, &style->stroke_linejoin, NULL, flags);
p += sp_style_write_ifloat(p, c + BMAX - p, "stroke-miterlimit", &style->stroke_miterlimit, NULL, flags);
p += sp_style_write_iscale24(p, c + BMAX - p, "stroke-opacity", &style->stroke_opacity, NULL, flags);
/** \todo fixme: */
if ((flags == SP_STYLE_FLAG_ALWAYS)
{
if (style->stroke_dasharray_inherit) {
gint i;
if (i) {
os << ", ";
}
}
if (p < c + BMAX) {
*p++ = ';';
}
} else {
}
}
/** \todo fixme: */
if (style->stroke_dashoffset_set) {
if (style->stroke_dashoffset_inherit) {
} else {
}
} else if (flags == SP_STYLE_FLAG_ALWAYS) {
}
}
bool marker_none = false;
} else if (flags == SP_STYLE_FLAG_ALWAYS) {
marker_none = true;
}
}
}
}
p += sp_style_write_ienum(p, c + BMAX - p, "visibility", enum_visibility, &style->visibility, NULL, flags);
p += sp_style_write_ienum(p, c + BMAX - p, "overflow", enum_overflow, &style->overflow, NULL, flags);
/* filter: */
p += sp_style_write_ienum(p, c + BMAX - p, "enable-background", enum_enable_background, &style->enable_background, NULL, flags);
/* clipping */
p += sp_style_write_ienum(p, c + BMAX - p, "clip-rule", enum_clip_rule, &style->clip_rule, NULL, flags);
/* fixme: */
/* Get rid of trailing `;'. */
if (p != c) {
--p;
if (*p == ';') {
*p = '\0';
}
}
return g_strdup(c);
}
#define STYLE_BUF_MAX
/**
* Dumps style to CSS string, see sp_style_write_string()
*
* \pre from != NULL.
* \pre to != NULL.
* \post ret != NULL.
*/
gchar *
{
*p = '\0';
p += sp_style_write_ifontsize(p, c + BMAX - p, "font-size", &from->font_size, &to->font_size, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "font-style", enum_font_style, &from->font_style, &to->font_style, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "font-variant", enum_font_variant, &from->font_variant, &to->font_variant, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "font-weight", enum_font_weight, &from->font_weight, &to->font_weight, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "font-stretch", enum_font_stretch, &from->font_stretch, &to->font_stretch, SP_STYLE_FLAG_IFDIFF);
/* Text */
p += sp_style_write_ilength(p, c + BMAX - p, "text-indent", &from->text_indent, &to->text_indent, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "text-align", enum_text_align, &from->text_align, &to->text_align, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_itextdecoration(p, c + BMAX - p, "text-decoration", &from->text_decoration, &to->text_decoration, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ilengthornormal(p, c + BMAX - p, "line-height", &from->line_height, &to->line_height, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ilengthornormal(p, c + BMAX - p, "letter-spacing", &from->letter_spacing, &to->letter_spacing, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ilengthornormal(p, c + BMAX - p, "word-spacing", &from->word_spacing, &to->word_spacing, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "text-transform", enum_text_transform, &from->text_transform, &to->text_transform, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "direction", enum_direction, &from->direction, &to->direction, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "block-progression", enum_block_progression, &from->block_progression, &to->block_progression, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "writing-mode", enum_writing_mode, &from->writing_mode, &to->writing_mode, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "text-anchor", enum_text_anchor, &from->text_anchor, &to->text_anchor, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ibaselineshift(p, c + BMAX - p, "baseline-shift", &from->baseline_shift, &to->baseline_shift, SP_STYLE_FLAG_IFDIFF);
/// \todo fixme: Per type methods need default flag too
p += sp_style_write_iscale24(p, c + BMAX - p, "opacity", &from->opacity, &to->opacity, SP_STYLE_FLAG_IFSET);
}
p += sp_style_write_ipaint(p, c + BMAX - p, "color", &from->color, &to->color, SP_STYLE_FLAG_IFSET);
}
p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation", enum_color_interpolation, &from->color_interpolation, &to->color_interpolation, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "color-interpolation-filters", enum_color_interpolation, &from->color_interpolation_filters, &to->color_interpolation_filters, SP_STYLE_FLAG_IFDIFF);
// if fill:none, skip writing fill properties
p += sp_style_write_iscale24(p, c + BMAX - p, "fill-opacity", &from->fill_opacity, &to->fill_opacity, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "fill-rule", enum_fill_rule, &from->fill_rule, &to->fill_rule, SP_STYLE_FLAG_IFDIFF);
}
p += sp_style_write_ipaint(p, c + BMAX - p, "stroke", &from->stroke, &to->stroke, SP_STYLE_FLAG_IFDIFF);
// stroke width affects markers, so write it if there's stroke OR any markers
p += sp_style_write_ilength(p, c + BMAX - p, "stroke-width", &from->stroke_width, &to->stroke_width, SP_STYLE_FLAG_IFDIFF);
}
// if stroke:none, skip writing stroke properties
/** \todo fixme: */
if (from->stroke_dasharray_set) {
if (from->stroke_dasharray_inherit) {
if (i) {
os << ", ";
}
}
}
}
/* fixme: */
if (from->stroke_dashoffset_set) {
if (from->stroke_dashoffset_inherit) {
} else {
}
}
p += sp_style_write_iscale24(p, c + BMAX - p, "stroke-opacity", &from->stroke_opacity, &to->stroke_opacity, SP_STYLE_FLAG_IFDIFF);
}
/* markers */
}
if (from->marker[SP_MARKER_LOC_START].value != NULL && (!master || strcmp(master, from->marker[SP_MARKER_LOC_START].value))) {
}
if (from->marker[SP_MARKER_LOC_MID].value != NULL && (!master || strcmp(master, from->marker[SP_MARKER_LOC_MID].value))) {
}
if (from->marker[SP_MARKER_LOC_END].value != NULL && (!master || strcmp(master, from->marker[SP_MARKER_LOC_END].value))) {
}
p += sp_style_write_ienum(p, c + BMAX - p, "visibility", enum_visibility, &from->visibility, &to->visibility, SP_STYLE_FLAG_IFSET);
p += sp_style_write_ienum(p, c + BMAX - p, "display", enum_display, &from->display, &to->display, SP_STYLE_FLAG_IFSET);
p += sp_style_write_ienum(p, c + BMAX - p, "overflow", enum_overflow, &from->overflow, &to->overflow, SP_STYLE_FLAG_IFSET);
/* filter: */
p += sp_style_write_ifilter(p, c + BMAX - p, "filter", &from->filter, &to->filter, SP_STYLE_FLAG_IFDIFF);
p += sp_style_write_ienum(p, c + BMAX - p, "enable-background", enum_enable_background, &from->enable_background, &to->enable_background, SP_STYLE_FLAG_IFSET);
p += sp_style_write_ienum(p, c + BMAX - p, "clip-rule", enum_clip_rule, &from->clip_rule, &to->clip_rule, SP_STYLE_FLAG_IFDIFF);
/** \todo
* The reason we use IFSET rather than IFDIFF is the belief that the IFDIFF
* flag is mainly only for attributes that don't handle explicit unset well.
* We may need to revisit the behaviour of this routine.
*/
/* Get rid of trailing `;'. */
if (p != c) {
--p;
if (*p == ';') {
*p = '\0';
}
}
return g_strdup(c);
}
/**
* Reset all style properties.
*/
static void
{
}
}
}
}
/** \todo fixme: Do that text manipulation via parents */
if (document) {
style->filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
style->fill.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), style));
style->stroke.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), style));
}
/* text */
style->color_interpolation.value = style->color_interpolation.computed = SP_CSS_COLOR_INTERPOLATION_SRGB;
style->color_interpolation_filters.value = style->color_interpolation_filters.computed = SP_CSS_COLOR_INTERPOLATION_LINEARRGB;
for (unsigned i = SP_MARKER_LOC; i < SP_MARKER_LOC_QTY; i++) {
}
}
/**
*
*/
static void
{
/* Ref: http://www.w3.org/TR/SVG11/painting.html#StrokeDasharrayProperty */
style->stroke_dasharray_inherit = true;
return;
}
style->stroke_dasharray_inherit = false;
return;
}
gdouble d[64];
bool LineSolid=true;
/* TODO: Should allow <length> rather than just a unitless (px) number. */
if (d[n_dash] > 0.00000001)
LineSolid = false;
if (e != str) {
n_dash += 1;
str = e;
}
}
if (LineSolid) {
return;
}
if (n_dash > 0) {
}
}
/*#########################
## SPTextStyle operations
#########################*/
/**
* Return new SPTextStyle object with default settings.
*/
static SPTextStyle *
{
return ts;
}
/**
* Clear text style settings.
*/
static void
{
}
/**
* Reduce refcount of text style and possibly free it.
*/
static SPTextStyle *
{
}
return NULL;
}
/**
* Return duplicate of text style.
*/
static SPTextStyle *
{
return nt;
}
/**
* Write SPTextStyle object into string.
*/
static guint
{
gint d = 0;
// We do not do diffing for text style
if (flags == SP_STYLE_FLAG_IFDIFF)
d += sp_style_write_istring(p + d, len - d, "-inkscape-font-specification", &st->font_specification, NULL, flags);
return d;
}
/* The following sp_tyle_read_* functions ignore invalid values, as per
* http://www.w3.org/TR/REC-CSS2/syndata.html#parsing-errors.
*
* [However, the SVG spec is somewhat unclear as to whether the style attribute should
* be handled as per CSS2 rules or whether it must simply be a set of PROPERTY:VALUE
* pairs, in which case SVG's error-handling rules
* http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing should instead be applied.]
*/
/**
* Set SPIFloat object from string.
*/
static void
{
} else {
}
}
}
/**
* Set SPIScale24 object from string.
*/
static void
{
} else {
}
}
}
/**
* Reads a style value and performs lookup based on the given style value enumerations.
*/
static void
bool const can_explicitly_inherit)
{
} else {
/* Save copying for values not needing it */
break;
}
}
}
return;
}
/**
* Set SPIString object from string.
*/
static void
{
} else {
}
}
/**
* Set SPILength object from string.
*/
static void
{
} else {
gchar *e;
/** \todo fixme: Move this to standard place (Lauris) */
return;
}
/** \todo
* Allow the number of px per inch to vary (document preferences,
* X server or whatever). E.g. don't fill in computed here, do
* it at the same time as percentage units are done.
*/
if (!*e) {
/* Userspace */
} else if (!strcmp(e, "px")) {
/* Userspace */
} else if (!strcmp(e, "pt")) {
/* Userspace / DEVICESCALE */
} else if (!strcmp(e, "pc")) {
} else if (!strcmp(e, "mm")) {
} else if (!strcmp(e, "cm")) {
} else if (!strcmp(e, "in")) {
} else if (!strcmp(e, "em")) {
/* EM square */
} else if (!strcmp(e, "ex")) {
/* ex square */
} else if (!strcmp(e, "%")) {
/* Percentage */
} else {
/* Invalid */
return;
}
}
}
}
/**
* Set SPILengthOrNormal object from string.
*/
static void
{
} else {
}
}
/**
* Set SPITextDecoration object from string.
*/
static void
{
} else {
bool found_underline = false;
bool found_overline = false;
bool found_line_through = false;
bool found_blink = false;
if (*str == ' ') continue;
found_underline = true;
str += 9;
found_overline = true;
str += 8;
found_line_through = true;
str += 12;
found_blink = true;
str += 5;
} else {
return; // invalid value
}
}
return; // invalid value: empty
}
}
}
/**
* Set SPIPaint object from string containing an integer value.
* \param document Ignored
*/
static void
{
(void)style; // TODO
(void)document; // TODO
} else {
if (rgb0 != 0xff) {
}
}
}
/**
* Set SPIPaint object from string.
*
* \pre paint == \&style.fill || paint == \&style.stroke.
*/
{
while (g_ascii_isspace(*str)) {
++str;
}
clear();
} else {
while ( g_ascii_isspace(*str) ) {
++str;
}
// TODO check on and comment the comparrison "paint != &style->color".
// it may be that this style's SPIPaint has not yet created its URIReference;
// now that we have a document, we can create it here
value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun((this == &style.fill)? sp_style_fill_paint_server_ref_changed : sp_style_stroke_paint_server_ref_changed), &style));
}
// TODO check what this does in light of move away from union
}
}
currentcolor = TRUE;
} else {
if (rgb0 != 0xff) {
while (g_ascii_isspace(*str)) {
++str;
}
delete tmp;
tmp = 0;
}
}
}
}
}
}
/**
* Set SPIFontSize object from string.
*/
static void
{
// xx-small, x-small, etc.
for (unsigned i = 0; enum_font_size[i].key; i++) {
return;
}
}
/* Invalid */
return;
} else {
} else {
}
}
return;
}
}
/**
* Set SPIBaselineShift object from string.
*/
static void
{
// baseline or sub or super
for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
return;
}
}
/* Invalid */
return;
} else {
} else {
}
return;
}
}
/**
* Set SPIFilter object from string.
*/
static void
{
/* Try all possible values: inherit, none, uri */
if (f->href){
}
}
if (f->href){
}
}
g_warning("Specified filter url is empty");
return;
}
if (f->href){
}
}
// it may be that this style has not yet created its SPFilterReference;
// now that we have a document, we can create it here
}
try {
} catch (Inkscape::BadURIException &e) {
}
} else {
/* We shouldn't reach this if SVG input is well-formed */
if (f->href){
}
}
}
}
/**
* Set SPIEnum object from repr attribute.
*/
static void
bool const can_explicitly_inherit)
{
if (str) {
}
}
/**
* Set SPILength object from repr attribute.
*/
static void
{
if (str) {
}
}
/**
* Set SPIFontSize object from repr attribute.
*/
static void
{
if (str) {
}
}
/**
* Set SPIBaselineShift object from repr attribute.
*/
static void
{
if (str) {
}
}
/**
* Set SPIFloat object from repr attribute.
*/
static void
{
if (str) {
}
}
/**
* Write SPIFloat object into string.
*/
static gint
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
} else {
}
}
return 0;
}
/**
* Write SPIScale24 object into string.
*/
static gint
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
} else {
}
}
return 0;
}
/**
* Write SPIEnum object into string.
*/
static gint
SPStyleEnum const *const dict,
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
}
}
}
}
return 0;
}
/**
* Write SPIString object into string.
*/
static gint
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
} else {
if (val_quoted) {
g_free (val_quoted);
}
}
}
return 0;
}
/**
*
*/
static bool
{
if (a->unit == SP_CSS_UNIT_EM) return true;
if (a->unit == SP_CSS_UNIT_EX) return true;
if (a->unit == SP_CSS_UNIT_PERCENT) return true;
if (b->unit == SP_CSS_UNIT_EM) return true;
if (b->unit == SP_CSS_UNIT_EX) return true;
if (b->unit == SP_CSS_UNIT_PERCENT) return true;
}
}
/**
* Write SPILength object into string.
*/
static gint
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
} else {
case SP_CSS_UNIT_NONE:
break;
case SP_CSS_UNIT_PX:
break;
case SP_CSS_UNIT_PT:
break;
case SP_CSS_UNIT_PC:
break;
case SP_CSS_UNIT_MM:
break;
case SP_CSS_UNIT_CM:
break;
case SP_CSS_UNIT_IN:
break;
case SP_CSS_UNIT_EM:
break;
case SP_CSS_UNIT_EX:
break;
case SP_CSS_UNIT_PERCENT:
break;
default:
/* Invalid */
break;
}
}
}
return 0;
}
/**
*
*/
static bool
{
if (a->normal) return false;
if (a->unit == SP_CSS_UNIT_EM) return true;
if (a->unit == SP_CSS_UNIT_EX) return true;
if (a->unit == SP_CSS_UNIT_PERCENT) return true;
if (b->unit == SP_CSS_UNIT_EM) return true;
if (b->unit == SP_CSS_UNIT_EX) return true;
if (b->unit == SP_CSS_UNIT_PERCENT) return true;
}
}
/**
* Write SPILengthOrNormal object into string.
*/
static gint
SPILengthOrNormal const *const val,
SPILengthOrNormal const *const base,
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
} else {
}
}
return 0;
}
/**
*
*/
static bool
{
|| a->line_through != b->line_through
}
/**
* Write SPITextDecoration object into string.
*/
static gint
SPITextDecoration const *const val,
SPITextDecoration const *const base,
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
} else {
} else
os << "none";
os << ";";
}
}
return 0;
}
/**
*
*/
static bool
{
|| (a->isPaintserver() != b->isPaintserver())
|| (a->currentcolor != b->currentcolor)
return true;
}
// TODO refactor to allow for mixed paints (rgb() *and* url(), etc)
if ( a->isPaintserver() ) {
return (a->value.href == NULL || b->value.href == NULL || a->value.href->getObject() != b->value.href->getObject());
}
if ( a->isColor() ) {
/* todo: Allow for epsilon differences in iccColor->colors, e.g. changes small enough not to show up
* in the string representation. */
}
return false;
}
/**
* Write SPIPaint object into string.
*/
static gint
{
int retval = 0;
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
css << "inherit";
} else {
}
css << " ";
}
css << "none";
}
if ( paint->currentcolor ) {
css << " ";
}
css << "currentColor";
}
css << " ";
}
char color_buf[8];
}
css << " ";
}
i != iEnd; ++i) {
css << ", " << *i;
}
css << ')';
}
}
}
}
return retval;
}
/**
*
*/
static bool
{
return true;
if (a->type == SP_FONT_SIZE_LENGTH) {
return true;
} else {
return true;
}
return false;
}
/**
* Write SPIFontSize object into string.
*/
static gint
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
for (unsigned i = 0; enum_font_size[i].key; i++) {
}
}
}
os << key << ":" << sp_style_css_size_px_to_units(val->computed, unit) << sp_style_get_css_unit_string(unit) << ";";
}
}
return 0;
}
/*
* baseline-shift is relative to parent. The only time it should
* not be written out is if it is zero (or not set).
*/
static bool
sp_baseline_shift_notzero(SPIBaselineShift const *const a )
{
if( a->type == SP_BASELINE_SHIFT_LITERAL ) {
if( a->literal == SP_CSS_BASELINE_SHIFT_BASELINE ) {
return false;
}
} else {
if( a->value == 0.0 ) {
return false;
}
}
return true;
}
/**
* Write SPIBaselineShift object into string.
*/
static gint
{
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
for (unsigned i = 0; enum_baseline_shift[i].key; i++) {
}
}
} else {
os << key << ":" << val->computed << "px;"; // must specify px, see inkscape bug 1221626, mozilla bug 234789
}
}
}
return 0;
}
/**
* Write SPIFilter object into string.
*/
static gint
{
(void)base; // TODO
if ((flags & SP_STYLE_FLAG_ALWAYS)
{
}
}
return 0;
}
set(0),
inherit(0),
currentcolor(0),
colorSet(0),
noneSet(0),
value()
{
}
{
set = false;
inherit = false;
currentcolor = false;
colorSet = false;
noneSet = false;
}
}
}
/**
* Clear filter object, and disconnect style from paintserver (if present).
*/
static void
{
}
}
}
// FIXME: Everything below this line belongs in a different file - css-chemistry?
void
{
if (linked) {
} else {
}
if (recursive) {
} else {
}
}
/**
* Clear all style property attributes in object.
*/
void
{
if (!o) {
return;
}
if (!style) {
return;
}
if (!repr) {
return;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
if (style->stroke_dasharray_set) {
}
if (style->stroke_dashoffset_set) {
}
}
}
}
}
}
}
}
}
/**
* \pre style != NULL.
* \pre flags in {IFSET, ALWAYS}.
*/
{
(flags == SP_STYLE_FLAG_ALWAYS) ),
NULL);
return css;
}
/**
* \pre object != NULL
* \pre flags in {IFSET, ALWAYS}.
*/
{
(flags == SP_STYLE_FLAG_ALWAYS) ),
NULL);
}
return result;
}
/**
* Unset any text-related properties
*/
{
return css;
}
bool
is_url(char const *p)
{
if (p == NULL)
return false;
/** \todo
* FIXME: I'm not sure if this applies to SVG as well, but CSS2 says any URIs
* in property values must start with 'url('.
*/
}
/**
* Unset any properties that contain URI values.
*
* Used for storing style that will be reused across documents when carrying
* the referenced defs is impractical.
*/
{
// All properties that may hold <uri> or <paint> according to SVG 1.1
if (is_url(sp_repr_css_property(css, "clip-path", NULL))) sp_repr_css_set_property(css, "clip-path", NULL);
if (is_url(sp_repr_css_property(css, "color-profile", NULL))) sp_repr_css_set_property(css, "color-profile", NULL);
if (is_url(sp_repr_css_property(css, "cursor", NULL))) sp_repr_css_set_property(css, "cursor", NULL);
if (is_url(sp_repr_css_property(css, "filter", NULL))) sp_repr_css_set_property(css, "filter", NULL);
if (is_url(sp_repr_css_property(css, "marker", NULL))) sp_repr_css_set_property(css, "marker", NULL);
if (is_url(sp_repr_css_property(css, "marker-start", NULL))) sp_repr_css_set_property(css, "marker-start", NULL);
if (is_url(sp_repr_css_property(css, "marker-mid", NULL))) sp_repr_css_set_property(css, "marker-mid", NULL);
if (is_url(sp_repr_css_property(css, "marker-end", NULL))) sp_repr_css_set_property(css, "marker-end", NULL);
if (is_url(sp_repr_css_property(css, "stroke", NULL))) sp_repr_css_set_property(css, "stroke", NULL);
return css;
}
/**
* Scale a single-value property.
*/
void
double ex, bool only_with_units = false)
{
if (w) {
if (w == units) {// nothing converted, non-numeric value
return;
}
// only_with_units, but no units found, so do nothing.
return;
}
}
}
/**
* Scale a list-of-values property.
*/
void
{
if (string) {
bool first = true;
gchar *w = *i;
if (w == NULL)
break;
if (w == units) {// nothing converted, non-numeric value ("none" or "inherit"); do nothing
g_strfreev(a);
return;
}
if (!first) {
os << ",";
}
first = false;
}
g_strfreev(a);
}
}
/**
* Scale any properties that may hold <length> by ex.
*/
{
return css;
}
/**
* Remove quotes and escapes from a string. Returned value must be g_free'd.
* Note: in CSS (in style= and in stylesheets), unquoting and unescaping is done
* by libcroco, our CSS parser, though it adds a new pair of "" quotes for the strings
* it parsed for us. So this function is only used to remove those quotes and for
* presentation attributes, without any unescaping. (XML unescaping
* (& etc) is done by XML parser.)
*/
gchar *
{
if (val) {
if (l >= 2) {
}
}
}
}
}
/**
*/
gchar *
bool quote = false;
bool last_was_space = false;
bool is_space = ( *i == ' ' );
// ASCII alphanumeric, - and _ don't require quotes
t.push_back(*i);
} else if ( is_space && !last_was_space ) {
// non-consecutive spaces don't require quotes
t.push_back(*i);
} else if (*i=='\'') {
// single quotes require escaping and quotes
t.push_back('\\');
t.push_back(*i);
quote = true;
} else {
// everything else requires quotes
t.push_back(*i);
quote = true;
}
if (i == val && !g_ascii_isalpha(*i)) {
quote = true;
}
}
if (last_was_space) {
// a trailing space requires quotes
quote = true;
}
if (quote) {
// we use single quotes so the result can be stored in an XML
// attribute without incurring un-aesthetic additional quoting
// (our XML emitter always uses double quotes)
t.push_back('\'');
}
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :