Difference between revisions of "CSS Support"

From Inkscape Wiki
Jump to navigation Jump to search
m (Retitled for readability)
 
(4 intermediate revisions by one other user not shown)
Line 1: Line 1:
=== Current State ===


An initial implementation is now in SVN.  Limitations:
Updated August 2017


* Allows a single <style> element in the document.  Doesn't allow external stylesheets, doesn't allow more than one <style> element.
== Current State ==
: (Or rather it ignores all but one of the <style> elements, possibly changing which one it respects based on which was most recently re-read.)


* No editing interface other than the XML editor.
Inkscape supports a single <tt>&lt;style&gt;</tt> element in the document. If there is more than one style element, Inkscape will pick one to use.


: There are a number of aspects of editing:
@import is supported as of 0.93 (read-only). other @-rules are not supported.


** The most basic level: allow editing using the XML editor(See Update section below.)
There is a simple style editor (Object -> Style dialog). Selectors can be added/deleted.
** Editing a stylesheet.
** Specifying what classes each object belongs to.


* Doesn't respect media restrictions (e.g. ignores "this rule applies only to non-visual media" directives, and doesn't allow having one    style for print and another style for on-screen).


* <tt>@font-face</tt> hints are ignored.
== Work Needed (incomplete list) ==


* Doesn't handle any other at-rules (<tt>@media</tt>, <tt>@import</tt>, <tt>@page</tt>, …).
* As of 0.93, libcroco supports multiple style sheets in a document. Inkscape needs to change how style sheet are handled to make use of this. Currently style sheet handling is tied to style elements. This needs to be changed so that style sheet handling is tied to the document so that all style sheets are evaluated at the same time.


==== Work Needed (incomplete list): ====
* Convert the simple user agent stylesheet given at http://www.w3.org/TR/SVG11/styling.html#UAStyleSheet to <tt>libcroco</tt> structures (perhaps by passing strings to <tt>libcroco</tt> parsing functions) and store in <tt>desktop-&gt;style_cascade</tt>.


* Ensure that this single stylesheet is updated whenever any of the <tt>&lt;style&gt;</tt> elements change (or are deleted or created etc.).
* Check that all "shorthand properties" are supported.


* Similarly, ensure that the picture is refreshed when the stylesheet is changed.
* Improve the usability of the Style dialog so that properties can be moved back and forth between style attributes and style elements.


* Convert the simple user agent style sheet given at http://www.w3.org/TR/SVG11/styling.html#UAStyleSheet to libcroco structures (perhaps by passing strings to libcroco parsing functions) and store in <tt>desktop-&gt;style_cascade</tt>.
== THE REST IS OUT-OF-DATE ==


* Modify style.cpp to query the stylesheet.  (Done but not checked in.)
==== Updating for changes to <tt>&lt;style&gt;</tt> content ====


* There may be some work needed for "shorthand properties", e.g. `<tt>marker</tt>' is shorthand for modifying <tt>marker-start</tt>, <tt>marker-mid</tt> and <tt>marker-end</tt> properties (http://www.w3.org/TR/SVG11/painting.html#MarkerProperty).  A non-SVG CSS example is `<tt>margin</tt>'.
'''State so far:''' Every keystroke in the XML Editor in the content of the <tt>&lt;style&gt;</tt> element gets <tt>sp_style_elem_read_content</tt> to be re-read.
One can force an object to get the revised stylesheet info…e.g., by &lt;Up&gt; &lt;Down&gt; (forcing an update) then deleting its <tt>style</tt> attribute.


==== Updating for changes to &lt;style&gt; content ====
So, one change is that we shouldn't be so keen to put things in the <tt>style</tt> attribute.
Currently, the stylesheet info gets merged into <tt>SPStyle</tt>, and set the <tt>style</tt> attribute to contain everything in <tt>SPStyle</tt> (and clear any styling attributes like <tt>fill=...</tt>).
One existing problem with this behaviour (other than how it interacts with stylesheets) is that we discard any <tt>style</tt> properties we don't know about. 


State so far: Every keystroke in the xml editor in the content of the &lt;style&gt; element gets sp_style_elem_read_content to be re-read.
Instead we should remember the content of the style attribute and only replace the properties we've changed, adding only as necessary.
One can force an object to get the revised stylesheet info by e.g. &lt;Up&gt; &lt;Down&gt; (forcing an update) then deleting its style attribute.
So one change is that we shouldn't be so keen to put things in the <tt>style</tt> attribute.
Currently, the stylesheet info gets merged into <tt>SPStyle</tt>, and set the <tt>style</tt> attribute to contain everything in <tt>SPStyle</tt> (and clear any styling attributes like <tt>fill=...</tt>).
One existing problem with this behaviour (other than how it interacts with stylesheets) is that we discard any <tt>style</tt> properties we don't know about.  Whereas we ought to remember the content of the style attribute and only replace the properties we've changed, and add to if necessary.


One implementation would be to keep <tt>SPStyle</tt> but indicate which properties came from where, and hence which ones need to be written to the style attribute and which ones don't.
One implementation would be to keep <tt>SPStyle</tt> but indicate which properties came from where, and hence which ones need to be written to the style attribute and which ones don't.
Line 44: Line 38:
Not to say that we can't choose to use the <tt>style</tt> attribute for properties that the user changes during an inkscape session, but currently we change from attributes to <tt>style=</tt>... even for shapes that the user just changes the position of without changing any styling stuff.
Not to say that we can't choose to use the <tt>style</tt> attribute for properties that the user changes during an inkscape session, but currently we change from attributes to <tt>style=</tt>... even for shapes that the user just changes the position of without changing any styling stuff.


=== Why can't we use libcroco-0.6's existing libxml interface to cr-sel-eng.c ? ===
=== Why can't we use <tt>libcroco-0.6</tt>'s existing <tt>libxml</tt> interface to <tt>cr-sel-eng.c</tt> ? ===


Some CSS selectors (http://www.w3.org/TR/REC-CSS2/selector.html) can express "is preceded by X" or "is a descendent of X" (where X can itself be similarly constrained recursively), so we'd pretty much need to maintain the entire document in libxml form if we want to use libcroco for CSS selectors.
Some CSS selectors (http://www.w3.org/TR/REC-CSS2/selector.html) can express "is preceded by X" or "is a descendent of X" (where X can itself be similarly constrained recursively), so we'd pretty much need to maintain the entire document in <tt>libxml</tt> form if we want to use <tt>libcroco</tt> for CSS selectors.


Suppose we want to find the style of node N.  We pass libcroco a stylesheet and ask it what rules apply to N.
Suppose we want to find the style of node N.  We pass <tt>libcroco</tt> a stylesheet and ask it what rules apply to N.
If the stylesheet says "nodes that are preceded by a node that is preceded by a node that's a descendent of (... etc. ...) have red stroking" then libcroco needs to be able to navigate through the tree.
If the stylesheet says "nodes that are preceded by a node that is preceded by a node that's a descendent of (... etc. ...) have red stroking" then <tt>libcroco</tt> needs to be able to navigate through the tree.
So we can't pass libcroco just a libxml version of node N, we need to fill in its parent and sibling links, providing a libxml node for a significant proportion of all nodes in the tree.
So we can't pass <tt>libcroco</tt> just a <tt>libxml</tt> version of node N, we need to fill in its parent and sibling links, providing a <tt>libxml</tt> node for a significant proportion of all nodes in the tree.
(Short of using hardware watchpoints to check access to the sibling/parent links and supply them lazily.)
(Short of using hardware watchpoints to check access to the sibling/parent links and supply them lazily.)


=== Notes on how to implement external stylesheets ===
=== Implementing External Stylesheets… ===


External stylesheets are arguably easier to implement than internal ones: the reference to the stylesheet comes right at the beginning of the xml file before even the top-level &lt;svg&gt; element, so we already know all the styling stuff for &lt;svg&gt; as soon as we reach it.  Editing may also be a bit easier, in that external stylesheets usually exist for sharing the same style among many documents, so there's less expectation of being able to edit the stylesheet itself.
External stylesheets are arguably easier to implement than internal ones: the reference to the stylesheet comes right at the beginning of the xml file before even the top-level <tt>&lt;svg&gt;</tt> element, so we already know all the styling stuff for <tt>&lt;svg&gt;</tt> as soon as we reach it.  Editing may also be a bit easier, in that external stylesheets usually exist for sharing styles across many documents, so there's less expectation of being able to edit the stylesheet itself.


The work of actually parsing the stylesheet once it's in memory is already done: see src/sp-style-elem.cpp:sp_style_elem_read_content.
The work of actually parsing the stylesheet once it's in memory is already done: see <tt>src/sp-style-elem.cpp:sp_style_elem_read_content</tt>.


So for read-only support of a single external stylesheet, it may well be just a matter of looking at how we can get XML processing instructions from libxml2 (please add a reference to the relevant documentation or code here once you've looked it up, anyone), and parse the pseudo-xml-attributes (see http://www.w3.org/TR/xml-stylesheet/; note that these aren't real xml attributes that libxml2 handles, so we do the parsing ourselves — or pass the string to a separate libxml2 instance/session/parser).
So for read-only support of a single external stylesheet, it may well be just a matter of looking at how we can get XML processing instructions from libxml2 (please add a reference to the relevant documentation or code here once you've looked it up, anyone), and parse the pseudo-xml-attributes (see http://www.w3.org/TR/xml-stylesheet/; note that these aren't real xml attributes that libxml2 handles, so we do the parsing ourselves — or pass the string to a separate libxml2 instance/session/parser).


Then get the CSS from the specified URI (presumably using the same gnome vfs stuff that we currently use for accepting URIs on the commandline, though we could use libcurl instead: man curl, and see the --libcurl option for producing example code!).
Then get the CSS from the specified URI (presumably using the same gnome vfs stuff that we currently use for accepting URIs from the command line…though we could use libcurl instead: man curl, and see the <tt>--libcurl</tt> option for producing example code).


Then proceed as sp-style-elem.cpp:sp_style_elem_read_content does (presumably splitting off most of that function into a new function that takes the string as argument).
Then proceed as <tt>sp-style-elem.cpp:sp_style_elem_read_content</tt> does (presumably splitting off most of that function into a new function that takes the string as argument).


==== Multiple stylesheets ====
==== Multiple stylesheets ====


Initially, we would support only a single stylesheet, as libcroco currently doesn't support multiple stylesheets.
Initially, we would support only a single stylesheet, as <tt>libcroco</tt> currently doesn't support multiple stylesheets.


If you don't want to change libcroco, then it suffices to concatenate all the stylesheets together; the only thing you lose with that approach is that any parsing errors won't have the right line number, but I believe it gives completely correct results in absence of errors in any of the stylesheets.
If you don't want to change libcroco, then it suffices to concatenate all the stylesheets together; the only thing you lose with that approach is that any parsing errors won't have the right line number, but I believe it gives completely correct results in absence of errors in any of the stylesheets.

Latest revision as of 12:28, 11 August 2017

Updated August 2017

Current State

Inkscape supports a single <style> element in the document. If there is more than one style element, Inkscape will pick one to use.

@import is supported as of 0.93 (read-only). other @-rules are not supported.

There is a simple style editor (Object -> Style dialog). Selectors can be added/deleted.


Work Needed (incomplete list)

  • As of 0.93, libcroco supports multiple style sheets in a document. Inkscape needs to change how style sheet are handled to make use of this. Currently style sheet handling is tied to style elements. This needs to be changed so that style sheet handling is tied to the document so that all style sheets are evaluated at the same time.
  • Check that all "shorthand properties" are supported.
  • Improve the usability of the Style dialog so that properties can be moved back and forth between style attributes and style elements.

THE REST IS OUT-OF-DATE

Updating for changes to <style> content

State so far: Every keystroke in the XML Editor in the content of the <style> element gets sp_style_elem_read_content to be re-read. One can force an object to get the revised stylesheet info…e.g., by <Up> <Down> (forcing an update) then deleting its style attribute.

So, one change is that we shouldn't be so keen to put things in the style attribute. Currently, the stylesheet info gets merged into SPStyle, and set the style attribute to contain everything in SPStyle (and clear any styling attributes like fill=...). One existing problem with this behaviour (other than how it interacts with stylesheets) is that we discard any style properties we don't know about.

Instead we should remember the content of the style attribute and only replace the properties we've changed, adding only as necessary.

One implementation would be to keep SPStyle but indicate which properties came from where, and hence which ones need to be written to the style attribute and which ones don't. Apart from not writing if src==stylesheet, we can also avoid writing if src==attribute: i.e. don't gratuitously break SVG Tiny conformance of a document (or more generally break compatibility with implementations that don't honour CSS style attributes). Not to say that we can't choose to use the style attribute for properties that the user changes during an inkscape session, but currently we change from attributes to style=... even for shapes that the user just changes the position of without changing any styling stuff.

Why can't we use libcroco-0.6's existing libxml interface to cr-sel-eng.c ?

Some CSS selectors (http://www.w3.org/TR/REC-CSS2/selector.html) can express "is preceded by X" or "is a descendent of X" (where X can itself be similarly constrained recursively), so we'd pretty much need to maintain the entire document in libxml form if we want to use libcroco for CSS selectors.

Suppose we want to find the style of node N. We pass libcroco a stylesheet and ask it what rules apply to N. If the stylesheet says "nodes that are preceded by a node that is preceded by a node that's a descendent of (... etc. ...) have red stroking" then libcroco needs to be able to navigate through the tree. So we can't pass libcroco just a libxml version of node N, we need to fill in its parent and sibling links, providing a libxml node for a significant proportion of all nodes in the tree. (Short of using hardware watchpoints to check access to the sibling/parent links and supply them lazily.)

Implementing External Stylesheets…

External stylesheets are arguably easier to implement than internal ones: the reference to the stylesheet comes right at the beginning of the xml file before even the top-level <svg> element, so we already know all the styling stuff for <svg> as soon as we reach it. Editing may also be a bit easier, in that external stylesheets usually exist for sharing styles across many documents, so there's less expectation of being able to edit the stylesheet itself.

The work of actually parsing the stylesheet once it's in memory is already done: see src/sp-style-elem.cpp:sp_style_elem_read_content.

So for read-only support of a single external stylesheet, it may well be just a matter of looking at how we can get XML processing instructions from libxml2 (please add a reference to the relevant documentation or code here once you've looked it up, anyone), and parse the pseudo-xml-attributes (see http://www.w3.org/TR/xml-stylesheet/; note that these aren't real xml attributes that libxml2 handles, so we do the parsing ourselves — or pass the string to a separate libxml2 instance/session/parser).

Then get the CSS from the specified URI (presumably using the same gnome vfs stuff that we currently use for accepting URIs from the command line…though we could use libcurl instead: man curl, and see the --libcurl option for producing example code).

Then proceed as sp-style-elem.cpp:sp_style_elem_read_content does (presumably splitting off most of that function into a new function that takes the string as argument).

Multiple stylesheets

Initially, we would support only a single stylesheet, as libcroco currently doesn't support multiple stylesheets.

If you don't want to change libcroco, then it suffices to concatenate all the stylesheets together; the only thing you lose with that approach is that any parsing errors won't have the right line number, but I believe it gives completely correct results in absence of errors in any of the stylesheets.

The xml-stylesheet spec says that multiple external stylesheets interact the same way as in HTML; the relevant part of the HTML spec is http://www.w3.org/TR/html4/present/styles.html#h-14.3.