summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitlab-ci.yml31
-rw-r--r--ARCHITECTURE.md114
-rw-r--r--COMPILING.md130
-rw-r--r--CONTRIBUTING.md97
-rw-r--r--Makefile.am72
-rw-r--r--NEWS36
-rw-r--r--README.md149
-rw-r--r--configure.ac11
-rw-r--r--doc/Makefile.am43
-rw-r--r--doc/rsvg-sections.txt2
-rw-r--r--doc/rsvg.types3
-rw-r--r--librsvg.doap3
-rw-r--r--rsvg-base-file-util.c16
-rw-r--r--rsvg-base.c887
-rw-r--r--rsvg-cairo-clip.c10
-rw-r--r--rsvg-cairo-draw.c68
-rw-r--r--rsvg-cairo-draw.h2
-rw-r--r--rsvg-cairo-render.c2
-rw-r--r--rsvg-convert.c9
-rw-r--r--rsvg-css.h27
-rw-r--r--rsvg-defs.c54
-rw-r--r--rsvg-filter.c11
-rw-r--r--rsvg-gobject.c484
-rw-r--r--rsvg-handle.c1135
-rw-r--r--rsvg-io.c65
-rw-r--r--rsvg-io.h4
-rw-r--r--rsvg-mask.c123
-rw-r--r--rsvg-mask.h40
-rw-r--r--rsvg-private.h36
-rw-r--r--rsvg-styles.c94
-rw-r--r--rsvg-styles.h51
-rw-r--r--rsvg-text.c473
-rw-r--r--rsvg-text.h2
-rw-r--r--rsvg.c5
-rw-r--r--rsvg.h15
-rw-r--r--rust/Cargo.lock124
-rw-r--r--rust/Cargo.toml14
-rw-r--r--rust/src/aspect_ratio.rs147
-rw-r--r--rust/src/bbox.rs52
-rw-r--r--rust/src/chars.rs118
-rw-r--r--rust/src/clip_path.rs59
-rw-r--r--rust/src/color.rs16
-rw-r--r--rust/src/coord_units.rs93
-rw-r--r--rust/src/drawing_ctx.rs47
-rw-r--r--rust/src/error.rs4
-rw-r--r--rust/src/gradient.rs61
-rw-r--r--rust/src/image.rs15
-rw-r--r--rust/src/length.rs171
-rw-r--r--rust/src/lib.rs51
-rw-r--r--rust/src/marker.rs56
-rw-r--r--rust/src/mask.rs172
-rw-r--r--rust/src/node.rs44
-rw-r--r--rust/src/opacity.rs6
-rw-r--r--rust/src/paint_server.rs40
-rw-r--r--rust/src/parsers.rs14
-rw-r--r--rust/src/path_builder.rs20
-rw-r--r--rust/src/path_parser.rs123
-rw-r--r--rust/src/pattern.rs63
-rw-r--r--rust/src/property_bag.rs2
-rw-r--r--rust/src/shapes.rs4
-rw-r--r--rust/src/space.rs103
-rw-r--r--rust/src/state.rs108
-rw-r--r--rust/src/stop.rs8
-rw-r--r--rust/src/structure.rs21
-rw-r--r--rust/src/text.rs102
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/README.md174
-rw-r--r--tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype-ref.pngbin0 -> 184 bytes
-rw-r--r--tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype.svg7
-rw-r--r--tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg-ref.pngbin0 -> 1214 bytes
-rw-r--r--tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg.svg3
-rw-r--r--tests/fixtures/reftests/bugs/340047-ref.pngbin4779 -> 4752 bytes
-rw-r--r--tests/fixtures/reftests/bugs/587721-text-transform-ref.pngbin3910 -> 3898 bytes
-rw-r--r--tests/fixtures/reftests/bugs/749415-ref.pngbin21862 -> 20607 bytes
-rw-r--r--tests/fixtures/reftests/bugs/760180-ref.pngbin0 -> 8715 bytes
-rw-r--r--tests/fixtures/reftests/bugs/760180.svg159
-rw-r--r--tests/fixtures/reftests/bugs/761175-recursive-masks-ref.pngbin0 -> 513 bytes
-rw-r--r--tests/fixtures/reftests/bugs/761175-recursive-masks.svg50
-rw-r--r--tests/fixtures/reftests/bugs/776297-marker-on-non-path-elements-ref.pngbin1203 -> 1205 bytes
-rw-r--r--tests/fixtures/reftests/bugs/777834-empty-text-children-ref.pngbin9386 -> 8477 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-01-b-ref.pngbin11819 -> 11820 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-02-t-ref.pngbin8286 -> 8110 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-03-t-ref.pngbin7889 -> 7743 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-04-t-ref.pngbin6654 -> 6589 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-05-t-ref.pngbin8105 -> 7854 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-06-t-ref.pngbin8493 -> 8249 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-07-t-ref.pngbin11482 -> 11131 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-08-t-ref.pngbin13265 -> 13223 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-trans-09-t-ref.pngbin17268 -> 17163 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-viewattr-01-b-ref.pngbin16515 -> 16264 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-viewattr-02-b-ref.pngbin37569 -> 37198 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/coords-viewattr-03-b-ref.pngbin24302 -> 24225 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/filters-color-02-b-ref.pngbin6231 -> 6047 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/filters-composite-02-b-ref.pngbin16613 -> 15874 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-intro-01-f-ref.pngbin14528 -> 14172 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-mask-01-b-ref.pngbin17887 -> 17856 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-mask-02-f-ref.pngbin4512 -> 4347 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-opacity-01-b-ref.pngbin30924 -> 29991 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-path-01-b-ref.pngbin12226 -> 11354 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-path-02-b-ref.pngbin13294 -> 12489 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-path-03-b-ref.pngbin23263 -> 21313 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-path-04-b-ref.pngbin92911 -> 91469 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-path-05-f-ref.pngbin0 -> 7090 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/masking-path-05-f.svg78
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-01-f-ref.pngbin8454 -> 8597 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-02-f-ref.pngbin9172 -> 9185 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-03-f-ref.pngbin29006 -> 28073 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-04-f-ref.pngbin27598 -> 26712 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-06-f-ref.pngbin8640 -> 8715 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-07-f-ref.pngbin5158 -> 4989 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/painting-marker-properties-01-f-ref.pngbin6175 -> 6113 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-01-t-ref.pngbin25436 -> 25402 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-02-t-ref.pngbin32917 -> 32826 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-03-f-ref.pngbin30956 -> 30706 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-04-t-ref.pngbin18138 -> 17850 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-05-t-ref.pngbin16037 -> 15891 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-06-t-ref.pngbin7242 -> 7189 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-07-t-ref.pngbin6628 -> 6443 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-08-t-ref.pngbin19317 -> 18892 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-09-t-ref.pngbin17595 -> 17272 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-10-t-ref.pngbin20995 -> 20604 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-12-t-ref.pngbin9704 -> 9595 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-13-t-ref.pngbin4526 -> 4395 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-14-t-ref.pngbin12525 -> 12377 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-15-t-ref.pngbin6001 -> 5852 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-16-t-ref.pngbin7879 -> 7644 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-17-f-ref.pngbin4464 -> 4283 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-18-f-ref.pngbin4781 -> 4633 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-19-f-ref.pngbin23515 -> 23394 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/paths-data-20-f-ref.pngbin9144 -> 8991 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-01-b-ref.pngbin9758 -> 9202 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-02-b-ref.pngbin22622 -> 21995 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-03-b-ref.pngbin9805 -> 9495 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-04-b-ref.pngbin24018 -> 23330 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-05-b-ref.pngbin65037 -> 63416 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-06-b-ref.pngbin21260 -> 20571 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-07-b-ref.pngbin11051 -> 10623 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-08-b-ref.pngbin38874 -> 37161 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-09-b-ref.pngbin6207 -> 5874 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-10-b-ref.pngbin9229 -> 8918 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-11-b-ref.pngbin56357 -> 54921 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-12-b-ref.pngbin23747 -> 23251 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-13-b-ref.pngbin93434 -> 93210 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-14-b-ref.pngbin24537 -> 24407 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-15-b-ref.pngbin10180 -> 10014 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-16-b-ref.pngbin4738 -> 4608 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-18-b-ref.pngbin4733 -> 4603 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-21-b-ref.pngbin11549 -> 11374 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-22-b-ref.pngbin7605 -> 7414 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-23-f-ref.pngbin6129 -> 6131 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-24-f-ref.pngbin7313 -> 7251 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-grad-stops-01-f-ref.pngbin6356 -> 6353 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-01-b-ref.pngbin20788 -> 19967 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-02-f-ref.pngbin35135 -> 34951 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-03-f-ref.pngbin6074 -> 6079 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-04-f-ref.pngbin6160 -> 5998 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-05-f-ref.pngbin7148 -> 7154 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-06-f-ref.pngbin6103 -> 6043 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-07-f-ref.pngbin7651 -> 7606 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-08-f-ref.pngbin7654 -> 7609 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/pservers-pattern-09-f-ref.pngbin5840 -> 5846 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-cond-01-t-ref.pngbin4498 -> 4367 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-cond-03-t-ref.pngbin4433 -> 4244 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-svg-03-f-ref.pngbin5890 -> 5892 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-symbol-01-b-ref.pngbin52263 -> 52108 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-use-01-t-ref.pngbin15253 -> 14391 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-use-03-t-ref.pngbin7785 -> 7627 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-use-04-b-ref.pngbin19927 -> 19669 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/struct-use-09-b-ref.pngbin6556 -> 6586 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/text-align-01-b-ref.pngbin0 -> 17897 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/text-align-01-b.svg80
-rw-r--r--tests/fixtures/reftests/svg1.1/text-align-03-b-ref.pngbin0 -> 14668 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/text-align-03-b.svg82
-rw-r--r--tests/fixtures/reftests/svg1.1/text-text-03-b-ref.pngbin0 -> 19989 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/text-text-03-b.svg94
-rw-r--r--tests/fixtures/reftests/svg1.1/text-text-08-b-ref.pngbin0 -> 40082 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/text-text-08-b.svg64
-rw-r--r--tests/fixtures/reftests/svg1.1/text-text-10-t-ref.pngbin0 -> 45339 bytes
-rw-r--r--tests/fixtures/reftests/svg1.1/text-text-10-t.svg76
-rw-r--r--tests/resources/LiberationSans-Regular.ttfbin139764 -> 0 bytes
-rw-r--r--tests/resources/Roboto-Bold.ttfbin0 -> 353376 bytes
-rw-r--r--tests/resources/Roboto-BoldItalic.ttfbin0 -> 380912 bytes
-rw-r--r--tests/resources/Roboto-Italic.ttfbin0 -> 379588 bytes
-rw-r--r--tests/resources/Roboto-Regular.ttfbin0 -> 353888 bytes
-rw-r--r--tests/styles.c1
-rw-r--r--win32/rsvg-rust.mak4
-rw-r--r--win32/vs12/rsvg-build-defines.props5
-rw-r--r--win32/vs12/rsvg-rust.vcxproj8
189 files changed, 4401 insertions, 2650 deletions
diff --git a/.gitignore b/.gitignore
index 3402c62a..6a792548 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+*~
Makefile
Makefile.in
aclocal.m4
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 00000000..b950388b
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,31 @@
+# -*- indent-tabs-mode: nil -*-
+
+image: opensuse:tumbleweed
+
+stages:
+ - test
+
+before_script:
+ - zypper install -y gcc rust rust-std cargo make
+ automake autoconf libtool gettext itstool
+ gtk-doc
+ git
+ gobject-introspection-devel
+ libxml2-devel
+ libcroco-devel
+ cairo-devel
+ pango-devel
+ gdk-pixbuf-devel
+ gtk3-devel
+
+test:
+ stage: test
+ script:
+ - ./autogen.sh --enable-debug
+ - make check
+
+ artifacts:
+ when: on_failure
+ paths:
+ - /tmp/*.png
+ - tests/*.log
diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
new file mode 100644
index 00000000..720ef069
--- /dev/null
+++ b/ARCHITECTURE.md
@@ -0,0 +1,114 @@
+Architecture of librsvg
+=======================
+
+This document describes the architecture of librsvg, and future plans
+for it.
+
+# A bit of history
+
+Librsvg is an old library. It started around 2001, when Eazel (the
+original makers of GNOME's file manager Nautilus) needed a library to
+render SVG images. At that time the SVG format was being
+standardized, so librsvg grew along with the SVG specification. This
+is why you will sometimes see references to deprecated SVG features in
+the source code.
+
+Librsvg started as an experiment to use libxml2's new SAX parser, so
+that SVG could be streamed in, instead of first creating a DOM.
+Originally it used libart as a rendering library; this was GNOME's
+first antialiased renderer with alpha compositing. Later, the
+renderer was replaced with Cairo.
+
+Librsvg started as a C library with an ad-hoc API. At some point it
+got turned into a GObject library, so that the main `RsvgHandle`
+object defines most of the entry points into the library. Through
+GObject Introspection, this allows librsvg to be used from other
+programming languages.
+
+In 2016, librsvg started getting ported to Rust. The plan is to leave
+the C API/ABI intact, but to have as much of the internals as possible
+implemented in Rust. This way we can use a memory-safe, modern
+language, but retain the traditional API/ABI.
+
+# RsvgHandle
+
+The `RsvgHandle` object is the only GObject that librsvg exposes in
+the public API.
+
+During its lifetime, an `RsvgHandle` can be in either of two stages:
+
+* Loading - the caller feeds the handle with SVG data. The SVG XML is
+ parsed into a DOM-like structure.
+
+* Rendering - the SVG is finished loading. The caller can then render
+ the image as many times as it wants to Cairo contexts.
+
+## Loading SVG data
+
+The following happens in `rsvg_handle_read_stream_sync()`:
+
+* The function peeks the first bytes of the stream to see if it is
+ compressed with gzip. In that case, it plugs a
+ `g_zlib_decompressor_new()` to the use-supplied stream.
+
+* The function creates an XML parser for the stream. The SAX parser's
+ callbacks are functions that create DOM-like objects within the
+ `RsvgHandle`. The most important callback is
+ `rsvg_start_element()`, and the one that actually creates our
+ element implementations is `rsvg_standard_element_start()`.
+
+## Translating SVG data into Nodes
+
+`RsvgHandlePrivate` has a `treebase` field, which is the root of the
+DOM tree. Each node in the tree is an `RsvgNode` object.
+
+`rsvg_standard_element_start()` gets called from the XML parsing
+machinery; it takes an SVG element name like "`rect`" or "`filter`"
+and a key/value list of attributes within the element. It then creates the
+appropriate subclass of an `RsvgNode` object, hooks the node to the
+DOM tree, and tells the node to set its attributes from the key/value
+pairs.
+
+While a node sets its key/value pairs in its `set_atts()` method, it
+may encounter an invalid value, for example, a negative width where
+only nonnegative ones are allowed. In this case the element may
+decide to set itself to be "in error" via the `node.set_error()`
+method. If a node is in error, the node's children will get parsed as
+usual, but the node and its children will be ignored during the
+rendering stage.
+
+The SVG spec says that SVG rendering should stop on the first element
+that is "in error". However, most implementations simply seem to
+ignore erroneous elements instead of completely stopping rendering,
+and we do the same in librsvg.
+
+## Element attributes and specified/computed values
+
+Some HTML or SVG engines like Gecko / Servo make a very clear
+distinction between "specified values" and "computed values" for
+element attributes. Currently librsvg doesn't have a clear
+distinction.
+
+Unspecified attributes cause librsvg to use defaults, some as per the
+spec, and some (erroneously) as values that seemed to make sense at
+the time of implementation. Please help us find these and make them
+spec-compliant!
+
+For specified attributes, sometimes the set_atts() methods will
+validate the values and resolve them to their final computed form, and
+sometimes they will just store them as they come in the SVG data. The
+computed or actually used values will be generated at rendering time.
+
+# Rendering
+
+The public `rsvg_handle_render_cairo()` and `rsvg_handle_cairo_sub()`
+functions initiate a rendering process; the first function just calls
+the second one with the root element of the SVG.
+
+This second function creates `RsvgDrawingCtx`, which contains the
+rendering state. This structure gets passed around into all the
+rendering functions. It carries the vtable for rendering in the
+`render` field, the CSS state for the node being rendered in the
+`state` field, and other values which are changed as rendering
+progresses.
+
diff --git a/COMPILING.md b/COMPILING.md
new file mode 100644
index 00000000..eb37bc08
--- /dev/null
+++ b/COMPILING.md
@@ -0,0 +1,130 @@
+Compiling librsvg
+=================
+
+Librsvg uses a mostly normal [autotools] setup, but it has some
+peculiarities due to librsvg's use of a Rust sub-library. The details
+of how librsvg integrates Cargo and Rust into its autotools setup are
+described in [this blog post][blog], although hopefully you will not
+need to refer to it.
+
+It is perfectly fine to [ask the maintainer][maintainer] if you have
+questions about the Autotools setup; it's a tricky bit of machinery,
+and we are glad to help.
+
+There are generic compilation/installation instructions in the
+[`INSTALL`][install] file, which comes from Autotools. The following
+explains librsvg's peculiarities.
+
+* [Verbosity](#verbosity)
+* [Debug or release builds](#debug-or-release-builds)
+* [Cross-compilation](#cross-compilation)
+* [Building with no network access](#building-with-no-network-access)
+
+# Verbosity
+
+By default the compilation process is quiet, and it just tells you
+which files it is compiling.
+
+If you wish to see the full compilation command lines, use "`make V=1`"
+instead of plain "`make`".
+
+# Debug or release builds
+
+Librsvg has code both in C and Rust, and each language has a different
+way of specifying compilation options to select compiler
+optimizations, or whether debug information should be included.
+
+You should set the `CFLAGS` environment variable with compiler flags
+that you want to pass to the C compiler.
+
+## Controlling debug or release mode for Rust
+
+For the Rust part of librsvg, we have an `--enable-debug` flag that
+you can pass to the `configure` script. When enabled, the Rust
+sub-library will have debugging information and no compiler
+optimizations. *This flag is off by default:* if the flag is not
+specified, the Rust sub-library will be built in release mode (no
+debug information, full compiler optimizations).
+
+The rationale is that people who already had scripts in place to build
+binary packages for librsvg, generally from release tarballs, are
+already using conventional machinery to specify C compiler options,
+such as that in RPM specfiles or Debian source packages. However,
+they may not contemplate Rust sub-libraries and they will certainly
+not want to modify their existing packaging scripts too much.
+
+So, by default, the Rust library builds in **release mode**, to make
+life easier to binary distributions. Librsvg's build scripts will add
+`--release` to the Cargo command line by default.
+
+Developers can request a debug build of the Rust sub-library by
+passing `--enable-debug` to the `configure` script. This will omit
+the `--release` option from Cargo, so that it will build the Rust
+sub-library in debug mode.
+
+# Cross-compilation
+
+If you need to cross-compile librsvg, specify the `--host=TRIPLE` to
+the `configure` script as usual with Autotools. This will cause
+librsvg's build scripts to automatically pass `--target=TRIPLE` to
+`cargo`.
+
+Note, however, that Rust may support different targets than the C
+compiler on your system. Rust's supported targets can be found in the
+[`rust/src/librustc_back/target`][rust-target-dir] in the Rust
+compiler's source code.
+
+You can check Jorge Aparicio's [guide on cross-compilation for
+Rust][rust-cross] for more details.
+
+## Cross-compiling to a target not supported by Rust out of the box
+
+When building with a target that is not supported out of the box by
+Rust, you have to do this:
+
+1. Create a [target JSON definition file][target-json].
+
+2. Set the environment variable `RUST_TARGET_PATH` to its directory
+ for the `make` command.
+
+Example:
+
+```sh
+cd /my/target/definition
+echo "JSON goes here" > MYMACHINE-VENDOR-OS.json
+cd /source/tree/for/librsvg
+./configure --host=MYMACHINE-VENDOR-OS
+make RUST_TARGET_PATH=/my/target/definition
+```
+
+# Building with no network access
+
+Automated build systems generally avoid network access so that they
+can compile from known-good sources, instead of pulling random updates
+from the net every time. However, normally Cargo likes to download
+dependencies when it first compiles a Rust project.
+
+We use [`cargo vendor`][cargo-vendor] to ship librsvg release tarballs
+with the source code for Rust dependencies **embedded within the
+tarball**. If you unpack a librsvg tarball, these sources will appear
+in the `rust/vendor` subdirectory. If you build librsvg from a
+tarball, instead of git, it should not need to access the network to
+download extra sources at all.
+
+Build systems can use [Cargo's source replacement
+mechanism][cargo-source-replacement] to override the location of the
+source code for the Rust dependencies, for example, in order to patch
+one of the Rust crates that librsvg uses internally.
+
+The source replacement information is in `rust/.cargo/config` in the
+unpacked tarball. Your build system can patch this file as needed.
+
+[autotools]: https://autotools.io/index.html
+[blog]: https://people.gnome.org/~federico/blog/librsvg-build-infrastructure.html
+[maintainer]: README.md#maintainers
+[install]: INSTALL
+[rust-target-dir]: https://github.com/rust-lang/rust/tree/master/src/librustc_back/target
+[cargo-vendor]: https://crates.io/crates/cargo-vendor
+[cargo-source-replacement]: http://doc.crates.io/source-replacement.html
+[rust-cross]: https://github.com/japaric/rust-cross
+[target-json]: https://github.com/japaric/rust-cross#target-specification-files
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c625e646..4bc99b71 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,17 +7,17 @@ contributing to librsvg, and we appreciate all of them.
* [Source repository](#source-code)
* [Reporting bugs](#reporting-bugs)
* [Feature requests](#feature-requests)
-* [Pull requests](#pull-requests)
+* [Merge requests](#merge-requests)
-There is a code of conduct for contributors to librsvg; please see the
-file `code_of_conduct.md`.
+There is a **code of conduct** for contributors to librsvg; please see the
+file [`code_of_conduct.md`][coc].
## Source repository
-Librsvg's main source repository is at git.gnome.org. You can view
+Librsvg's main source repository is at gitlab.gnome.org. You can view
the web interface here:
-https://git.gnome.org/browse/librsvg/
+https://gitlab.gnome.org/GNOME/librsvg
Development happens in the master branch. There are also branches for
stable releases.
@@ -29,17 +29,24 @@ https://github.com/GNOME/librsvg
Note that we don't do bug tracking in the Github mirror; see the next
section.
+If you need to publish a branch, feel free to do it at any
+publically-accessible Git hosting service, although gitlab.gnome.org
+makes things easier for the maintainers of librsvg.
+
## Reporting bugs
-Please report bugs at http://bugzilla.gnome.org/enter_bug.cgi?product=librsvg
+Please report bugs at https://gitlab.gnome.org/GNOME/librsvg/issues
If you want to report a rendering bug, or a missing SVG feature,
please provide an example SVG file as an attachment to your bug
report. It really helps if you can minimize the SVG to only the
elements required to reproduce the bug or see the missing feature, but
-it is not absolutely required. Please be careful of publishing SVG
-images that you don't want other people to see; the bug tracker is a
-public resource and attachments are visible to everyone.
+it is not absolutely required. **Please be careful** of publishing
+SVG images that you don't want other people to see, or images whose
+copyright does not allow redistribution; the bug tracker is a public
+resource and attachments are visible to everyone.
+
+You can also [browse the existing bugs][bugs-browse].
## Feature requests
@@ -55,15 +62,26 @@ directed there.
It is especially helpful if you file bug for a feature request along
with a sample SVG file.
-## Pull requests
+## Merge requests
+
+### Creating a merge request
-You may upload a forked version of librsvg
-to [GNOME's Gitlab instance][gitlab], and create a pull request there.
+You may create a forked version of librsvg in [GNOME's Gitlab
+instance][gitlab], or any other publically-accesible Git hosting
+service. You can register an account there, or log in with your
+account from other OAuth services.
-Although all of `git.gnome.org`'s modules are mirrored at Github, we
-don't support pull requests from there. Apologies for the
-inconvenience - we do this to promote the use of free software,
-including web-based services. Please use [GNOME's Gitlab][gitlab] instead.
+Note that the maintainers of librsvg only get notified about merge
+requests (or pull requests) if your fork is in
+[gitlab.gnome.org][gitlab].
+
+For technical reasons, the maintainers of librsvg do not get
+automatically notified if you submit a pull request through the GNOME
+mirror in Github. [Please contact the maintainer][maintainer] directly if you
+have a pull request there or a branch that you would like to
+contribute.
+
+### Test suite
Please make sure that the test suite passes with the changes in your
branch. The easiest way to run all the tests is to go to librsvg's
@@ -72,6 +90,47 @@ unit tests and the black box tests in the `librsvg/tests` directory.
If you need to add new tests (you should, for new features, or for
things that we weren't testing!), or for additional information on how
-the test suite works, please see the file `tests/README.md`.
-
-[gitlab](https://gitlab.gnome.org/)
+the test suite works, please see the file
+[`tests/README.md`][tests-readme].
+
+### Working on the source
+
+Librvg uses an autotools setup, which is described in detail [in this
+blog post][blog].
+
+If you need to **add a new source file**, you need to do it in the
+toplevel [`Makefile.am`][toplevel-makefile]. *Note that this is for
+both C and Rust sources*, since `make(1)` needs to know when a Rust
+file changed so it can call `cargo` as appropriate.
+
+It is perfectly fine to [ask the maintainer][maintainer] if you have
+questions about the Autotools setup; it's a tricky bit of machinery,
+and we are glad to help.
+
+### Testing changes
+
+The most direct way to test a change is to have an example SVG file
+that exercises the code you want to test. Then you can rebuild
+librsvg, and run this:
+
+```
+cd /src/librsvg
+libtool --mode=execute ./rsvg-convert -o foo.png foo.svg
+```
+
+Then you can view the resulting `foo.png` image. Alternatively, you
+can use `./rsvg-view-3` for a quick-and-dirty SVG viewer.
+
+**Please update the test suite** with a suitable example file once you
+have things working (or before even writing code, if you like
+test-driven development), so we can avoid regressions later. The test
+suite is documented in [`tests/README.md`][tests-readme].
+
+[coc]: code_of_conduct.md
+[gitlab]: https://gitlab.gnome.org/GNOME/librsvg
+[bugs-browse]: https://gitlab.gnome.org/GNOME/librsvg/issues
+[maintainer]: README.md#maintainers
+[tests-readme]: tests/README.md
+[blog]: https://people.gnome.org/~federico/blog/librsvg-build-infrastructure.html
+[toplevel-makefile]: Makefile.am
+[tests-readme]: tests/README.md
diff --git a/Makefile.am b/Makefile.am
index 6e03e6d1..ccd48781 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,58 +20,60 @@ enum_sources = \
BUILT_SOURCES += $(enum_sources)
librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
+ librsvg-enum-types.c \
+ librsvg-enum-types.h \
librsvg-features.c \
+ librsvg-features.h \
+ rsvg-base-file-util.c \
+ rsvg-base.c \
+ rsvg-cairo-clip.c \
+ rsvg-cairo-clip.h \
+ rsvg-cairo-draw.c \
+ rsvg-cairo-draw.h \
+ rsvg-cairo-render.c \
+ rsvg-cairo-render.h \
+ rsvg-cairo.h \
+ rsvg-compat.h \
+ rsvg-cond.c \
rsvg-css.c \
rsvg-css.h \
- rsvg-compat.h \
rsvg-defs.c \
rsvg-defs.h \
+ rsvg-file-util.c \
+ rsvg-filter.c \
+ rsvg-filter.h \
+ rsvg-handle.c \
rsvg-io.c \
rsvg-io.h \
+ rsvg-marker.h \
+ rsvg-mask.h \
rsvg-paint-server.c \
rsvg-paint-server.h \
rsvg-path-builder.h \
rsvg-private.h \
- rsvg-base-file-util.c \
- rsvg-filter.c \
- rsvg-filter.h \
- rsvg-marker.h \
- rsvg-mask.c \
- rsvg-mask.h \
rsvg-shapes.h \
+ rsvg-size-callback.c \
+ rsvg-size-callback.h \
rsvg-structure.h \
rsvg-styles.c \
rsvg-styles.h \
rsvg-text.c \
rsvg-text.h \
- rsvg-cond.c \
- rsvg-base.c \
- librsvg-enum-types.c \
- rsvg-cairo-draw.c \
- rsvg-cairo-draw.h \
- rsvg-cairo-render.c \
- rsvg-cairo-render.h \
- rsvg-cairo-clip.h \
- rsvg-cairo-clip.c \
- rsvg.c \
- rsvg-gobject.c \
- rsvg-file-util.c \
- rsvg-size-callback.c \
- rsvg-size-callback.h \
rsvg-xml.c \
rsvg-xml.h \
+ rsvg.c \
rsvg.h \
- rsvg-cairo.h \
- librsvg-features.h \
- librsvg-enum-types.h \
$(NULL)
RUST_SOURCES = \
rust/Cargo.toml \
rust/src/aspect_ratio.rs \
rust/src/bbox.rs \
+ rust/src/chars.rs \
+ rust/src/clip_path.rs \
rust/src/cnode.rs \
rust/src/color.rs \
+ rust/src/coord_units.rs \
rust/src/drawing_ctx.rs \
rust/src/error.rs \
rust/src/gradient.rs \
@@ -80,6 +82,7 @@ RUST_SOURCES = \
rust/src/length.rs \
rust/src/lib.rs \
rust/src/marker.rs \
+ rust/src/mask.rs \
rust/src/node.rs \
rust/src/opacity.rs \
rust/src/paint_server.rs \
@@ -89,9 +92,11 @@ RUST_SOURCES = \
rust/src/pattern.rs \
rust/src/property_bag.rs \
rust/src/shapes.rs \
+ rust/src/space.rs \
rust/src/state.rs \
rust/src/stop.rs \
rust/src/structure.rs \
+ rust/src/text.rs \
rust/src/transform.rs \
rust/src/util.rs \
rust/src/viewbox.rs \
@@ -117,14 +122,15 @@ cargo_verbose_0 =
cargo_verbose_1 = --verbose
RUST_LIB=@abs_top_builddir@/rust/target/@RUST_TARGET_SUBDIR@/librsvg_internals.a
+CARGO_TARGET_DIR=@abs_top_builddir@/rust/target
check-local:
cd $(srcdir)/rust && \
- CARGO_TARGET_DIR=@abs_top_builddir@/rust/target cargo test
+ CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) cargo test
clean-local:
cd $(top_srcdir)/rust && \
- CARGO_TARGET_DIR=@abs_top_builddir@/rust/target cargo clean
+ CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) cargo clean
dist-hook:
(cd $(distdir)/rust && \
@@ -133,8 +139,11 @@ dist-hook:
cp cargo-vendor-config .cargo/config)
$(RUST_LIB): $(RUST_SOURCES)
- +cd $(top_srcdir)/rust && PKG_CONFIG_ALLOW_CROSS=1 PKG_CONFIG='$(PKG_CONFIG)' \
- CARGO_TARGET_DIR=@abs_top_builddir@/rust/target cargo build $(CARGO_VERBOSE) $(CARGO_TARGET_ARGS) $(CARGO_RELEASE_ARGS)
+ +cd $(top_srcdir)/rust && \
+ PKG_CONFIG_ALLOW_CROSS=1 \
+ PKG_CONFIG='$(PKG_CONFIG)' \
+ CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
+ cargo build $(CARGO_VERBOSE) $(CARGO_TARGET_ARGS) $(CARGO_RELEASE_ARGS)
librsvg_@RSVG_API_MAJOR_VERSION@_la_CPPFLAGS = \
-I$(top_srcdir) \
@@ -222,7 +231,11 @@ if OS_WIN32
rsvg_view_3_LDFLAGS += -mwindows
endif # OS_WIN32
-dist_doc_DATA = README.md
+dist_doc_DATA = \
+ COMPILING.md \
+ CONTRIBUTING.md \
+ README.md \
+ code_of_conduct.md
EXTRA_DIST = \
$(RUST_SOURCES) \
@@ -230,7 +243,6 @@ EXTRA_DIST = \
librsvg.doap \
AUTHORS \
NEWS \
- TODO \
COPYING.LIB \
librsvg-zip.in \
gtk-doc.make \
diff --git a/NEWS b/NEWS
index dfa66aa1..d47d063b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,39 @@
+Version 2.42.0
+- Fix a memory leak in rsvg_handle_new_from_file() (Lovell Fuller).
+- Optimize the xml:space normalization function (Jordan Petridis).
+- gitlab#179 - fix a runtime warning in the feMergeNode code.
+- gitlab#175 - Clarify documentation about the rsvg_*_sub() APIs.
+- Stylistic fixes from cargo-clippy (Jordan Petridis).
+- Port the Pango glue code to Rust.
+- New ARCHITECTURE.md with a description of librsvg's internals.
+
+Version 2.41.2
+- We now require glib 2.52.0.
+- bgo#787895 - Fix mis-use of libxml2. Thanks to Nick Wellnhofer for
+ the guidance.
+- bgo#761175 - Allow masks and clips to reuse a node being drawn.
+- Fix xml:space normalization, per the spec.
+- Don't access the file system when deciding whether to load a remote
+ file with a UNC path for a paint server (i.e. don't try to load it at all).
+- We now support cross-compilation of the Rust code (David Michael).
+ See COMPILING.md for details.
+- Fixed bugs from Coverity runs (Philip Withnall).
+- Vastly improved README.md, new COMPILING.md, improved CONTRIBUTING.md.
+- Markers now have the correct default size per the SVG spec.
+- Visual Studio: We now use HIGHENTROPYVA linker option on x64 builds,
+ to enhance the security of built binaries (Chun-wei Fan).
+- Cargo is now verbose as well if you use "make V=1".
+- Fixed some memory leaks.
+- Don't render elements that establish a viewport if their viewBox
+ size is 0, per the spec.
+- SVG elements ported to Rust: image, clipPath, mask, character data in elements.
+- Fixed loading files one byte at a time.
+- Reference documentation is now DocBook 5.1.
+- Reference docs now have an overview of the library.
+- Distribute README.md in the tarball properly.
+- Expanded the test suite.
+- Lots of internal refactoring.
+
Version 2.41.1
- The feConvolveMatrix filter primitive wasn't being rendered at all;
now it works.
diff --git a/README.md b/README.md
index d3305f4a..e3679895 100644
--- a/README.md
+++ b/README.md
@@ -1,35 +1,65 @@
Librsvg
=======
-This is librsvg - A small SVG rendering library associated with the
-GNOME Project.
+This is librsvg - A small library to render Scalable Vector Graphics
+([SVG][svg]), associated with the [GNOME Project][gnome]. It renders
+SVG files to [Cairo][cairo] surfaces. Cairo is the 2D, antialiased
+drawing library that GNOME uses to draw things to the screen or to
+generate output for printing.
Do you want to render non-animated SVGs to a Cairo surface with a
-minimal, no-nonsense API? Librsvg may be adequate for you.
+minimal API? Librsvg may be adequate for you.
+
+Using librsvg
+-------------
+
+**Compiling:** Librsvg uses a mostly normal [autotools] setup. You
+may run into some peculiarities due to the Rust internals library if
+you are **cross-compiling** or if you are in a **build system with no
+network access**, or if you are **building binary packages from a
+librsvg tarball**. In those cases, please refer to the
+[`COMPILING.md`][compiling] file.
+
+**Documentation:** You can read the [documentation for librsvg][docs] at
+developer.gnome.org. Please [tell us][mail] if you don't find
+something there that you need.
+
+**Bug tracking:** If you have found a bug, take a look at [our bug
+tracker][bugs]. Please see the "[reporting bugs][reporting-bugs]"
+section in the file [CONTRIBUTING.md][contributing] to see how to
+provide a good bug report.
+
+**Asking questions:** Feel free to ask questions about using librsvg
+in the [desktop-devel-list][d-d-l] mailing list.
+
+**Programming languages:** Librsvg exports its API through [GObject
+Introspection][gi]. This way, it is available in many programming
+languages other than C. Please see your language binding's
+documentation for information on how to load the `Rsvg` namespace.
+
+Contributing to librsvg's development
+-------------------------------------
There is a code of conduct for contributors to librsvg; please see the
-file `code_of_conduct.md`.
+file [`code_of_conduct.md`][coc].
For information on how to report bugs, or how to contribute to librsvg
-in general, please see the file `CONTRIBUTING.md`.
+in general, please see the file [`CONTRIBUTING.md`][contributing].
Goals of librsvg
----------------
Librsvg aims to be a low-footprint library for rendering SVG images.
-It is used primarily in the [GNOME project](https://www.gnome.org) to render
-SVG icons and vector images that appear on the desktop. It is also
-used in Wikimedia to render the SVG images that appear in Wikipedia,
-so that even old web browsers can display them.
+It is used primarily in the [GNOME project](https://www.gnome.org) to
+render SVG icons and vector images that appear on the desktop. It is
+also used in Wikimedia to render the SVG images that appear in
+Wikipedia, so that even old web browsers can display them. Many
+projects which casually need to render static SVG images use librsvg.
We aim to be a "render this SVG for me, quickly, and with a minimal
-API" kind of library. The SVG specification is huge, and definitely
-contains features that are not frequently used in the Real World, if
-at all.
+API" kind of library.
-Feature additions will be considered on a case-by-case basis. Extra
-points if you provide a proof-of-concept patch, and an example of the
-situation in which you encountered that missing feature!
+Feature additions will be considered on a case-by-case basis.
Non-goals of librsvg
--------------------
@@ -38,10 +68,95 @@ We don't aim to:
* Implement every single SVG feature that is in the spec.
-* Implement external access to the SVG's DOM.
+* Implement scripting or external access to the SVG's DOM.
* Implement support for CSS-based animations (but if you can think of
- a nice API to do this, we'd be glad to know!)
+ a nice API to do this, we would be glad to know!)
* Replace the industrial-strength SVG rendering machinery in modern
web browsers.
+
+Of course, [contributions are welcome][contributing]. In particular,
+if you find nice ways of doing the above while still maintaining the
+existing API of librsvg, we would love to know about it!
+
+Who uses librsvg?
+-----------------
+
+Librsvg is part of the [GNOME platform][platform]. Inside GNOME,
+librsvg takes multiple roles:
+
+* Loads SVGs from the generic gdk-pixbuf loader infrastructure, so any
+ application which uses gdk-pixbuf can load SVGs as if they were
+ raster images.
+
+* Loads SVG icons for the desktop.
+
+* Creates SVG thumbnails for the file manager.
+
+* Loads SVGs within GNOME's default image viewer, Eye of Gnome.
+
+Outside of GNOME's core:
+
+* GNOME games (chess, five-or-more, etc. to draw game pieces)
+
+* GIMP
+
+* GCompris
+
+* Claws-mail
+
+* Darktable
+
+* Mate-panel
+
+* Evas/Enlightenment
+
+* Emacs
+
+* ImageMagick
+
+* Wikipedia, to render SVGs as raster images for old browsers.
+ *Special thanks to Wikimedia for providing excellent bug reports.*
+
+
+Presentations on librsvg
+------------------------
+
+"[Replacing C library code with Rust: What I learned with
+librsvg][guadec-presentation]" was presented at GUADEC 2017. It gives
+a little history of librsvg, and how/why it is being ported to Rust
+from C.
+
+Maintainers
+-----------
+
+The maintainer of librsvg is [Federico Mena Quintero][federico]. Feel
+free to contact me for any questions you may have about librsvg, both
+its usage and its development. You can contact me in the following
+ways:
+
+* [Mail me][mail] at federico@gnome.org.
+
+* IRC: I am `federico` on `irc.gnome.org` in the `#rust` or
+ `#gnome-hackers` channels. I'm there most weekdays (Mon-Fri)
+ starting at about UTC 14:00 (that's 08:00 my time; I am in the UTC-6
+ timezone). If this is not a convenient time for you, feel free to
+ [mail me][mail] and we can arrange a time.
+
+[svg]: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
+[gnome]: https://www.gnome.org/
+[cairo]: https://www.cairographics.org/
+[coc]: code_of_conduct.md
+[autotools]: https://autotools.io/index.html
+[compiling]: COMPILING.md
+[docs]: https://developer.gnome.org/rsvg/stable/
+[mail]: mailto:federico@gnome.org
+[bugs]: https://gitlab.gnome.org/GNOME/librsvg/issues
+[gi]: https://wiki.gnome.org/Projects/GObjectIntrospection
+[contributing]: CONTRIBUTING.md
+[reporting-bugs]: CONTRIBUTING.md#reporting-bugs
+[d-d-l]: https://mail.gnome.org/mailman/listinfo/desktop-devel-list
+[federico]: https://people.gnome.org/~federico/
+[platform]: https://developer.gnome.org/
+[guadec-presentation]: https://people.gnome.org/~federico/blog/docs/fmq-porting-c-to-rust.pdf
diff --git a/configure.ac b/configure.ac
index 18ca8bd6..4103df31 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
m4_define([rsvg_major_version],[2])
-m4_define([rsvg_minor_version],[41])
-m4_define([rsvg_micro_version],[2])
+m4_define([rsvg_minor_version],[42])
+m4_define([rsvg_micro_version],[1])
m4_define([rsvg_extra_version],[])
m4_define([rsvg_version],[rsvg_major_version.rsvg_minor_version.rsvg_micro_version()rsvg_extra_version])
m4_define([rsvg_lt_version_info],m4_eval(rsvg_major_version + rsvg_minor_version):rsvg_micro_version:rsvg_minor_version)
-AC_INIT([RSVG],[rsvg_version],[https://bugzilla.gnome.org/enter_bug.cgi?product=librsvg],[librsvg])
+AC_INIT([RSVG],[rsvg_version],[https://gitlab.gnome.org/GNOME/librsvg/issues],[librsvg])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([rsvg.h])
@@ -38,7 +38,7 @@ AC_SUBST([LIBRSVG_MICRO_VERSION],[rsvg_micro_version])
dnl ===========================================================================
-GLIB_REQUIRED=2.12.0
+GLIB_REQUIRED=2.52.0
GIO_REQUIRED=2.24.0
LIBXML_REQUIRED=2.9.0
CAIRO_REQUIRED=1.2.0
@@ -188,8 +188,6 @@ AC_SUBST([gdk_pixbuf_cache_file])
AM_CONDITIONAL([ENABLE_PIXBUF_LOADER],[test "$enable_pixbuf_loader" = "yes"])
-AM_CONDITIONAL(CROSS_COMPILING, test $cross_compiling = yes)
-
##########################################################
# Check for -Bsymbolic-functions linker flag used to avoid
# intra-library PLT jumps, if available.
@@ -262,6 +260,7 @@ else
fi
AM_CONDITIONAL([DEBUG_RELEASE], [test "x$debug_release" = "xyes"])
+AM_CONDITIONAL(CROSS_COMPILING, test $cross_compiling = yes)
if test "x$cross_compiling" = "xyes" ; then
RUST_TARGET_SUBDIR="$host/$RUST_TARGET_SUBDIR"
fi
diff --git a/doc/Makefile.am b/doc/Makefile.am
index a2d2ed47..d0c7cef5 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -20,7 +20,7 @@ DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml
# gtk-doc will search all .c & .h files beneath here for inline comments
# documenting the functions and macros.
# e.g. DOC_SOURCE_DIR=../../../gtk
-DOC_SOURCE_DIR = ..
+DOC_SOURCE_DIR = $(abs_top_srcdir)
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
SCANGOBJ_OPTIONS = --type-init-func="g_type_init ()"
@@ -31,7 +31,7 @@ SCAN_OPTIONS = --deprecated-guards="RSVG_DISABLE_DEPRECATED"
# Extra options to supply to gtkdoc-mkdb.
# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
-MKDB_OPTIONS = --sgml-mode --output-format=xml --name-space=rsvg
+MKDB_OPTIONS = --xml-mode --output-format=xml --name-space=rsvg
# Extra options to supply to gtkdoc-mktmpl
# e.g. MKTMPL_OPTIONS=--only-section-tmpl
@@ -68,25 +68,26 @@ EXTRA_HFILES =
# Header files to ignore when scanning. Use base file name, no paths
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
-IGNORE_HFILES = \
- config.h \
- rsvg-bpath-util.h \
- rsvg-cairo-clip.h \
- rsvg-cairo-draw.h \
- rsvg-cairo-render.h \
- rsvg-css.h \
- rsvg-defs.h \
- rsvg-filter.h \
- rsvg-image.h \
- rsvg-marker.h \
- rsvg-mask.h \
- rsvg-paint-server.h \
- rsvg-path.h \
- rsvg-private.h \
- rsvg-shapes.h \
- rsvg-structure.h \
- rsvg-styles.h \
- rsvg-text.h \
+IGNORE_HFILES = \
+ config.h \
+ rsvg-cairo-clip.h \
+ rsvg-cairo-draw.h \
+ rsvg-cairo-render.h \
+ rsvg-compat.h \
+ rsvg-css.h \
+ rsvg-defs.h \
+ rsvg-filter.h \
+ rsvg-io.h \
+ rsvg-marker.h \
+ rsvg-mask.h \
+ rsvg-paint-server.h \
+ rsvg-path-builder.h \
+ rsvg-private.h \
+ rsvg-shapes.h \
+ rsvg-size-callback.h \
+ rsvg-structure.h \
+ rsvg-styles.h \
+ rsvg-text.h \
rsvg-xml.h
# Images to copy into HTML directory.
diff --git a/doc/rsvg-sections.txt b/doc/rsvg-sections.txt
index 7614c569..71550188 100644
--- a/doc/rsvg-sections.txt
+++ b/doc/rsvg-sections.txt
@@ -94,6 +94,4 @@ LIBRSVG_HAVE_SVGZ
LIBRSVG_HAVE_CSS
LIBRSVG_CHECK_FEATURE
librsvg_version
-librsvg_preinit
-librsvg_postinit
</SECTION>
diff --git a/doc/rsvg.types b/doc/rsvg.types
deleted file mode 100644
index a899771c..00000000
--- a/doc/rsvg.types
+++ /dev/null
@@ -1,3 +0,0 @@
-rsvg_error_get_type
-rsvg_handle_flags_get_type
-rsvg_handle_get_type
diff --git a/librsvg.doap b/librsvg.doap
index 9a2f8d10..7f47d9e2 100644
--- a/librsvg.doap
+++ b/librsvg.doap
@@ -17,9 +17,10 @@
<homepage rdf:resource="https://wiki.gnome.org/action/show/Projects/LibRsvg" />
<mailing-list rdf:resource="https://mail.gnome.org/mailman/listinfo/desktop-devel-list" />
<download-page rdf:resource="https://download.gnome.org/sources/librsvg/" />
- <bug-database rdf:resource="https://bugzilla.gnome.org/browse.cgi?product=librsvg" />
+ <bug-database rdf:resource="https://gitlab.gnome.org/GNOME/librsvg/issues" />
<category rdf:resource="http://api.gnome.org/doap-extensions#deprecated" />
<programming-language>C</programming-language>
+ <programming-language>Rust</programming-language>
<maintainer>
<foaf:Person>
diff --git a/rsvg-base-file-util.c b/rsvg-base-file-util.c
index d33f93f6..c4be0d59 100644
--- a/rsvg-base-file-util.c
+++ b/rsvg-base-file-util.c
@@ -87,11 +87,22 @@ rsvg_handle_new_from_file (const gchar * file_name, GError ** error)
char *data;
gsize data_len;
RsvgHandle *handle = NULL;
+ GFile *file;
rsvg_return_val_if_fail (file_name != NULL, NULL, error);
- base_uri = rsvg_get_base_uri_from_filename (file_name);
- data = _rsvg_io_acquire_data (file_name, base_uri, NULL, &data_len, NULL, error);
+ file = g_file_new_for_path (file_name);
+ base_uri = g_file_get_uri (file);
+ if (!base_uri) {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Cannot obtain URI from '%s'"), file_name);
+ g_object_unref (file);
+ return NULL;
+ }
+
+ data = _rsvg_io_acquire_data (base_uri, base_uri, NULL, &data_len, NULL, error);
if (data) {
handle = rsvg_handle_new ();
@@ -104,6 +115,7 @@ rsvg_handle_new_from_file (const gchar * file_name, GError ** error)
}
g_free (base_uri);
+ g_object_unref (file);
return handle;
}
diff --git a/rsvg-base.c b/rsvg-base.c
index f0a5539c..c79ce222 100644
--- a/rsvg-base.c
+++ b/rsvg-base.c
@@ -139,7 +139,7 @@ rsvg_style_handler_free (RsvgSaxHandler * self)
}
static void
-rsvg_style_handler_characters (RsvgSaxHandler * self, const char *ch, int len)
+rsvg_style_handler_characters (RsvgSaxHandler * self, const char *ch, gssize len)
{
RsvgSaxHandlerStyle *z = (RsvgSaxHandlerStyle *) self;
g_string_append_len (z->style, ch, len);
@@ -272,7 +272,7 @@ static const NodeCreator node_creators[] = {
/* "animateMotion", FALSE, */
/* "animateTransform", FALSE, */
{ "circle", TRUE, rsvg_node_circle_new },
- { "clipPath", TRUE, rsvg_new_clip_path },
+ { "clipPath", TRUE, rsvg_node_clip_path_new },
/* "color-profile", FALSE, */
{ "conicalGradient", TRUE, rsvg_node_radial_gradient_new },
/* "cursor", FALSE, */
@@ -319,7 +319,7 @@ static const NodeCreator node_creators[] = {
{ "line", TRUE, rsvg_node_line_new },
{ "linearGradient", TRUE, rsvg_node_linear_gradient_new },
{ "marker", TRUE, rsvg_node_marker_new },
- { "mask", TRUE, rsvg_new_mask },
+ { "mask", TRUE, rsvg_node_mask_new },
/* "metadata", FALSE, */
/* "missing-glyph", TRUE, */
/* "mpath" FALSE, */
@@ -465,7 +465,7 @@ rsvg_extra_handler_free (RsvgSaxHandler * self)
}
static void
-rsvg_extra_handler_characters (RsvgSaxHandler * self, const char *ch, int len)
+rsvg_extra_handler_characters (RsvgSaxHandler * self, const char *ch, gssize len)
{
RsvgSaxHandlerExtra *z = (RsvgSaxHandlerExtra *) self;
@@ -480,7 +480,7 @@ rsvg_extra_handler_characters (RsvgSaxHandler * self, const char *ch, int len)
if (!g_utf8_validate ((char *) ch, len, NULL)) {
char *utf8;
- utf8 = rsvg_make_valid_utf8 ((char *) ch, len);
+ utf8 = g_utf8_make_valid (ch, len);
g_string_append (z->string, utf8);
g_free (utf8);
} else {
@@ -616,10 +616,8 @@ typedef struct _RsvgSaxHandlerXinclude {
gboolean in_fallback;
} RsvgSaxHandlerXinclude;
-static void
- rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts);
-static void
- rsvg_characters_impl (RsvgHandle * ctx, const xmlChar * ch, int len);
+static void rsvg_start_xinclude (RsvgHandle *ctx, RsvgPropertyBag *atts);
+static void rsvg_characters_impl (RsvgHandle *ctx, const char *ch, gssize len);
static void
rsvg_xinclude_handler_free (RsvgSaxHandler * self)
@@ -628,12 +626,12 @@ rsvg_xinclude_handler_free (RsvgSaxHandler * self)
}
static void
-rsvg_xinclude_handler_characters (RsvgSaxHandler * self, const char *ch, int len)
+rsvg_xinclude_handler_characters (RsvgSaxHandler * self, const char *ch, gssize len)
{
RsvgSaxHandlerXinclude *z = (RsvgSaxHandlerXinclude *) self;
if (z->in_fallback) {
- rsvg_characters_impl (z->ctx, (const xmlChar *) ch, len);
+ rsvg_characters_impl (z->ctx, ch, len);
}
}
@@ -762,7 +760,7 @@ rsvg_start_xinclude (RsvgHandle * ctx, RsvgPropertyBag * atts)
data_len = text_data_len;
}
- rsvg_characters_impl (ctx, (xmlChar *) data, data_len);
+ rsvg_characters_impl (ctx, data, data_len);
g_free (data);
} else {
@@ -884,59 +882,27 @@ rsvg_end_element (void *data, const xmlChar * xmlname)
}
}
-static void
-rsvg_node_chars_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag * atts)
-{
- /* nothing */
-}
-
-static void
-rsvg_node_chars_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
- /* nothing */
-}
+/* Implemented in rust/src/chars.rs */
+extern RsvgNode *rsvg_node_chars_new(RsvgNode *parent);
-static void
-rsvg_node_chars_free (gpointer impl)
-{
- RsvgNodeChars *self = impl;
- g_string_free (self->contents, TRUE);
- g_free (self);
-}
+/* Implemented in rust/src/chars.rs */
+extern void rsvg_node_chars_append (RsvgNode *node, const char *text, gssize len);
-static RsvgNode *
-rsvg_new_node_chars (const char *text,
- int len,
- RsvgNode *parent)
+static gboolean
+node_is_text_or_tspan (RsvgNode *node)
{
- RsvgNodeChars *self;
- RsvgState *state;
-
- self = g_new0 (RsvgNodeChars, 1);
+ RsvgNodeType type;
- if (!g_utf8_validate (text, len, NULL)) {
- char *utf8;
- utf8 = rsvg_make_valid_utf8 (text, len);
- self->contents = g_string_new (utf8);
- g_free (utf8);
- } else {
- self->contents = g_string_new_len (text, len);
+ if (!node) {
+ return FALSE;
}
- state = rsvg_state_new ();
- state->cond_true = FALSE;
-
- return rsvg_rust_cnode_new (RSVG_NODE_TYPE_CHARS,
- parent,
- state,
- self,
- rsvg_node_chars_set_atts,
- rsvg_node_chars_draw,
- rsvg_node_chars_free);
+ type = rsvg_node_get_type (node);
+ return type == RSVG_NODE_TYPE_TEXT || type == RSVG_NODE_TYPE_TSPAN;
}
static gboolean
-find_last_chars_node (RsvgNode *node, gpointer data)
+find_last_chars_node_foreach (RsvgNode *node, gpointer data)
{
RsvgNode **dest;
@@ -945,57 +911,81 @@ find_last_chars_node (RsvgNode *node, gpointer data)
if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_CHARS) {
*dest = rsvg_node_ref (node);
} else if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_TSPAN) {
- *dest = rsvg_node_unref (*dest); /* Discard the last chars node we found */
+ /* If we have
+ * <text>
+ * First (1)
+ * <tspan>foo bar</tspan>
+ * Second (2)
+ * </text>
+ *
+ * Then we want (1) to go into a chars node. However, the "foo bar" tspan will go
+ * into its own node. When we read (2), we want it to go into a *new* chars node,
+ * not the one from (1). So, here we discard the last chars node we found if
+ * we run into a tspan.
+ */
+ *dest = rsvg_node_unref (*dest);
}
return TRUE;
}
-static void
-rsvg_characters_impl (RsvgHandle * ctx, const xmlChar * ch, int len)
+/* Finds the last chars child inside a given @node to which new characters can
+ * be appended. @node can be null; in this case we'll return NULL as we didn't
+ * find any children.
+ */
+static RsvgNode *
+find_last_chars_child (RsvgNode *node)
+{
+ RsvgNode *child = NULL;
+
+ if (node_is_text_or_tspan (node)) {
+ /* find the last CHARS node in the text or tspan node, so that we can
+ * coalesce the text, and thus avoid screwing up the Pango layouts.
+ */
+ rsvg_node_foreach_child (node,
+ find_last_chars_node_foreach,
+ &child);
+ }
+
+ return child;
+}
+
+static RsvgNode *
+add_new_chars_child_to_current_node (RsvgHandle *ctx)
{
RsvgNode *node;
- if (!ch || !len)
- return;
+ node = rsvg_node_chars_new (ctx->priv->currentnode);
+ add_node_to_handle (ctx, node);
if (ctx->priv->currentnode) {
- RsvgNodeType type = rsvg_node_get_type (ctx->priv->currentnode);
- if (type == RSVG_NODE_TYPE_TSPAN || type == RSVG_NODE_TYPE_TEXT) {
- RsvgNodeChars *self;
-
- /* find the last CHARS node in the text or tspan node, so that we
- can coalesce the text, and thus avoid screwing up the Pango layouts */
- node = NULL;
- rsvg_node_foreach_child (ctx->priv->currentnode,
- find_last_chars_node,
- &node);
-
- if (node) {
- g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_CHARS);
- self = rsvg_rust_cnode_get_impl (node);
-
- if (!g_utf8_validate ((char *) ch, len, NULL)) {
- char *utf8;
- utf8 = rsvg_make_valid_utf8 ((char *) ch, len);
- g_string_append (self->contents, utf8);
- g_free (utf8);
- } else {
- g_string_append_len (self->contents, (char *)ch, len);
- }
+ rsvg_node_add_child (ctx->priv->currentnode, node);
+ }
- node = rsvg_node_unref (node);
- return;
- }
- }
+ return node;
+}
+
+static void
+rsvg_characters_impl (RsvgHandle *ctx, const char *ch, gssize len)
+{
+ RsvgNode *node = NULL;
+
+ if (!ch || !len) {
+ return;
+ }
+
+ if (!node_is_text_or_tspan (ctx->priv->currentnode)) {
+ return;
}
- node = rsvg_new_node_chars ((char *) ch, len, ctx->priv->currentnode);
+ node = find_last_chars_child (ctx->priv->currentnode);
- add_node_to_handle (ctx, node);
+ if (!node) {
+ node = add_new_chars_child_to_current_node (ctx);
+ }
- if (ctx->priv->currentnode)
- rsvg_node_add_child (ctx->priv->currentnode, node);
+ g_assert (rsvg_node_get_type (node) == RSVG_NODE_TYPE_CHARS);
+ rsvg_node_chars_append (node, ch, len);
node = rsvg_node_unref (node);
}
@@ -1010,7 +1000,7 @@ rsvg_characters (void *data, const xmlChar * ch, int len)
return;
}
- rsvg_characters_impl (ctx, ch, len);
+ rsvg_characters_impl (ctx, (const char *) ch, len);
}
static xmlEntityPtr
@@ -1173,138 +1163,6 @@ rsvg_SAX_handler_struct_init (void)
}
}
-/* http://www.ietf.org/rfc/rfc2396.txt */
-
-static gboolean
-rsvg_path_is_uri (char const *path)
-{
- char const *p;
-
- if (path == NULL)
- return FALSE;
-
- if (strlen (path) < 4)
- return FALSE;
-
- if ((path[0] < 'a' || path[0] > 'z') &&
- (path[0] < 'A' || path[0] > 'Z')) {
- return FALSE;
- }
-
- for (p = &path[1];
- (*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9') ||
- *p == '+' ||
- *p == '-' ||
- *p == '.';
- p++);
-
- if (strlen (p) < 3)
- return FALSE;
-
- return (p[0] == ':' && p[1] == '/' && p[2] == '/');
-}
-
-gchar *
-rsvg_get_base_uri_from_filename (const gchar * filename)
-{
- gchar *current_dir;
- gchar *absolute_filename;
- gchar *base_uri;
-
-
- if (g_path_is_absolute (filename))
- return g_filename_to_uri (filename, NULL, NULL);
-
- current_dir = g_get_current_dir ();
- absolute_filename = g_build_filename (current_dir, filename, NULL);
- base_uri = g_filename_to_uri (absolute_filename, NULL, NULL);
- g_free (absolute_filename);
- g_free (current_dir);
-
- return base_uri;
-}
-
-/**
- * rsvg_handle_set_base_uri:
- * @handle: A #RsvgHandle
- * @base_uri: The base uri
- *
- * Set the base URI for this SVG. This can only be called before rsvg_handle_write()
- * has been called.
- *
- * Since: 2.9
- */
-void
-rsvg_handle_set_base_uri (RsvgHandle * handle, const char *base_uri)
-{
- gchar *uri;
- GFile *file;
-
- g_return_if_fail (handle != NULL);
-
- if (base_uri == NULL)
- return;
-
- if (rsvg_path_is_uri (base_uri))
- uri = g_strdup (base_uri);
- else
- uri = rsvg_get_base_uri_from_filename (base_uri);
-
- file = g_file_new_for_uri (uri ? uri : "data:");
- rsvg_handle_set_base_gfile (handle, file);
- g_object_unref (file);
- g_free (uri);
-}
-
-/**
- * rsvg_handle_set_base_gfile:
- * @handle: a #RsvgHandle
- * @base_file: a #GFile
- *
- * Set the base URI for @handle from @file.
- * Note: This function may only be called before rsvg_handle_write()
- * or rsvg_handle_read_stream_sync() has been called.
- *
- * Since: 2.32
- */
-void
-rsvg_handle_set_base_gfile (RsvgHandle *handle,
- GFile *base_file)
-{
- RsvgHandlePrivate *priv;
-
- g_return_if_fail (RSVG_IS_HANDLE (handle));
- g_return_if_fail (G_IS_FILE (base_file));
-
- priv = handle->priv;
-
- g_object_ref (base_file);
- if (priv->base_gfile)
- g_object_unref (priv->base_gfile);
- priv->base_gfile = base_file;
-
- g_free (priv->base_uri);
- priv->base_uri = g_file_get_uri (base_file);
-}
-
-/**
- * rsvg_handle_get_base_uri:
- * @handle: A #RsvgHandle
- *
- * Gets the base uri for this #RsvgHandle.
- *
- * Returns: the base uri, possibly null
- * Since: 2.8
- */
-const char *
-rsvg_handle_get_base_uri (RsvgHandle * handle)
-{
- g_return_val_if_fail (handle, NULL);
- return handle->priv->base_uri;
-}
-
/**
* rsvg_error_quark:
*
@@ -1339,7 +1197,7 @@ rsvg_set_error (GError **error, xmlParserCtxtPtr ctxt)
}
static gboolean
-rsvg_handle_write_impl (RsvgHandle * handle, const guchar * buf, gsize count, GError ** error)
+write_impl (RsvgHandle * handle, const guchar * buf, gsize count, GError ** error)
{
GError *real_error = NULL;
int result;
@@ -1369,7 +1227,7 @@ rsvg_handle_write_impl (RsvgHandle * handle, const guchar * buf, gsize count, GE
}
static gboolean
-rsvg_handle_close_impl (RsvgHandle * handle, GError ** error)
+close_impl (RsvgHandle * handle, GError ** error)
{
GError *real_error = NULL;
@@ -1419,321 +1277,6 @@ rsvg_drawing_ctx_free (RsvgDrawingCtx * handle)
}
/**
- * rsvg_handle_get_metadata:
- * @handle: An #RsvgHandle
- *
- * Returns the SVG's metadata in UTF-8 or %NULL. You must make a copy
- * of this metadata if you wish to use it after @handle has been freed.
- *
- * Returns: (nullable): The SVG's title
- *
- * Since: 2.9
- *
- * Deprecated: 2.36
- */
-const char *
-rsvg_handle_get_metadata (RsvgHandle * handle)
-{
- g_return_val_if_fail (handle, NULL);
-
- if (handle->priv->metadata)
- return handle->priv->metadata->str;
- else
- return NULL;
-}
-
-/**
- * rsvg_handle_get_title:
- * @handle: An #RsvgHandle
- *
- * Returns the SVG's title in UTF-8 or %NULL. You must make a copy
- * of this title if you wish to use it after @handle has been freed.
- *
- * Returns: (nullable): The SVG's title
- *
- * Since: 2.4
- *
- * Deprecated: 2.36
- */
-const char *
-rsvg_handle_get_title (RsvgHandle * handle)
-{
- g_return_val_if_fail (handle, NULL);
-
- if (handle->priv->title)
- return handle->priv->title->str;
- else
- return NULL;
-}
-
-/**
- * rsvg_handle_get_desc:
- * @handle: An #RsvgHandle
- *
- * Returns the SVG's description in UTF-8 or %NULL. You must make a copy
- * of this description if you wish to use it after @handle has been freed.
- *
- * Returns: (nullable): The SVG's description
- *
- * Since: 2.4
- *
- * Deprecated: 2.36
- */
-const char *
-rsvg_handle_get_desc (RsvgHandle * handle)
-{
- g_return_val_if_fail (handle, NULL);
-
- if (handle->priv->desc)
- return handle->priv->desc->str;
- else
- return NULL;
-}
-
-/**
- * rsvg_handle_get_dimensions:
- * @handle: A #RsvgHandle
- * @dimension_data: (out): A place to store the SVG's size
- *
- * Get the SVG's size. Do not call from within the size_func callback, because an infinite loop will occur.
- *
- * Since: 2.14
- */
-void
-rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimension_data)
-{
- /* This function is probably called from the cairo_render functions.
- * To prevent an infinite loop we are saving the state.
- */
- if (!handle->priv->in_loop) {
- handle->priv->in_loop = TRUE;
- rsvg_handle_get_dimensions_sub (handle, dimension_data, NULL);
- handle->priv->in_loop = FALSE;
- } else {
- /* Called within the size function, so return a standard size */
- dimension_data->em = dimension_data->width = 1;
- dimension_data->ex = dimension_data->height = 1;
- }
-}
-
-/**
- * rsvg_handle_get_dimensions_sub:
- * @handle: A #RsvgHandle
- * @dimension_data: (out): A place to store the SVG's size
- * @id: (nullable): An element's id within the SVG, or %NULL to get
- * the dimension of the whole SVG. For example, if you have a layer
- * called "layer1" for that you want to get the dimension, pass
- * "#layer1" as the id.
- *
- * Get the size of a subelement of the SVG file. Do not call from within the size_func callback, because an infinite loop will occur.
- *
- * Since: 2.22
- */
-gboolean
-rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id)
-{
- cairo_t *cr;
- cairo_surface_t *target;
- RsvgDrawingCtx *draw;
- RsvgNode *sself = NULL;
- RsvgBbox bbox;
- RsvgLength root_width, root_height;
- RsvgViewBox root_vbox;
-
- gboolean handle_subelement = TRUE;
-
- g_return_val_if_fail (handle, FALSE);
- g_return_val_if_fail (dimension_data, FALSE);
-
- memset (dimension_data, 0, sizeof (RsvgDimensionData));
-
- if (id && *id) {
- sself = rsvg_defs_lookup (handle->priv->defs, id);
-
- if (rsvg_node_is_same (sself, handle->priv->treebase))
- id = NULL;
- } else {
- sself = handle->priv->treebase;
- }
-
- if (!sself && id)
- return FALSE;
-
- if (!handle->priv->treebase)
- return FALSE;
-
- g_assert (rsvg_node_get_type (handle->priv->treebase) == RSVG_NODE_TYPE_SVG);
-
- bbox.rect.x = bbox.rect.y = 0;
- bbox.rect.width = bbox.rect.height = 1;
-
- rsvg_node_svg_get_size (handle->priv->treebase, &root_width, &root_height);
- root_vbox = rsvg_node_svg_get_view_box (handle->priv->treebase);
-
- if (!id) {
- if ((root_width.unit == LENGTH_UNIT_PERCENT || root_height.unit == LENGTH_UNIT_PERCENT) && !root_vbox.active)
- handle_subelement = TRUE;
- else
- handle_subelement = FALSE;
- }
-
- if (handle_subelement == TRUE) {
- target = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
- 1, 1);
- cr = cairo_create (target);
-
- draw = rsvg_cairo_new_drawing_ctx (cr, handle);
-
- if (!draw) {
- cairo_destroy (cr);
- cairo_surface_destroy (target);
-
- return FALSE;
- }
-
- g_assert (sself != NULL);
- rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, sself);
-
- rsvg_drawing_ctx_draw_node_from_stack (draw, handle->priv->treebase, 0);
- bbox = RSVG_CAIRO_RENDER (draw->render)->bbox;
-
- rsvg_drawing_ctx_free (draw);
- cairo_destroy (cr);
- cairo_surface_destroy (target);
-
- dimension_data->width = bbox.rect.width;
- dimension_data->height = bbox.rect.height;
- } else {
- bbox.rect.width = root_vbox.rect.width;
- bbox.rect.height = root_vbox.rect.height;
-
- dimension_data->width = (int) (rsvg_length_hand_normalize (&root_width, handle->priv->dpi_x,
- bbox.rect.width, 12) + 0.5);
- dimension_data->height = (int) (rsvg_length_hand_normalize (&root_height, handle->priv->dpi_y,
- bbox.rect.height, 12) + 0.5);
- }
-
- dimension_data->em = dimension_data->width;
- dimension_data->ex = dimension_data->height;
-
- if (handle->priv->size_func)
- (*handle->priv->size_func) (&dimension_data->width, &dimension_data->height,
- handle->priv->user_data);
-
- return TRUE;
-}
-
-/**
- * rsvg_handle_get_position_sub:
- * @handle: A #RsvgHandle
- * @position_data: (out): A place to store the SVG fragment's position.
- * @id: An element's id within the SVG.
- * For example, if you have a layer called "layer1" for that you want to get
- * the position, pass "##layer1" as the id.
- *
- * Get the position of a subelement of the SVG file. Do not call from within
- * the size_func callback, because an infinite loop will occur.
- *
- * Since: 2.22
- */
-gboolean
-rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_data, const char *id)
-{
- RsvgDrawingCtx *draw;
- RsvgNode *node;
- RsvgBbox bbox;
- RsvgDimensionData dimension_data;
- cairo_surface_t *target = NULL;
- cairo_t *cr = NULL;
- gboolean ret = FALSE;
-
- g_return_val_if_fail (handle, FALSE);
- g_return_val_if_fail (position_data, FALSE);
-
- if (!handle->priv->treebase)
- return FALSE;
-
- /* Short-cut when no id is given. */
- if (NULL == id || '\0' == *id) {
- position_data->x = 0;
- position_data->y = 0;
- return TRUE;
- }
-
- memset (position_data, 0, sizeof (*position_data));
- memset (&dimension_data, 0, sizeof (dimension_data));
-
- node = rsvg_defs_lookup (handle->priv->defs, id);
- if (!node) {
- return FALSE;
- } else if (rsvg_node_is_same (node, handle->priv->treebase)) {
- /* Root node. */
- position_data->x = 0;
- position_data->y = 0;
- return TRUE;
- }
-
- target = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
- cr = cairo_create (target);
- draw = rsvg_cairo_new_drawing_ctx (cr, handle);
- if (!draw)
- goto bail;
-
- g_assert (node != NULL);
- rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, node);
-
- rsvg_drawing_ctx_draw_node_from_stack (draw, handle->priv->treebase, 0);
- bbox = RSVG_CAIRO_RENDER (draw->render)->bbox;
-
- rsvg_drawing_ctx_free (draw);
-
- position_data->x = bbox.rect.x;
- position_data->y = bbox.rect.y;
- dimension_data.width = bbox.rect.width;
- dimension_data.height = bbox.rect.height;
-
- dimension_data.em = dimension_data.width;
- dimension_data.ex = dimension_data.height;
-
- if (handle->priv->size_func)
- (*handle->priv->size_func) (&dimension_data.width, &dimension_data.height,
- handle->priv->user_data);
-
- ret = TRUE;
-
-bail:
- if (cr)
- cairo_destroy (cr);
- if (target)
- cairo_surface_destroy (target);
-
- return ret;
-}
-
-/**
- * rsvg_handle_has_sub:
- * @handle: a #RsvgHandle
- * @id: an element's id within the SVG
- *
- * Checks whether the element @id exists in the SVG document.
- *
- * Returns: %TRUE if @id exists in the SVG document
- *
- * Since: 2.22
- */
-gboolean
-rsvg_handle_has_sub (RsvgHandle * handle,
- const char *id)
-{
- g_return_val_if_fail (handle, FALSE);
-
- if (G_UNLIKELY (!id || !id[0]))
- return FALSE;
-
- return rsvg_defs_lookup (handle->priv->defs, id) != NULL;
-}
-
-/**
* rsvg_set_default_dpi:
* @dpi: Dots Per Inch (aka Pixels Per Inch)
*
@@ -1774,106 +1317,6 @@ rsvg_set_default_dpi_x_y (double dpi_x, double dpi_y)
rsvg_internal_dpi_y = dpi_y;
}
-/**
- * rsvg_handle_set_dpi:
- * @handle: An #RsvgHandle
- * @dpi: Dots Per Inch (aka Pixels Per Inch)
- *
- * Sets the DPI for the outgoing pixbuf. Common values are
- * 75, 90, and 300 DPI. Passing a number <= 0 to @dpi will
- * reset the DPI to whatever the default value happens to be.
- *
- * Since: 2.8
- */
-void
-rsvg_handle_set_dpi (RsvgHandle * handle, double dpi)
-{
- rsvg_handle_set_dpi_x_y (handle, dpi, dpi);
-}
-
-/**
- * rsvg_handle_set_dpi_x_y:
- * @handle: An #RsvgHandle
- * @dpi_x: Dots Per Inch (aka Pixels Per Inch)
- * @dpi_y: Dots Per Inch (aka Pixels Per Inch)
- *
- * Sets the DPI for the outgoing pixbuf. Common values are
- * 75, 90, and 300 DPI. Passing a number <= 0 to #dpi_x or @dpi_y will
- * reset the DPI to whatever the default value happens to be.
- *
- * Since: 2.8
- */
-void
-rsvg_handle_set_dpi_x_y (RsvgHandle * handle, double dpi_x, double dpi_y)
-{
- g_return_if_fail (handle != NULL);
-
- if (dpi_x <= 0.)
- handle->priv->dpi_x = rsvg_internal_dpi_x;
- else
- handle->priv->dpi_x = dpi_x;
-
- if (dpi_y <= 0.)
- handle->priv->dpi_y = rsvg_internal_dpi_y;
- else
- handle->priv->dpi_y = dpi_y;
-}
-
-/**
- * rsvg_handle_set_size_callback:
- * @handle: An #RsvgHandle
- * @size_func: (nullable): A sizing function, or %NULL
- * @user_data: User data to pass to @size_func, or %NULL
- * @user_data_destroy: Destroy function for @user_data, or %NULL
- *
- * Sets the sizing function for the @handle. This function is called right
- * after the size of the image has been loaded. The size of the image is passed
- * in to the function, which may then modify these values to set the real size
- * of the generated pixbuf. If the image has no associated size, then the size
- * arguments are set to -1.
- *
- * Deprecated: Set up a cairo matrix and use rsvg_handle_render_cairo() instead.
- * You can call rsvg_handle_get_dimensions() to figure out the size of your SVG,
- * and then scale it to the desired size via Cairo. For example, the following
- * code renders an SVG at a specified size, scaled proportionally from whatever
- * original size it may have had:
- *
- * |[<!-- language="C" -->
- * void
- * render_scaled_proportionally (RsvgHandle *handle, cairo_t cr, int width, int height)
- * {
- * RsvgDimensionData dimensions;
- * double x_factor, y_factor;
- * double scale_factor;
- *
- * rsvg_handle_get_dimensions (handle, &dimensions);
- *
- * x_factor = (double) width / dimensions.width;
- * y_factor = (double) height / dimensions.height;
- *
- * scale_factor = MIN (x_factor, y_factor);
- *
- * cairo_scale (cr, scale_factor, scale_factor);
- *
- * rsvg_handle_render_cairo (handle, cr);
- * }
- * ]|
- **/
-void
-rsvg_handle_set_size_callback (RsvgHandle * handle,
- RsvgSizeFunc size_func,
- gpointer user_data, GDestroyNotify user_data_destroy)
-{
- g_return_if_fail (handle != NULL);
-
- if (handle->priv->user_data_destroy)
- (*handle->priv->user_data_destroy) (handle->priv->user_data);
-
- handle->priv->size_func = size_func;
- handle->priv->user_data = user_data;
- handle->priv->user_data_destroy = user_data_destroy;
-}
-
#define GZ_MAGIC_0 ((guchar) 0x1f)
#define GZ_MAGIC_1 ((guchar) 0x8b)
@@ -1934,7 +1377,7 @@ rsvg_handle_write (RsvgHandle * handle, const guchar * buf, gsize count, GError
count--;
} else {
priv->state = RSVG_HANDLE_STATE_READING;
- return rsvg_handle_write_impl (handle, buf, count, error);
+ return write_impl (handle, buf, count, error);
}
break;
@@ -1947,7 +1390,7 @@ rsvg_handle_write (RsvgHandle * handle, const guchar * buf, gsize count, GError
count--;
} else {
priv->state = RSVG_HANDLE_STATE_READING;
- return rsvg_handle_write_impl (handle, buf, count, error);
+ return write_impl (handle, buf, count, error);
}
break;
@@ -1958,7 +1401,7 @@ rsvg_handle_write (RsvgHandle * handle, const guchar * buf, gsize count, GError
return TRUE;
case RSVG_HANDLE_STATE_READING:
- return rsvg_handle_write_impl (handle, buf, count, error);
+ return write_impl (handle, buf, count, error);
default:
g_assert_not_reached ();
@@ -2011,7 +1454,7 @@ rsvg_handle_close (RsvgHandle * handle, GError ** error)
return ret;
}
- result = rsvg_handle_close_impl (handle, error);
+ result = close_impl (handle, error);
if (result) {
priv->state = RSVG_HANDLE_STATE_CLOSED_OK;
@@ -2144,110 +1587,6 @@ rsvg_handle_read_stream_sync (RsvgHandle *handle,
}
/**
- * rsvg_handle_new_from_gfile_sync:
- * @file: a #GFile
- * @flags: flags from #RsvgHandleFlags
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- * @error: (allow-none): a location to store a #GError, or %NULL
- *
- * Creates a new #RsvgHandle for @file.
- *
- * If @cancellable is not %NULL, then the operation can be cancelled by
- * triggering the cancellable object from another thread. If the
- * operation was cancelled, the error %G_IO_ERROR_CANCELLED will be
- * returned.
- *
- * Returns: a new #RsvgHandle on success, or %NULL with @error filled in
- *
- * Since: 2.32
- */
-RsvgHandle *
-rsvg_handle_new_from_gfile_sync (GFile *file,
- RsvgHandleFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- RsvgHandle *handle;
- GFileInputStream *stream;
-
- g_return_val_if_fail (G_IS_FILE (file), NULL);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- stream = g_file_read (file, cancellable, error);
- if (stream == NULL)
- return NULL;
-
- handle = rsvg_handle_new_from_stream_sync (G_INPUT_STREAM (stream), file,
- flags, cancellable, error);
- g_object_unref (stream);
-
- return handle;
-}
-
-/**
- * rsvg_handle_new_from_stream_sync:
- * @input_stream: a #GInputStream
- * @base_file: (allow-none): a #GFile, or %NULL
- * @flags: flags from #RsvgHandleFlags
- * @cancellable: (allow-none): a #GCancellable, or %NULL
- * @error: (allow-none): a location to store a #GError, or %NULL
- *
- * Creates a new #RsvgHandle for @stream.
- *
- * If @cancellable is not %NULL, then the operation can be cancelled by
- * triggering the cancellable object from another thread. If the
- * operation was cancelled, the error %G_IO_ERROR_CANCELLED will be
- * returned.
- *
- * Returns: a new #RsvgHandle on success, or %NULL with @error filled in
- *
- * Since: 2.32
- */
-RsvgHandle *
-rsvg_handle_new_from_stream_sync (GInputStream *input_stream,
- GFile *base_file,
- RsvgHandleFlags flags,
- GCancellable *cancellable,
- GError **error)
-{
- RsvgHandle *handle;
-
- g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL);
- g_return_val_if_fail (base_file == NULL || G_IS_FILE (base_file), NULL);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- handle = rsvg_handle_new_with_flags (flags);
-
- if (base_file)
- rsvg_handle_set_base_gfile (handle, base_file);
-
- if (!rsvg_handle_read_stream_sync (handle, input_stream, cancellable, error)) {
- g_object_unref (handle);
- return NULL;
- }
-
- return handle;
-}
-
-/**
- * _rsvg_handle_internal_set_testing:
- * @handle: a #RsvgHandle
- * @testing: Whether to enable testing mode
- *
- * Do not call this function. This is intended for librsvg's internal
- * test suite only.
- **/
-void
-rsvg_handle_internal_set_testing (RsvgHandle *handle, gboolean testing)
-{
- g_return_if_fail (RSVG_IS_HANDLE (handle));
-
- handle->priv->is_testing = testing ? TRUE : FALSE;
-}
-
-/**
* rsvg_init:
*
* Initializes librsvg
@@ -2453,6 +1792,21 @@ rsvg_drawing_ctx_set_current_state_affine (RsvgDrawingCtx *ctx, cairo_matrix_t *
rsvg_current_state (ctx)->affine = *affine;
}
+PangoContext *
+rsvg_drawing_ctx_get_pango_context (RsvgDrawingCtx *draw_ctx)
+{
+ return draw_ctx->render->get_pango_context (draw_ctx);
+}
+
+void
+rsvg_drawing_ctx_render_pango_layout (RsvgDrawingCtx *draw_ctx,
+ PangoLayout *layout,
+ double x,
+ double y)
+{
+ draw_ctx->render->render_pango_layout (draw_ctx, layout, x, y);
+}
+
void
rsvg_render_path_builder (RsvgDrawingCtx * ctx, RsvgPathBuilder *builder)
{
@@ -2665,16 +2019,17 @@ rsvg_return_if_fail_warning (const char *pretty_function, const char *expression
g_set_error (error, RSVG_ERROR, 0, _("%s: assertion `%s' failed"), pretty_function, expression);
}
-static gboolean
-_rsvg_handle_allow_load (RsvgHandle *handle,
- const char *uri,
- GError **error)
+gboolean
+rsvg_allow_load (GFile *base_gfile,
+ const char *uri,
+ GError **error)
{
- RsvgHandlePrivate *priv = handle->priv;
GFile *base;
char *path, *dir;
char *scheme = NULL, *cpath = NULL, *cdir = NULL;
+ g_assert (error == NULL || *error == NULL);
+
scheme = g_uri_parse_scheme (uri);
/* Not a valid URI */
@@ -2686,11 +2041,11 @@ _rsvg_handle_allow_load (RsvgHandle *handle,
goto allow;
/* No base to compare to? */
- if (priv->base_gfile == NULL)
+ if (base_gfile == NULL)
goto deny;
/* Deny loads from differing URI schemes */
- if (!g_file_has_uri_scheme (priv->base_gfile, scheme))
+ if (!g_file_has_uri_scheme (base_gfile, scheme))
goto deny;
/* resource: is allowed to load anything from other resources */
@@ -2701,7 +2056,7 @@ _rsvg_handle_allow_load (RsvgHandle *handle,
if (!g_str_equal (scheme, "file"))
goto deny;
- base = g_file_get_parent (priv->base_gfile);
+ base = g_file_get_parent (base_gfile);
if (base == NULL)
goto deny;
@@ -2746,9 +2101,9 @@ _rsvg_handle_allow_load (RsvgHandle *handle,
return FALSE;
}
-static char *
-_rsvg_handle_resolve_uri (RsvgHandle *handle,
- const char *uri)
+char *
+rsvg_handle_resolve_uri (RsvgHandle *handle,
+ const char *uri)
{
RsvgHandlePrivate *priv = handle->priv;
char *scheme, *resolved_uri;
@@ -2782,12 +2137,13 @@ _rsvg_handle_acquire_data (RsvgHandle *handle,
gsize *len,
GError **error)
{
+ RsvgHandlePrivate *priv = handle->priv;
char *uri;
char *data;
- uri = _rsvg_handle_resolve_uri (handle, url);
+ uri = rsvg_handle_resolve_uri (handle, url);
- if (_rsvg_handle_allow_load (handle, uri, error)) {
+ if (rsvg_allow_load (priv->base_gfile, uri, error)) {
data = _rsvg_io_acquire_data (uri,
rsvg_handle_get_base_uri (handle),
content_type,
@@ -2808,12 +2164,13 @@ _rsvg_handle_acquire_stream (RsvgHandle *handle,
char **content_type,
GError **error)
{
+ RsvgHandlePrivate *priv = handle->priv;
char *uri;
GInputStream *stream;
- uri = _rsvg_handle_resolve_uri (handle, url);
+ uri = rsvg_handle_resolve_uri (handle, url);
- if (_rsvg_handle_allow_load (handle, uri, error)) {
+ if (rsvg_allow_load (priv->base_gfile, uri, error)) {
stream = _rsvg_io_acquire_stream (uri,
rsvg_handle_get_base_uri (handle),
content_type,
diff --git a/rsvg-cairo-clip.c b/rsvg-cairo-clip.c
index 0f485ead..b1905a5b 100644
--- a/rsvg-cairo-clip.c
+++ b/rsvg-cairo-clip.c
@@ -151,7 +151,7 @@ rsvg_cairo_clip_render_new (cairo_t *cr, RsvgCairoRender *parent)
render->type = RSVG_RENDER_TYPE_CAIRO_CLIP;
render->free = rsvg_cairo_clip_render_free;
- render->create_pango_context = rsvg_cairo_create_pango_context;
+ render->get_pango_context = rsvg_cairo_get_pango_context;
render->render_pango_layout = rsvg_cairo_clip_render_pango_layout;
render->render_path_builder = rsvg_cairo_clip_render_path_builder;
render->render_surface = rsvg_cairo_clip_render_surface;
@@ -182,15 +182,15 @@ rsvg_cairo_clip_render_new (cairo_t *cr, RsvgCairoRender *parent)
void
rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgNode *node_clip_path, RsvgBbox * bbox)
{
- RsvgClipPath *clip;
RsvgCairoClipRender *clip_render;
RsvgCairoRender *save = RSVG_CAIRO_RENDER (ctx->render);
cairo_matrix_t affinesave;
RsvgState *clip_path_state;
cairo_t *cr;
+ RsvgCoordUnits clip_units;
g_assert (rsvg_node_get_type (node_clip_path) == RSVG_NODE_TYPE_CLIP_PATH);
- clip = rsvg_rust_cnode_get_impl (node_clip_path);
+ clip_units = rsvg_node_clip_path_get_units (node_clip_path);
cr = save->cr;
clip_render = RSVG_CAIRO_CLIP_RENDER (rsvg_cairo_clip_render_new (cr, save));
@@ -199,7 +199,7 @@ rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgNode *node_clip_path, RsvgBbox * bbox
clip_path_state = rsvg_node_get_state (node_clip_path);
/* Horribly dirty hack to have the bbox premultiplied to everything */
- if (clip->units == objectBoundingBox) {
+ if (clip_units == objectBoundingBox) {
cairo_matrix_t bbtransform;
cairo_matrix_init (&bbtransform,
bbox->rect.width,
@@ -216,7 +216,7 @@ rsvg_cairo_clip (RsvgDrawingCtx * ctx, RsvgNode *node_clip_path, RsvgBbox * bbox
rsvg_node_draw_children (node_clip_path, ctx, 0);
rsvg_state_pop (ctx);
- if (clip->units == objectBoundingBox)
+ if (clip_units == objectBoundingBox)
clip_path_state->affine = affinesave;
g_assert (clip_render->super.cr_stack == NULL);
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index d456a6bd..f16a39a4 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -158,15 +158,24 @@ set_font_options_for_testing (PangoContext *context)
static void
create_font_config_for_testing (RsvgCairoRender *render)
{
- const char *font_path = SRCDIR "/tests/resources/LiberationSans-Regular.ttf";
+ const char *font_paths[] = {
+ SRCDIR "/tests/resources/Roboto-Regular.ttf",
+ SRCDIR "/tests/resources/Roboto-Italic.ttf",
+ SRCDIR "/tests/resources/Roboto-Bold.ttf",
+ SRCDIR "/tests/resources/Roboto-BoldItalic.ttf",
+ };
+
+ int i;
if (render->font_config_for_testing != NULL)
return;
render->font_config_for_testing = FcConfigCreate ();
- if (!FcConfigAppFontAddFile (render->font_config_for_testing, (const FcChar8 *) font_path)) {
- g_error ("Could not load font file \"%s\" for tests; aborting", font_path);
+ for (i = 0; i < G_N_ELEMENTS(font_paths); i++) {
+ if (!FcConfigAppFontAddFile (render->font_config_for_testing, (const FcChar8 *) font_paths[i])) {
+ g_error ("Could not load font file \"%s\" for tests; aborting", font_paths[i]);
+ }
}
}
@@ -186,7 +195,7 @@ get_font_map_for_testing (RsvgCairoRender *render)
#endif
PangoContext *
-rsvg_cairo_create_pango_context (RsvgDrawingCtx * ctx)
+rsvg_cairo_get_pango_context (RsvgDrawingCtx * ctx)
{
PangoFontMap *fontmap;
PangoContext *context;
@@ -349,7 +358,7 @@ rsvg_cairo_render_path_builder (RsvgDrawingCtx * ctx, RsvgPathBuilder *builder)
* viewports/clipping, and one for user applications like a
* rsvg_compute_ink_rect() function in the future.
*
- * See https://bugzilla.gnome.org/show_bug.cgi?id=760112 for discussion of a
+ * See https://gitlab.gnome.org/GNOME/librsvg/issues/128 for discussion of a
* public API to get the ink rectangle.
*/
@@ -518,7 +527,7 @@ rsvg_cairo_set_cairo_context (RsvgDrawingCtx *ctx, cairo_t *cr)
}
static void
-rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *node_mask, RsvgDrawingCtx *ctx, RsvgBbox *bbox)
+rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *mask, RsvgDrawingCtx *ctx, RsvgBbox *bbox)
{
RsvgCairoRender *render = RSVG_CAIRO_RENDER (ctx->render);
cairo_surface_t *surface;
@@ -528,12 +537,13 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *node_mask, RsvgDrawingCtx *ctx
guint32 width = render->width, height = render->height;
guint32 rowstride = width * 4, row, i;
cairo_matrix_t affinesave;
+ RsvgLength mask_x, mask_y, mask_w, mask_h;
double sx, sy, sw, sh;
gboolean nest = cr != render->initial_cr;
- RsvgMask *self;
+ RsvgCoordUnits mask_units;
+ RsvgCoordUnits content_units;
- g_assert (rsvg_node_get_type (node_mask) == RSVG_NODE_TYPE_MASK);
- self = rsvg_rust_cnode_get_impl (node_mask);
+ g_assert (rsvg_node_get_type (mask) == RSVG_NODE_TYPE_MASK);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
@@ -544,22 +554,30 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *node_mask, RsvgDrawingCtx *ctx
pixels = cairo_image_surface_get_data (surface);
rowstride = cairo_image_surface_get_stride (surface);
- if (self->maskunits == objectBoundingBox)
+ mask_units = rsvg_node_mask_get_units (mask);
+ content_units = rsvg_node_mask_get_content_units (mask);
+
+ if (mask_units == objectBoundingBox)
rsvg_drawing_ctx_push_view_box (ctx, 1, 1);
- sx = rsvg_length_normalize (&self->x, ctx);
- sy = rsvg_length_normalize (&self->y, ctx);
- sw = rsvg_length_normalize (&self->width, ctx);
- sh = rsvg_length_normalize (&self->height, ctx);
+ mask_x = rsvg_node_mask_get_x (mask);
+ mask_y = rsvg_node_mask_get_y (mask);
+ mask_w = rsvg_node_mask_get_width (mask);
+ mask_h = rsvg_node_mask_get_height (mask);
- if (self->maskunits == objectBoundingBox)
+ sx = rsvg_length_normalize (&mask_x, ctx);
+ sy = rsvg_length_normalize (&mask_y, ctx);
+ sw = rsvg_length_normalize (&mask_w, ctx);
+ sh = rsvg_length_normalize (&mask_h, ctx);
+
+ if (mask_units == objectBoundingBox)
rsvg_drawing_ctx_pop_view_box (ctx);
mask_cr = cairo_create (surface);
save_cr = render->cr;
render->cr = mask_cr;
- if (self->maskunits == objectBoundingBox)
+ if (mask_units == objectBoundingBox)
rsvg_cairo_add_clipping_rect (ctx,
sx * bbox->rect.width + bbox->rect.x,
sy * bbox->rect.height + bbox->rect.y,
@@ -569,7 +587,7 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *node_mask, RsvgDrawingCtx *ctx
rsvg_cairo_add_clipping_rect (ctx, sx, sy, sw, sh);
/* Horribly dirty hack to have the bbox premultiplied to everything */
- if (self->contentunits == objectBoundingBox) {
+ if (content_units == objectBoundingBox) {
cairo_matrix_t bbtransform;
RsvgState *mask_state;
@@ -581,7 +599,7 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *node_mask, RsvgDrawingCtx *ctx
bbox->rect.x,
bbox->rect.y);
- mask_state = rsvg_node_get_state (node_mask);
+ mask_state = rsvg_node_get_state (mask);
affinesave = mask_state->affine;
cairo_matrix_multiply (&mask_state->affine, &bbtransform, &mask_state->affine);
@@ -589,15 +607,15 @@ rsvg_cairo_generate_mask (cairo_t * cr, RsvgNode *node_mask, RsvgDrawingCtx *ctx
}
rsvg_state_push (ctx);
- rsvg_node_draw_children (node_mask, ctx, 0);
+ rsvg_node_draw_children (mask, ctx, 0);
rsvg_state_pop (ctx);
- if (self->contentunits == objectBoundingBox) {
+ if (content_units == objectBoundingBox) {
RsvgState *mask_state;
rsvg_drawing_ctx_pop_view_box (ctx);
- mask_state = rsvg_node_get_state (node_mask);
+ mask_state = rsvg_node_get_state (mask);
mask_state->affine = affinesave;
}
@@ -655,9 +673,7 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx * ctx)
RsvgNode *node;
node = rsvg_drawing_ctx_acquire_node_of_type (ctx, rsvg_current_state (ctx)->clip_path, RSVG_NODE_TYPE_CLIP_PATH);
if (node) {
- RsvgClipPath *clip_path = rsvg_rust_cnode_get_impl (node);
-
- switch (clip_path->units) {
+ switch (rsvg_node_clip_path_get_units (node)) {
case userSpaceOnUse:
rsvg_cairo_clip (ctx, node, NULL);
break;
@@ -733,9 +749,7 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx * ctx)
RsvgNode *node;
node = rsvg_drawing_ctx_acquire_node_of_type (ctx, rsvg_current_state (ctx)->clip_path, RSVG_NODE_TYPE_CLIP_PATH);
if (node) {
- RsvgClipPath *cp = rsvg_rust_cnode_get_impl (node);
-
- if (cp->units == objectBoundingBox) {
+ if (rsvg_node_clip_path_get_units (node) == objectBoundingBox) {
lateclip = node;
} else {
rsvg_drawing_ctx_release_node (ctx, node);
diff --git a/rsvg-cairo-draw.h b/rsvg-cairo-draw.h
index cbf8dbc8..05b0d8b4 100644
--- a/rsvg-cairo-draw.h
+++ b/rsvg-cairo-draw.h
@@ -33,7 +33,7 @@
G_BEGIN_DECLS
G_GNUC_INTERNAL
-PangoContext *rsvg_cairo_create_pango_context (RsvgDrawingCtx *ctx);
+PangoContext *rsvg_cairo_get_pango_context (RsvgDrawingCtx *ctx);
G_GNUC_INTERNAL
void rsvg_cairo_render_pango_layout (RsvgDrawingCtx *ctx, PangoLayout *layout,
double x, double y);
diff --git a/rsvg-cairo-render.c b/rsvg-cairo-render.c
index 892fd03d..fc567ede 100644
--- a/rsvg-cairo-render.c
+++ b/rsvg-cairo-render.c
@@ -73,7 +73,7 @@ rsvg_cairo_render_new (cairo_t * cr, double width, double height)
cairo_render->super.type = RSVG_RENDER_TYPE_CAIRO;
cairo_render->super.free = rsvg_cairo_render_free;
- cairo_render->super.create_pango_context = rsvg_cairo_create_pango_context;
+ cairo_render->super.get_pango_context = rsvg_cairo_get_pango_context;
cairo_render->super.render_pango_layout = rsvg_cairo_render_pango_layout;
cairo_render->super.render_surface = rsvg_cairo_render_surface;
cairo_render->super.render_path_builder = rsvg_cairo_render_path_builder;
diff --git a/rsvg-convert.c b/rsvg-convert.c
index 9770f5c8..ef4ead6a 100644
--- a/rsvg-convert.c
+++ b/rsvg-convert.c
@@ -44,6 +44,7 @@
#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+#include <fcntl.h>
#include <gio/gwin32inputstream.h>
#endif
@@ -211,14 +212,22 @@ main (int argc, char **argv)
g_free (output);
}
+#ifdef G_OS_WIN32
+ else {
+ setmode (fileno (stdout), O_BINARY);
+ }
+#endif
if (args)
while (args[n_args] != NULL)
n_args++;
if (n_args == 0) {
+ const gchar * const stdin_args[] = { "stdin", NULL };
n_args = 1;
using_stdin = TRUE;
+ g_strfreev (args);
+ args = g_strdupv ((gchar **) stdin_args);
} else if (n_args > 1 && (!format || !(!strcmp (format, "ps") || !strcmp (format, "eps") || !strcmp (format, "pdf")))) {
g_printerr (_("Multiple SVG files are only allowed for PDF and (E)PS output.\n"));
exit (1);
diff --git a/rsvg-css.h b/rsvg-css.h
index 74c32201..088521da 100644
--- a/rsvg-css.h
+++ b/rsvg-css.h
@@ -35,19 +35,6 @@
G_BEGIN_DECLS
-#define RSVG_ASPECT_RATIO_NONE (0)
-#define RSVG_ASPECT_RATIO_XMIN_YMIN (1 << 0)
-#define RSVG_ASPECT_RATIO_XMID_YMIN (1 << 1)
-#define RSVG_ASPECT_RATIO_XMAX_YMIN (1 << 2)
-#define RSVG_ASPECT_RATIO_XMIN_YMID (1 << 3)
-#define RSVG_ASPECT_RATIO_XMID_YMID (1 << 4)
-#define RSVG_ASPECT_RATIO_XMAX_YMID (1 << 5)
-#define RSVG_ASPECT_RATIO_XMIN_YMAX (1 << 6)
-#define RSVG_ASPECT_RATIO_XMID_YMAX (1 << 7)
-#define RSVG_ASPECT_RATIO_XMAX_YMAX (1 << 8)
-#define RSVG_ASPECT_RATIO_SLICE (1 << 30)
-#define RSVG_ASPECT_RATIO_DEFER (1 << 31)
-
/* Keep this in sync with rust/src/color.rs:ColorKind */
typedef enum {
RSVG_CSS_COLOR_SPEC_INHERIT,
@@ -102,20 +89,6 @@ typedef struct {
G_GNUC_INTERNAL
RsvgOpacitySpec rsvg_css_parse_opacity (const char *str);
-/* This is implemented in rust/src/aspect_ratio.rs */
-G_GNUC_INTERNAL
-guint32 rsvg_aspect_ratio_parse (const char *str);
-
-/* This is implemented in rust/src/aspect_ratio.rs */
-G_GNUC_INTERNAL
-void rsvg_aspect_ratio_compute (guint32 aspect,
- double object_width,
- double object_height,
- double *dest_x,
- double *dest_y,
- double *dest_width,
- double *dest_height);
-
G_GNUC_INTERNAL
PangoStyle rsvg_css_parse_font_style (const char *str, gboolean * inherit);
G_GNUC_INTERNAL
diff --git a/rsvg-defs.c b/rsvg-defs.c
index efe7acd8..e74e1155 100644
--- a/rsvg-defs.c
+++ b/rsvg-defs.c
@@ -50,52 +50,50 @@ rsvg_defs_new (RsvgHandle *handle)
return result;
}
-static int
-rsvg_defs_load_extern (const RsvgDefs * defs, const char *name)
+static RsvgHandle *
+rsvg_defs_load_extern (const RsvgDefs * defs, const char *uri)
{
- RsvgHandle *handle;
- gchar *filename, *base_uri;
+ RsvgHandle *handle = NULL;
char *data;
gsize data_len;
- gboolean rv;
-
- filename = _rsvg_io_get_file_path (name, rsvg_handle_get_base_uri (defs->ctx));
- data = _rsvg_handle_acquire_data (defs->ctx, name, NULL, &data_len, NULL);
+ data = _rsvg_handle_acquire_data (defs->ctx, uri, NULL, &data_len, NULL);
if (data) {
handle = rsvg_handle_new ();
-
- base_uri = rsvg_get_base_uri_from_filename (filename);
- rsvg_handle_set_base_uri (handle, base_uri);
- g_free (base_uri);
-
- rv = rsvg_handle_write (handle, (guchar *) data, data_len, NULL);
- rv = rsvg_handle_close (handle, NULL) && rv;
- if (rv) {
- g_hash_table_insert (defs->externs, g_strdup (name), handle);
+ rsvg_handle_set_base_uri (handle, uri);
+
+ if (rsvg_handle_write (handle, (guchar *) data, data_len, NULL)
+ && rsvg_handle_close (handle, NULL)) {
+ g_hash_table_insert (defs->externs, g_strdup (uri), handle);
+ } else {
+ g_object_unref (handle);
+ handle = NULL;
}
g_free (data);
}
- g_free (filename);
- return 0;
+ return handle;
}
static RsvgNode *
-rsvg_defs_extern_lookup (const RsvgDefs * defs, const char *filename, const char *name)
+rsvg_defs_extern_lookup (const RsvgDefs * defs, const char *possibly_relative_uri, const char *name)
{
- RsvgHandle *file;
- file = (RsvgHandle *) g_hash_table_lookup (defs->externs, filename);
- if (file == NULL) {
- if (rsvg_defs_load_extern (defs, filename))
- return NULL;
- file = (RsvgHandle *) g_hash_table_lookup (defs->externs, filename);
+ RsvgHandle *handle;
+ char *uri;
+
+ uri = rsvg_handle_resolve_uri (defs->ctx, possibly_relative_uri);
+ if (!uri)
+ return NULL;
+
+ handle = (RsvgHandle *) g_hash_table_lookup (defs->externs, uri);
+ if (handle == NULL) {
+ handle = rsvg_defs_load_extern (defs, uri);
}
- if (file != NULL)
- return g_hash_table_lookup (file->priv->defs->hash, name);
+ if (handle != NULL)
+ return g_hash_table_lookup (handle->priv->defs->hash, name);
else
return NULL;
}
diff --git a/rsvg-filter.c b/rsvg-filter.c
index 07f8d594..04342851 100644
--- a/rsvg-filter.c
+++ b/rsvg-filter.c
@@ -103,8 +103,13 @@ rsvg_filter_primitive_free (gpointer impl)
{
RsvgFilterPrimitive *primitive = impl;
- g_string_free (primitive->in, TRUE);
- g_string_free (primitive->result, TRUE);
+ if (primitive->in) {
+ g_string_free (primitive->in, TRUE);
+ }
+
+ if (primitive->result) {
+ g_string_free (primitive->result, TRUE);
+ }
g_free (primitive);
}
@@ -972,7 +977,7 @@ rsvg_filter_blend (RsvgFilterPrimitiveBlendMode mode,
cr = bca + bcb - 2 * bca * bcb;
break;
case difference:
- cr = abs (bca - bcb);
+ cr = fabs (bca - bcb);
break;
}
cr *= 255.0;
diff --git a/rsvg-gobject.c b/rsvg-gobject.c
deleted file mode 100644
index a211bf74..00000000
--- a/rsvg-gobject.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set sw=4 sts=4 expandtab: */
-/*
- rsvg-gobject.c: GObject support.
-
- Copyright (C) 2006 Robert Staudinger <robert.staudinger@gmail.com>
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-*/
-
-/**
- * SECTION: rsvg-handle
- * @short_description: Loads SVG data into memory.
- *
- * This is the main entry point into the librsvg library. An RsvgHandle is an
- * object that represents SVG data in memory. Your program creates an
- * RsvgHandle from an SVG file, or from a memory buffer that contains SVG data,
- * or in the most general form, from a #GInputStream that will provide SVG data.
- *
- * Librsvg supports reading <link
- * xlink:href="https://www.w3.org/TR/SVG/">SVG 1.1</link> data. It also
- * supports SVGZ files, which is just an SVG stream compressed with the GZIP
- * algorithm.
- *
- * # The "base file" and resolving references to external files
- *
- * When you load an SVG, librsvg needs to know the location of the "base file"
- * for it. This is so that librsvg can determine the location of referenced
- * entities. For example, say you have an SVG in <filename>/foo/bar/foo.svg</filename>
- * and that it has an image element like this:
- *
- * |[
- * <image xlink:href="resources/foo.png" .../>
- * ]|
- *
- * In this case, librsvg needs to know the location of the toplevel
- * <filename>/foo/bar/foo.svg</filename> so that it can generate the appropriate
- * reference to <filename>/foo/bar/resources/foo.png</filename>.
- *
- * ## Security and locations of referenced files
- *
- * When processing an SVG, librsvg will only load referenced files if they are
- * in the same directory as the base file, or in a subdirectory of it. That is,
- * if the base file is <filename>/foo/bar/baz.svg</filename>, then librsvg will
- * only try to load referenced files (from SVG's "image" element, for example,
- * or from content included through XML entities) if those files are in
- * <filename>/foo/bar/<!-- -->*</filename> or in
- * <filename>/foo/bar/<!-- -->*<!-- -->/.../<!-- -->*</filename>. This is so that malicious
- * SVG files cannot include files that are in a directory above.
- *
- * # Loading an SVG with GIO
- *
- * If you have a #GFile that stands for an SVG file, you can simply call
- * rsvg_handle_new_from_gfile_sync() to load an RsvgHandle from it.
- *
- * Alternatively, if you have a #GInputStream, you can use
- * rsvg_handle_new_from_stream_sync().
- *
- * Both of those methods allow specifying a #GCancellable, so the loading
- * process can be cancelled from another thread.
- *
- * # Loading an SVG without GIO
- *
- * You can load an RsvgHandle from a simple filename or URI with
- * rsvg_handle_new_from_file(). Note that this is a blocking operation; there
- * is no way to cancel it if loading a remote URI takes a long time.
- *
- * Alternatively, you can create an empty RsvgHandle with rsvg_handle_new() or
- * rsvg_handle_new_with_flags(). The first function is equivalent to using
- * #RSVG_HANDLE_FLAGS_NONE on the second one. These functions give you back an
- * empty RsvgHandle, which is ready for you to feed it SVG data. You can do
- * this with rsvg_handle_write() and rsvg_handle_close().
- *
- * # Resolution of the rendered image (dots per inch, or DPI)
- *
- * SVG images can contain dimensions like "<literal>5 cm</literal>" or
- * "<literal>2 pt</literal>" that must be converted from physical units
- * into device units. To do this, librsvg needs to know the actual dots per
- * inch (DPI) of your target device.
- *
- * The recommended way to set the DPI is to use rsvg_handle_set_dpi() or
- * rsvg_handle_set_dpi_x_y() on an RsvgHandle before rendering it.
- *
- * Alternatively, you can use rsvg_set_default_dpi() or
- * rsvg_set_default_dpi_x_y() <emphasis>before</emphasis> creating any
- * RsvgHandle objects. These functions will make RsvgHandle objects created
- * afterwards to have the default DPI value you specified.
- *
- * # Rendering
- *
- * The preferred way to render an already-loaded RsvgHandle is to use
- * rsvg_handle_render_cairo(). Please see its documentation for details.
- *
- * Alternatively, you can use rsvg_handle_get_pixbuf() to directly obtain a
- * #GdkPixbuf with the rendered image. This is simple, but it does not let you
- * control the size at which the SVG will be rendered. It will just be rendered
- * at the size which rsvg_handle_get_dimensions() would return, which depends on
- * the dimensions that librsvg is able to compute from the SVG data.
- */
-
-#include "config.h"
-
-#include "rsvg-private.h"
-#include "rsvg-defs.h"
-
-enum {
- PROP_0,
- PROP_FLAGS,
- PROP_DPI_X,
- PROP_DPI_Y,
- PROP_BASE_URI,
- PROP_WIDTH,
- PROP_HEIGHT,
- PROP_EM,
- PROP_EX,
- PROP_TITLE,
- PROP_DESC,
- PROP_METADATA,
- NUM_PROPS
-};
-
-extern double rsvg_internal_dpi_x;
-extern double rsvg_internal_dpi_y;
-
-G_DEFINE_TYPE (RsvgHandle, rsvg_handle, G_TYPE_OBJECT)
-
-static void
-rsvg_handle_init (RsvgHandle * self)
-{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, RSVG_TYPE_HANDLE, RsvgHandlePrivate);
-
- self->priv->flags = RSVG_HANDLE_FLAGS_NONE;
- self->priv->state = RSVG_HANDLE_STATE_START;
- self->priv->all_nodes = g_ptr_array_new ();
- self->priv->defs = rsvg_defs_new (self);
- self->priv->handler_nest = 0;
- self->priv->entities = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) xmlFreeNode);
- self->priv->dpi_x = rsvg_internal_dpi_x;
- self->priv->dpi_y = rsvg_internal_dpi_y;
-
- self->priv->css_props = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) g_hash_table_destroy);
-
- self->priv->ctxt = NULL;
- self->priv->currentnode = NULL;
- self->priv->treebase = NULL;
- self->priv->element_name_stack = NULL;
-
- self->priv->compressed_input_stream = NULL;
- self->priv->cancellable = NULL;
-
- self->priv->is_disposed = FALSE;
- self->priv->in_loop = FALSE;
-
- self->priv->is_testing = FALSE;
-}
-
-static void
-free_nodes (RsvgHandle *self)
-{
- int i;
-
- g_assert (self->priv->all_nodes != NULL);
-
- for (i = 0; i < self->priv->all_nodes->len; i++) {
- RsvgNode *node;
-
- node = g_ptr_array_index (self->priv->all_nodes, i);
- node = rsvg_node_unref (node);
- }
-
- g_ptr_array_free (self->priv->all_nodes, TRUE);
- self->priv->all_nodes = NULL;
-}
-
-static void
-rsvg_handle_dispose (GObject *instance)
-{
- RsvgHandle *self = (RsvgHandle *) instance;
-
- if (self->priv->is_disposed)
- goto chain;
-
- self->priv->is_disposed = TRUE;
-
- self->priv->ctxt = rsvg_free_xml_parser_and_doc (self->priv->ctxt);
-
- g_hash_table_destroy (self->priv->entities);
-
- free_nodes (self);
-
- rsvg_defs_free (self->priv->defs);
- self->priv->defs = NULL;
-
- g_hash_table_destroy (self->priv->css_props);
-
- self->priv->treebase = rsvg_node_unref (self->priv->treebase);
- self->priv->currentnode = rsvg_node_unref (self->priv->currentnode);
-
- if (self->priv->user_data_destroy)
- (*self->priv->user_data_destroy) (self->priv->user_data);
-
- if (self->priv->title)
- g_string_free (self->priv->title, TRUE);
- if (self->priv->desc)
- g_string_free (self->priv->desc, TRUE);
- if (self->priv->metadata)
- g_string_free (self->priv->metadata, TRUE);
- if (self->priv->base_uri)
- g_free (self->priv->base_uri);
-
- if (self->priv->base_gfile) {
- g_object_unref (self->priv->base_gfile);
- self->priv->base_gfile = NULL;
- }
- if (self->priv->compressed_input_stream) {
- g_object_unref (self->priv->compressed_input_stream);
- self->priv->compressed_input_stream = NULL;
- }
-
- g_clear_object (&self->priv->cancellable);
-
- chain:
- G_OBJECT_CLASS (rsvg_handle_parent_class)->dispose (instance);
-}
-
-static void
-rsvg_handle_set_property (GObject * instance, guint prop_id, GValue const *value, GParamSpec * pspec)
-{
- RsvgHandle *self = RSVG_HANDLE (instance);
-
- switch (prop_id) {
- case PROP_FLAGS:
- self->priv->flags = g_value_get_flags (value);
- break;
- case PROP_DPI_X:
- rsvg_handle_set_dpi_x_y (self, g_value_get_double (value), self->priv->dpi_y);
- break;
- case PROP_DPI_Y:
- rsvg_handle_set_dpi_x_y (self, self->priv->dpi_x, g_value_get_double (value));
- break;
- case PROP_BASE_URI:
- rsvg_handle_set_base_uri (self, g_value_get_string (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (instance, prop_id, pspec);
- }
-}
-
-static void
-rsvg_handle_get_property (GObject * instance, guint prop_id, GValue * value, GParamSpec * pspec)
-{
- RsvgHandle *self = RSVG_HANDLE (instance);
- RsvgDimensionData dim;
-
- switch (prop_id) {
- case PROP_FLAGS:
- g_value_set_flags (value, self->priv->flags);
- break;
- case PROP_DPI_X:
- g_value_set_double (value, self->priv->dpi_x);
- break;
- case PROP_DPI_Y:
- g_value_set_double (value, self->priv->dpi_y);
- break;
- case PROP_BASE_URI:
- g_value_set_string (value, rsvg_handle_get_base_uri (self));
- break;
- case PROP_WIDTH:
- rsvg_handle_get_dimensions (self, &dim);
- g_value_set_int (value, dim.width);
- break;
- case PROP_HEIGHT:
- rsvg_handle_get_dimensions (self, &dim);
- g_value_set_int (value, dim.height);
- break;
- case PROP_EM:
- rsvg_handle_get_dimensions (self, &dim);
- g_value_set_double (value, dim.em);
- break;
- case PROP_EX:
- rsvg_handle_get_dimensions (self, &dim);
- g_value_set_double (value, dim.ex);
- break;
- case PROP_TITLE:
- g_value_set_string (value, rsvg_handle_get_title (self));
- break;
- case PROP_DESC:
- g_value_set_string (value, rsvg_handle_get_desc (self));
- break;
- case PROP_METADATA:
- g_value_set_string (value, rsvg_handle_get_metadata (self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (instance, prop_id, pspec);
- }
-}
-
-static void
-rsvg_handle_class_init (RsvgHandleClass * klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->dispose = rsvg_handle_dispose;
- gobject_class->set_property = rsvg_handle_set_property;
- gobject_class->get_property = rsvg_handle_get_property;
-
- /**
- * RsvgHandle:flags:
- *
- * Flags from #RsvgHandleFlags.
- *
- * Since: 2.36
- */
- g_object_class_install_property (gobject_class,
- PROP_FLAGS,
- g_param_spec_flags ("flags", NULL, NULL,
- RSVG_TYPE_HANDLE_FLAGS,
- RSVG_HANDLE_FLAGS_NONE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- /**
- * dpi-x:
- */
- g_object_class_install_property (gobject_class,
- PROP_DPI_X,
- g_param_spec_double ("dpi-x", _("Horizontal resolution"),
- _("Horizontal resolution"), 0.,
- G_MAXDOUBLE, rsvg_internal_dpi_x,
- (GParamFlags) (G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT)));
-
- g_object_class_install_property (gobject_class,
- PROP_DPI_Y,
- g_param_spec_double ("dpi-y", _("Vertical resolution"),
- _("Vertical resolution"), 0., G_MAXDOUBLE,
- rsvg_internal_dpi_y,
- (GParamFlags) (G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT)));
-
- g_object_class_install_property (gobject_class,
- PROP_BASE_URI,
- g_param_spec_string ("base-uri", _("Base URI"),
- _("Base URI"), NULL,
- (GParamFlags) (G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT)));
-
- g_object_class_install_property (gobject_class,
- PROP_WIDTH,
- g_param_spec_int ("width", _("Image width"),
- _("Image width"), 0, G_MAXINT, 0,
- (GParamFlags) (G_PARAM_READABLE)));
-
- g_object_class_install_property (gobject_class,
- PROP_HEIGHT,
- g_param_spec_int ("height", _("Image height"),
- _("Image height"), 0, G_MAXINT, 0,
- (GParamFlags) (G_PARAM_READABLE)));
-
- g_object_class_install_property (gobject_class,
- PROP_EM,
- g_param_spec_double ("em", _("em"),
- _("em"), 0, G_MAXDOUBLE, 0,
- (GParamFlags) (G_PARAM_READABLE)));
-
- g_object_class_install_property (gobject_class,
- PROP_EX,
- g_param_spec_double ("ex", _("ex"),
- _("ex"), 0, G_MAXDOUBLE, 0,
- (GParamFlags) (G_PARAM_READABLE)));
-
- /**
- * RsvgHandle:title:
- *
- * SVG's description
- *
- * Deprecated: 2.36
- */
- g_object_class_install_property (gobject_class,
- PROP_TITLE,
- g_param_spec_string ("title", _("Title"),
- _("SVG file title"), NULL,
- (GParamFlags) (G_PARAM_READABLE)));
-
- /**
- * RsvgHandle:desc:
- *
- * SVG's description
- *
- * Deprecated: 2.36
- */
- g_object_class_install_property (gobject_class,
- PROP_DESC,
- g_param_spec_string ("desc", _("Description"),
- _("SVG file description"), NULL,
- (GParamFlags) (G_PARAM_READABLE)));
-
- /**
- * RsvgHandle:metadata:
- *
- * SVG's description
- *
- * Deprecated: 2.36
- */
- g_object_class_install_property (gobject_class,
- PROP_METADATA,
- g_param_spec_string ("metadata", _("Metadata"),
- _("SVG file metadata"), NULL,
- (GParamFlags) (G_PARAM_READABLE)));
-
- g_type_class_add_private (klass, sizeof (RsvgHandlePrivate));
-
- xmlInitParser ();
-
- rsvg_SAX_handler_struct_init ();
-}
-
-/**
- * rsvg_handle_free:
- * @handle: An #RsvgHandle
- *
- * Frees @handle.
- * Deprecated: Use g_object_unref() instead.
- **/
-void
-rsvg_handle_free (RsvgHandle * handle)
-{
- g_object_unref (handle);
-}
-
-/**
- * rsvg_handle_new:
- *
- * Returns a new rsvg handle. Must be freed with @g_object_unref. This
- * handle can be used for dynamically loading an image. You need to feed it
- * data using @rsvg_handle_write, then call @rsvg_handle_close when done.
- * Afterwords, you can render it using Cairo or get a GdkPixbuf from it. When
- * finished, free with g_object_unref(). No more than one image can be loaded
- * with one handle.
- *
- * Returns: A new #RsvgHandle
- **/
-RsvgHandle *
-rsvg_handle_new (void)
-{
- return RSVG_HANDLE (g_object_new (RSVG_TYPE_HANDLE, NULL));
-}
-
-
-/**
- * rsvg_handle_new_with_flags:
- * @flags: flags from #RsvgHandleFlags
- *
- * Creates a new #RsvgHandle with flags @flags.
- *
- * Returns: (transfer full): a new #RsvgHandle
- *
- * Since: 2.36
- **/
-RsvgHandle *
-rsvg_handle_new_with_flags (RsvgHandleFlags flags)
-{
- return g_object_new (RSVG_TYPE_HANDLE,
- "flags", flags,
- NULL);
-}
diff --git a/rsvg-handle.c b/rsvg-handle.c
new file mode 100644
index 00000000..1083f813
--- /dev/null
+++ b/rsvg-handle.c
@@ -0,0 +1,1135 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set sw=4 sts=4 expandtab: */
+/*
+ rsvg-gobject.c: GObject support.
+
+ Copyright (C) 2006 Robert Staudinger <robert.staudinger@gmail.com>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * SECTION: rsvg-handle
+ * @short_description: Loads SVG data into memory.
+ *
+ * This is the main entry point into the librsvg library. An RsvgHandle is an
+ * object that represents SVG data in memory. Your program creates an
+ * RsvgHandle from an SVG file, or from a memory buffer that contains SVG data,
+ * or in the most general form, from a #GInputStream that will provide SVG data.
+ *
+ * Librsvg supports reading <link
+ * xlink:href="https://www.w3.org/TR/SVG/">SVG 1.1</link> data. It also
+ * supports SVGZ files, which is just an SVG stream compressed with the GZIP
+ * algorithm.
+ *
+ * # The "base file" and resolving references to external files
+ *
+ * When you load an SVG, librsvg needs to know the location of the "base file"
+ * for it. This is so that librsvg can determine the location of referenced
+ * entities. For example, say you have an SVG in <filename>/foo/bar/foo.svg</filename>
+ * and that it has an image element like this:
+ *
+ * |[
+ * <image xlink:href="resources/foo.png" .../>
+ * ]|
+ *
+ * In this case, librsvg needs to know the location of the toplevel
+ * <filename>/foo/bar/foo.svg</filename> so that it can generate the appropriate
+ * reference to <filename>/foo/bar/resources/foo.png</filename>.
+ *
+ * ## Security and locations of referenced files
+ *
+ * When processing an SVG, librsvg will only load referenced files if they are
+ * in the same directory as the base file, or in a subdirectory of it. That is,
+ * if the base file is <filename>/foo/bar/baz.svg</filename>, then librsvg will
+ * only try to load referenced files (from SVG's "image" element, for example,
+ * or from content included through XML entities) if those files are in
+ * <filename>/foo/bar/<!-- -->*</filename> or in
+ * <filename>/foo/bar/<!-- -->*<!-- -->/.../<!-- -->*</filename>. This is so that malicious
+ * SVG files cannot include files that are in a directory above.
+ *
+ * # Loading an SVG with GIO
+ *
+ * If you have a #GFile that stands for an SVG file, you can simply call
+ * rsvg_handle_new_from_gfile_sync() to load an RsvgHandle from it.
+ *
+ * Alternatively, if you have a #GInputStream, you can use
+ * rsvg_handle_new_from_stream_sync().
+ *
+ * Both of those methods allow specifying a #GCancellable, so the loading
+ * process can be cancelled from another thread.
+ *
+ * # Loading an SVG without GIO
+ *
+ * You can load an RsvgHandle from a simple filename or URI with
+ * rsvg_handle_new_from_file(). Note that this is a blocking operation; there
+ * is no way to cancel it if loading a remote URI takes a long time.
+ *
+ * Alternatively, you can create an empty RsvgHandle with rsvg_handle_new() or
+ * rsvg_handle_new_with_flags(). The first function is equivalent to using
+ * #RSVG_HANDLE_FLAGS_NONE on the second one. These functions give you back an
+ * empty RsvgHandle, which is ready for you to feed it SVG data. You can do
+ * this with rsvg_handle_write() and rsvg_handle_close().
+ *
+ * # Resolution of the rendered image (dots per inch, or DPI)
+ *
+ * SVG images can contain dimensions like "<literal>5 cm</literal>" or
+ * "<literal>2 pt</literal>" that must be converted from physical units
+ * into device units. To do this, librsvg needs to know the actual dots per
+ * inch (DPI) of your target device.
+ *
+ * The recommended way to set the DPI is to use rsvg_handle_set_dpi() or
+ * rsvg_handle_set_dpi_x_y() on an RsvgHandle before rendering it.
+ *
+ * Alternatively, you can use rsvg_set_default_dpi() or
+ * rsvg_set_default_dpi_x_y() <emphasis>before</emphasis> creating any
+ * RsvgHandle objects. These functions will make RsvgHandle objects created
+ * afterwards to have the default DPI value you specified.
+ *
+ * # Rendering
+ *
+ * The preferred way to render an already-loaded RsvgHandle is to use
+ * rsvg_handle_render_cairo(). Please see its documentation for details.
+ *
+ * Alternatively, you can use rsvg_handle_get_pixbuf() to directly obtain a
+ * #GdkPixbuf with the rendered image. This is simple, but it does not let you
+ * control the size at which the SVG will be rendered. It will just be rendered
+ * at the size which rsvg_handle_get_dimensions() would return, which depends on
+ * the dimensions that librsvg is able to compute from the SVG data.
+ */
+
+#include "config.h"
+#include <string.h>
+
+#include "rsvg-private.h"
+#include "rsvg-defs.h"
+#include "rsvg-cairo-render.h"
+#include "rsvg-structure.h"
+
+enum {
+ PROP_0,
+ PROP_FLAGS,
+ PROP_DPI_X,
+ PROP_DPI_Y,
+ PROP_BASE_URI,
+ PROP_WIDTH,
+ PROP_HEIGHT,
+ PROP_EM,
+ PROP_EX,
+ PROP_TITLE,
+ PROP_DESC,
+ PROP_METADATA,
+ NUM_PROPS
+};
+
+extern double rsvg_internal_dpi_x;
+extern double rsvg_internal_dpi_y;
+
+G_DEFINE_TYPE (RsvgHandle, rsvg_handle, G_TYPE_OBJECT)
+
+static void
+rsvg_handle_init (RsvgHandle * self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, RSVG_TYPE_HANDLE, RsvgHandlePrivate);
+
+ self->priv->flags = RSVG_HANDLE_FLAGS_NONE;
+ self->priv->state = RSVG_HANDLE_STATE_START;
+ self->priv->all_nodes = g_ptr_array_new ();
+ self->priv->defs = rsvg_defs_new (self);
+ self->priv->handler_nest = 0;
+ self->priv->entities = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) xmlFreeNode);
+ self->priv->dpi_x = rsvg_internal_dpi_x;
+ self->priv->dpi_y = rsvg_internal_dpi_y;
+
+ self->priv->css_props = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_hash_table_destroy);
+
+ self->priv->ctxt = NULL;
+ self->priv->currentnode = NULL;
+ self->priv->treebase = NULL;
+ self->priv->element_name_stack = NULL;
+
+ self->priv->compressed_input_stream = NULL;
+ self->priv->cancellable = NULL;
+
+ self->priv->is_disposed = FALSE;
+ self->priv->in_loop = FALSE;
+
+ self->priv->is_testing = FALSE;
+}
+
+static void
+free_nodes (RsvgHandle *self)
+{
+ int i;
+
+ g_assert (self->priv->all_nodes != NULL);
+
+ for (i = 0; i < self->priv->all_nodes->len; i++) {
+ RsvgNode *node;
+
+ node = g_ptr_array_index (self->priv->all_nodes, i);
+ node = rsvg_node_unref (node);
+ }
+
+ g_ptr_array_free (self->priv->all_nodes, TRUE);
+ self->priv->all_nodes = NULL;
+}
+
+static void
+rsvg_handle_dispose (GObject *instance)
+{
+ RsvgHandle *self = (RsvgHandle *) instance;
+
+ if (self->priv->is_disposed)
+ goto chain;
+
+ self->priv->is_disposed = TRUE;
+
+ self->priv->ctxt = rsvg_free_xml_parser_and_doc (self->priv->ctxt);
+
+ g_hash_table_destroy (self->priv->entities);
+
+ free_nodes (self);
+
+ rsvg_defs_free (self->priv->defs);
+ self->priv->defs = NULL;
+
+ g_hash_table_destroy (self->priv->css_props);
+
+ self->priv->treebase = rsvg_node_unref (self->priv->treebase);
+ self->priv->currentnode = rsvg_node_unref (self->priv->currentnode);
+
+ if (self->priv->user_data_destroy)
+ (*self->priv->user_data_destroy) (self->priv->user_data);
+
+ if (self->priv->title)
+ g_string_free (self->priv->title, TRUE);
+ if (self->priv->desc)
+ g_string_free (self->priv->desc, TRUE);
+ if (self->priv->metadata)
+ g_string_free (self->priv->metadata, TRUE);
+ if (self->priv->base_uri)
+ g_free (self->priv->base_uri);
+
+ if (self->priv->base_gfile) {
+ g_object_unref (self->priv->base_gfile);
+ self->priv->base_gfile = NULL;
+ }
+ if (self->priv->compressed_input_stream) {
+ g_object_unref (self->priv->compressed_input_stream);
+ self->priv->compressed_input_stream = NULL;
+ }
+
+ g_clear_object (&self->priv->cancellable);
+
+ chain:
+ G_OBJECT_CLASS (rsvg_handle_parent_class)->dispose (instance);
+}
+
+static void
+rsvg_handle_set_property (GObject * instance, guint prop_id, GValue const *value, GParamSpec * pspec)
+{
+ RsvgHandle *self = RSVG_HANDLE (instance);
+
+ switch (prop_id) {
+ case PROP_FLAGS:
+ self->priv->flags = g_value_get_flags (value);
+ break;
+ case PROP_DPI_X:
+ rsvg_handle_set_dpi_x_y (self, g_value_get_double (value), self->priv->dpi_y);
+ break;
+ case PROP_DPI_Y:
+ rsvg_handle_set_dpi_x_y (self, self->priv->dpi_x, g_value_get_double (value));
+ break;
+ case PROP_BASE_URI:
+ rsvg_handle_set_base_uri (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (instance, prop_id, pspec);
+ }
+}
+
+static void
+rsvg_handle_get_property (GObject * instance, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ RsvgHandle *self = RSVG_HANDLE (instance);
+ RsvgDimensionData dim;
+
+ switch (prop_id) {
+ case PROP_FLAGS:
+ g_value_set_flags (value, self->priv->flags);
+ break;
+ case PROP_DPI_X:
+ g_value_set_double (value, self->priv->dpi_x);
+ break;
+ case PROP_DPI_Y:
+ g_value_set_double (value, self->priv->dpi_y);
+ break;
+ case PROP_BASE_URI:
+ g_value_set_string (value, rsvg_handle_get_base_uri (self));
+ break;
+ case PROP_WIDTH:
+ rsvg_handle_get_dimensions (self, &dim);
+ g_value_set_int (value, dim.width);
+ break;
+ case PROP_HEIGHT:
+ rsvg_handle_get_dimensions (self, &dim);
+ g_value_set_int (value, dim.height);
+ break;
+ case PROP_EM:
+ rsvg_handle_get_dimensions (self, &dim);
+ g_value_set_double (value, dim.em);
+ break;
+ case PROP_EX:
+ rsvg_handle_get_dimensions (self, &dim);
+ g_value_set_double (value, dim.ex);
+ break;
+ case PROP_TITLE:
+ g_value_set_string (value, rsvg_handle_get_title (self));
+ break;
+ case PROP_DESC:
+ g_value_set_string (value, rsvg_handle_get_desc (self));
+ break;
+ case PROP_METADATA:
+ g_value_set_string (value, rsvg_handle_get_metadata (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (instance, prop_id, pspec);
+ }
+}
+
+static void
+rsvg_handle_class_init (RsvgHandleClass * klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = rsvg_handle_dispose;
+ gobject_class->set_property = rsvg_handle_set_property;
+ gobject_class->get_property = rsvg_handle_get_property;
+
+ /**
+ * RsvgHandle:flags:
+ *
+ * Flags from #RsvgHandleFlags.
+ *
+ * Since: 2.36
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_FLAGS,
+ g_param_spec_flags ("flags", NULL, NULL,
+ RSVG_TYPE_HANDLE_FLAGS,
+ RSVG_HANDLE_FLAGS_NONE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+ * dpi-x:
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_DPI_X,
+ g_param_spec_double ("dpi-x", _("Horizontal resolution"),
+ _("Horizontal resolution"), 0.,
+ G_MAXDOUBLE, rsvg_internal_dpi_x,
+ (GParamFlags) (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT)));
+
+ g_object_class_install_property (gobject_class,
+ PROP_DPI_Y,
+ g_param_spec_double ("dpi-y", _("Vertical resolution"),
+ _("Vertical resolution"), 0., G_MAXDOUBLE,
+ rsvg_internal_dpi_y,
+ (GParamFlags) (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT)));
+
+ g_object_class_install_property (gobject_class,
+ PROP_BASE_URI,
+ g_param_spec_string ("base-uri", _("Base URI"),
+ _("Base URI"), NULL,
+ (GParamFlags) (G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT)));
+
+ g_object_class_install_property (gobject_class,
+ PROP_WIDTH,
+ g_param_spec_int ("width", _("Image width"),
+ _("Image width"), 0, G_MAXINT, 0,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ g_object_class_install_property (gobject_class,
+ PROP_HEIGHT,
+ g_param_spec_int ("height", _("Image height"),
+ _("Image height"), 0, G_MAXINT, 0,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ g_object_class_install_property (gobject_class,
+ PROP_EM,
+ g_param_spec_double ("em", _("em"),
+ _("em"), 0, G_MAXDOUBLE, 0,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ g_object_class_install_property (gobject_class,
+ PROP_EX,
+ g_param_spec_double ("ex", _("ex"),
+ _("ex"), 0, G_MAXDOUBLE, 0,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ /**
+ * RsvgHandle:title:
+ *
+ * SVG's description
+ *
+ * Deprecated: 2.36
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_TITLE,
+ g_param_spec_string ("title", _("Title"),
+ _("SVG file title"), NULL,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ /**
+ * RsvgHandle:desc:
+ *
+ * SVG's description
+ *
+ * Deprecated: 2.36
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_DESC,
+ g_param_spec_string ("desc", _("Description"),
+ _("SVG file description"), NULL,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ /**
+ * RsvgHandle:metadata:
+ *
+ * SVG's description
+ *
+ * Deprecated: 2.36
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_METADATA,
+ g_param_spec_string ("metadata", _("Metadata"),
+ _("SVG file metadata"), NULL,
+ (GParamFlags) (G_PARAM_READABLE)));
+
+ g_type_class_add_private (klass, sizeof (RsvgHandlePrivate));
+
+ xmlInitParser ();
+
+ rsvg_SAX_handler_struct_init ();
+}
+
+/**
+ * rsvg_handle_free:
+ * @handle: An #RsvgHandle
+ *
+ * Frees @handle.
+ * Deprecated: Use g_object_unref() instead.
+ **/
+void
+rsvg_handle_free (RsvgHandle * handle)
+{
+ g_object_unref (handle);
+}
+
+/**
+ * rsvg_handle_new:
+ *
+ * Returns a new rsvg handle. Must be freed with @g_object_unref. This
+ * handle can be used for dynamically loading an image. You need to feed it
+ * data using @rsvg_handle_write, then call @rsvg_handle_close when done.
+ * Afterwords, you can render it using Cairo or get a GdkPixbuf from it. When
+ * finished, free with g_object_unref(). No more than one image can be loaded
+ * with one handle.
+ *
+ * Returns: A new #RsvgHandle
+ **/
+RsvgHandle *
+rsvg_handle_new (void)
+{
+ return RSVG_HANDLE (g_object_new (RSVG_TYPE_HANDLE, NULL));
+}
+
+
+/**
+ * rsvg_handle_new_with_flags:
+ * @flags: flags from #RsvgHandleFlags
+ *
+ * Creates a new #RsvgHandle with flags @flags.
+ *
+ * Returns: (transfer full): a new #RsvgHandle
+ *
+ * Since: 2.36
+ **/
+RsvgHandle *
+rsvg_handle_new_with_flags (RsvgHandleFlags flags)
+{
+ return g_object_new (RSVG_TYPE_HANDLE,
+ "flags", flags,
+ NULL);
+}
+
+/**
+ * rsvg_handle_new_from_gfile_sync:
+ * @file: a #GFile
+ * @flags: flags from #RsvgHandleFlags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a location to store a #GError, or %NULL
+ *
+ * Creates a new #RsvgHandle for @file.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the
+ * operation was cancelled, the error %G_IO_ERROR_CANCELLED will be
+ * returned.
+ *
+ * Returns: a new #RsvgHandle on success, or %NULL with @error filled in
+ *
+ * Since: 2.32
+ */
+RsvgHandle *
+rsvg_handle_new_from_gfile_sync (GFile *file,
+ RsvgHandleFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ RsvgHandle *handle;
+ GFileInputStream *stream;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ stream = g_file_read (file, cancellable, error);
+ if (stream == NULL)
+ return NULL;
+
+ handle = rsvg_handle_new_from_stream_sync (G_INPUT_STREAM (stream), file,
+ flags, cancellable, error);
+ g_object_unref (stream);
+
+ return handle;
+}
+
+/**
+ * rsvg_handle_new_from_stream_sync:
+ * @input_stream: a #GInputStream
+ * @base_file: (allow-none): a #GFile, or %NULL
+ * @flags: flags from #RsvgHandleFlags
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): a location to store a #GError, or %NULL
+ *
+ * Creates a new #RsvgHandle for @stream.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the
+ * operation was cancelled, the error %G_IO_ERROR_CANCELLED will be
+ * returned.
+ *
+ * Returns: a new #RsvgHandle on success, or %NULL with @error filled in
+ *
+ * Since: 2.32
+ */
+RsvgHandle *
+rsvg_handle_new_from_stream_sync (GInputStream *input_stream,
+ GFile *base_file,
+ RsvgHandleFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ RsvgHandle *handle;
+
+ g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL);
+ g_return_val_if_fail (base_file == NULL || G_IS_FILE (base_file), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ handle = rsvg_handle_new_with_flags (flags);
+
+ if (base_file)
+ rsvg_handle_set_base_gfile (handle, base_file);
+
+ if (!rsvg_handle_read_stream_sync (handle, input_stream, cancellable, error)) {
+ g_object_unref (handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+/* http://www.ietf.org/rfc/rfc2396.txt */
+
+static gboolean
+path_is_uri (char const *path)
+{
+ char const *p;
+
+ if (path == NULL)
+ return FALSE;
+
+ if (strlen (path) < 4)
+ return FALSE;
+
+ if ((path[0] < 'a' || path[0] > 'z') &&
+ (path[0] < 'A' || path[0] > 'Z')) {
+ return FALSE;
+ }
+
+ for (p = &path[1];
+ (*p >= 'a' && *p <= 'z') ||
+ (*p >= 'A' && *p <= 'Z') ||
+ (*p >= '0' && *p <= '9') ||
+ *p == '+' ||
+ *p == '-' ||
+ *p == '.';
+ p++);
+
+ if (strlen (p) < 3)
+ return FALSE;
+
+ return (p[0] == ':' && p[1] == '/' && p[2] == '/');
+}
+
+static gchar *
+get_base_uri_from_filename (const gchar * filename)
+{
+ gchar *current_dir;
+ gchar *absolute_filename;
+ gchar *base_uri;
+
+ if (g_path_is_absolute (filename))
+ return g_filename_to_uri (filename, NULL, NULL);
+
+ current_dir = g_get_current_dir ();
+ absolute_filename = g_build_filename (current_dir, filename, NULL);
+ base_uri = g_filename_to_uri (absolute_filename, NULL, NULL);
+ g_free (absolute_filename);
+ g_free (current_dir);
+
+ return base_uri;
+}
+
+/**
+ * rsvg_handle_set_base_uri:
+ * @handle: A #RsvgHandle
+ * @base_uri: The base uri
+ *
+ * Set the base URI for this SVG. This can only be called before rsvg_handle_write()
+ * has been called.
+ *
+ * Since: 2.9
+ */
+void
+rsvg_handle_set_base_uri (RsvgHandle * handle, const char *base_uri)
+{
+ gchar *uri;
+ GFile *file;
+
+ g_return_if_fail (handle != NULL);
+
+ if (base_uri == NULL)
+ return;
+
+ if (path_is_uri (base_uri))
+ uri = g_strdup (base_uri);
+ else
+ uri = get_base_uri_from_filename (base_uri);
+
+ file = g_file_new_for_uri (uri ? uri : "data:");
+ rsvg_handle_set_base_gfile (handle, file);
+ g_object_unref (file);
+ g_free (uri);
+}
+
+/**
+ * rsvg_handle_set_base_gfile:
+ * @handle: a #RsvgHandle
+ * @base_file: a #GFile
+ *
+ * Set the base URI for @handle from @file.
+ * Note: This function may only be called before rsvg_handle_write()
+ * or rsvg_handle_read_stream_sync() has been called.
+ *
+ * Since: 2.32
+ */
+void
+rsvg_handle_set_base_gfile (RsvgHandle *handle,
+ GFile *base_file)
+{
+ RsvgHandlePrivate *priv;
+
+ g_return_if_fail (RSVG_IS_HANDLE (handle));
+ g_return_if_fail (G_IS_FILE (base_file));
+
+ priv = handle->priv;
+
+ g_object_ref (base_file);
+ if (priv->base_gfile)
+ g_object_unref (priv->base_gfile);
+ priv->base_gfile = base_file;
+
+ g_free (priv->base_uri);
+ priv->base_uri = g_file_get_uri (base_file);
+}
+
+/**
+ * rsvg_handle_get_base_uri:
+ * @handle: A #RsvgHandle
+ *
+ * Gets the base uri for this #RsvgHandle.
+ *
+ * Returns: the base uri, possibly null
+ * Since: 2.8
+ */
+const char *
+rsvg_handle_get_base_uri (RsvgHandle * handle)
+{
+ g_return_val_if_fail (handle, NULL);
+ return handle->priv->base_uri;
+}
+
+/**
+ * rsvg_handle_get_metadata:
+ * @handle: An #RsvgHandle
+ *
+ * Returns the SVG's metadata in UTF-8 or %NULL. You must make a copy
+ * of this metadata if you wish to use it after @handle has been freed.
+ *
+ * Returns: (nullable): The SVG's title
+ *
+ * Since: 2.9
+ *
+ * Deprecated: 2.36
+ */
+const char *
+rsvg_handle_get_metadata (RsvgHandle * handle)
+{
+ g_return_val_if_fail (handle, NULL);
+
+ if (handle->priv->metadata)
+ return handle->priv->metadata->str;
+ else
+ return NULL;
+}
+
+/**
+ * rsvg_handle_get_title:
+ * @handle: An #RsvgHandle
+ *
+ * Returns the SVG's title in UTF-8 or %NULL. You must make a copy
+ * of this title if you wish to use it after @handle has been freed.
+ *
+ * Returns: (nullable): The SVG's title
+ *
+ * Since: 2.4
+ *
+ * Deprecated: 2.36
+ */
+const char *
+rsvg_handle_get_title (RsvgHandle * handle)
+{
+ g_return_val_if_fail (handle, NULL);
+
+ if (handle->priv->title)
+ return handle->priv->title->str;
+ else
+ return NULL;
+}
+
+/**
+ * rsvg_handle_get_desc:
+ * @handle: An #RsvgHandle
+ *
+ * Returns the SVG's description in UTF-8 or %NULL. You must make a copy
+ * of this description if you wish to use it after @handle has been freed.
+ *
+ * Returns: (nullable): The SVG's description
+ *
+ * Since: 2.4
+ *
+ * Deprecated: 2.36
+ */
+const char *
+rsvg_handle_get_desc (RsvgHandle * handle)
+{
+ g_return_val_if_fail (handle, NULL);
+
+ if (handle->priv->desc)
+ return handle->priv->desc->str;
+ else
+ return NULL;
+}
+
+/**
+ * rsvg_handle_get_dimensions:
+ * @handle: A #RsvgHandle
+ * @dimension_data: (out): A place to store the SVG's size
+ *
+ * Get the SVG's size. Do not call from within the size_func callback, because an infinite loop will occur.
+ *
+ * Since: 2.14
+ */
+void
+rsvg_handle_get_dimensions (RsvgHandle * handle, RsvgDimensionData * dimension_data)
+{
+ /* This function is probably called from the cairo_render functions.
+ * To prevent an infinite loop we are saving the state.
+ */
+ if (!handle->priv->in_loop) {
+ handle->priv->in_loop = TRUE;
+ rsvg_handle_get_dimensions_sub (handle, dimension_data, NULL);
+ handle->priv->in_loop = FALSE;
+ } else {
+ /* Called within the size function, so return a standard size */
+ dimension_data->em = dimension_data->width = 1;
+ dimension_data->ex = dimension_data->height = 1;
+ }
+}
+
+/**
+ * rsvg_handle_get_dimensions_sub:
+ * @handle: A #RsvgHandle
+ * @dimension_data: (out): A place to store the SVG's size
+ * @id: (nullable): An element's id within the SVG, starting with "##", for
+ * example, "##layer1"; or %NULL to use the whole SVG.
+ *
+ * Get the size of a subelement of the SVG file. Do not call from within the
+ * size_func callback, because an infinite loop will occur.
+ *
+ * Since: 2.22
+ */
+gboolean
+rsvg_handle_get_dimensions_sub (RsvgHandle * handle, RsvgDimensionData * dimension_data, const char *id)
+{
+ cairo_t *cr;
+ cairo_surface_t *target;
+ RsvgDrawingCtx *draw;
+ RsvgNode *sself = NULL;
+ RsvgBbox bbox;
+ RsvgLength root_width, root_height;
+ RsvgViewBox root_vbox;
+
+ gboolean handle_subelement = TRUE;
+
+ g_return_val_if_fail (handle, FALSE);
+ g_return_val_if_fail (dimension_data, FALSE);
+
+ memset (dimension_data, 0, sizeof (RsvgDimensionData));
+
+ if (id && *id) {
+ sself = rsvg_defs_lookup (handle->priv->defs, id);
+
+ if (rsvg_node_is_same (sself, handle->priv->treebase))
+ id = NULL;
+ } else {
+ sself = handle->priv->treebase;
+ }
+
+ if (!sself && id)
+ return FALSE;
+
+ if (!handle->priv->treebase)
+ return FALSE;
+
+ g_assert (rsvg_node_get_type (handle->priv->treebase) == RSVG_NODE_TYPE_SVG);
+
+ bbox.rect.x = bbox.rect.y = 0;
+ bbox.rect.width = bbox.rect.height = 1;
+
+ rsvg_node_svg_get_size (handle->priv->treebase, &root_width, &root_height);
+ root_vbox = rsvg_node_svg_get_view_box (handle->priv->treebase);
+
+ if (!id) {
+ if ((root_width.unit == LENGTH_UNIT_PERCENT || root_height.unit == LENGTH_UNIT_PERCENT) && !root_vbox.active)
+ handle_subelement = TRUE;
+ else
+ handle_subelement = FALSE;
+ }
+
+ if (handle_subelement == TRUE) {
+ target = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ 1, 1);
+ cr = cairo_create (target);
+
+ draw = rsvg_cairo_new_drawing_ctx (cr, handle);
+
+ if (!draw) {
+ cairo_destroy (cr);
+ cairo_surface_destroy (target);
+
+ return FALSE;
+ }
+
+ g_assert (sself != NULL);
+ rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, sself);
+
+ rsvg_drawing_ctx_draw_node_from_stack (draw, handle->priv->treebase, 0);
+ bbox = RSVG_CAIRO_RENDER (draw->render)->bbox;
+
+ rsvg_drawing_ctx_free (draw);
+ cairo_destroy (cr);
+ cairo_surface_destroy (target);
+
+ dimension_data->width = bbox.rect.width;
+ dimension_data->height = bbox.rect.height;
+ } else {
+ bbox.rect.width = root_vbox.rect.width;
+ bbox.rect.height = root_vbox.rect.height;
+
+ dimension_data->width = (int) (rsvg_length_hand_normalize (&root_width, handle->priv->dpi_x,
+ bbox.rect.width, 12) + 0.5);
+ dimension_data->height = (int) (rsvg_length_hand_normalize (&root_height, handle->priv->dpi_y,
+ bbox.rect.height, 12) + 0.5);
+ }
+
+ dimension_data->em = dimension_data->width;
+ dimension_data->ex = dimension_data->height;
+
+ if (handle->priv->size_func)
+ (*handle->priv->size_func) (&dimension_data->width, &dimension_data->height,
+ handle->priv->user_data);
+
+ return TRUE;
+}
+
+/**
+ * rsvg_handle_get_position_sub:
+ * @handle: A #RsvgHandle
+ * @position_data: (out): A place to store the SVG fragment's position.
+ * @id: (nullable): An element's id within the SVG, starting with "##", for
+ * example, "##layer1"; or %NULL to use the whole SVG.
+ *
+ * Get the position of a subelement of the SVG file. Do not call from within
+ * the size_func callback, because an infinite loop will occur.
+ *
+ * Since: 2.22
+ */
+gboolean
+rsvg_handle_get_position_sub (RsvgHandle * handle, RsvgPositionData * position_data, const char *id)
+{
+ RsvgDrawingCtx *draw;
+ RsvgNode *node;
+ RsvgBbox bbox;
+ RsvgDimensionData dimension_data;
+ cairo_surface_t *target = NULL;
+ cairo_t *cr = NULL;
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (handle, FALSE);
+ g_return_val_if_fail (position_data, FALSE);
+
+ if (!handle->priv->treebase)
+ return FALSE;
+
+ /* Short-cut when no id is given. */
+ if (NULL == id || '\0' == *id) {
+ position_data->x = 0;
+ position_data->y = 0;
+ return TRUE;
+ }
+
+ memset (position_data, 0, sizeof (*position_data));
+ memset (&dimension_data, 0, sizeof (dimension_data));
+
+ node = rsvg_defs_lookup (handle->priv->defs, id);
+ if (!node) {
+ return FALSE;
+ } else if (rsvg_node_is_same (node, handle->priv->treebase)) {
+ /* Root node. */
+ position_data->x = 0;
+ position_data->y = 0;
+ return TRUE;
+ }
+
+ target = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
+ cr = cairo_create (target);
+ draw = rsvg_cairo_new_drawing_ctx (cr, handle);
+ if (!draw)
+ goto bail;
+
+ g_assert (node != NULL);
+ rsvg_drawing_ctx_add_node_and_ancestors_to_stack (draw, node);
+
+ rsvg_drawing_ctx_draw_node_from_stack (draw, handle->priv->treebase, 0);
+ bbox = RSVG_CAIRO_RENDER (draw->render)->bbox;
+
+ rsvg_drawing_ctx_free (draw);
+
+ position_data->x = bbox.rect.x;
+ position_data->y = bbox.rect.y;
+ dimension_data.width = bbox.rect.width;
+ dimension_data.height = bbox.rect.height;
+
+ dimension_data.em = dimension_data.width;
+ dimension_data.ex = dimension_data.height;
+
+ if (handle->priv->size_func)
+ (*handle->priv->size_func) (&dimension_data.width, &dimension_data.height,
+ handle->priv->user_data);
+
+ ret = TRUE;
+
+bail:
+ if (cr)
+ cairo_destroy (cr);
+ if (target)
+ cairo_surface_destroy (target);
+
+ return ret;
+}
+
+/**
+ * rsvg_handle_has_sub:
+ * @handle: a #RsvgHandle
+ * @id: an element's id within the SVG, starting with "##", for example, "##layer1".
+ *
+ * Checks whether the element @id exists in the SVG document.
+ *
+ * Returns: %TRUE if @id exists in the SVG document
+ *
+ * Since: 2.22
+ */
+gboolean
+rsvg_handle_has_sub (RsvgHandle * handle,
+ const char *id)
+{
+ g_return_val_if_fail (handle, FALSE);
+
+ if (G_UNLIKELY (!id || !id[0]))
+ return FALSE;
+
+ return rsvg_defs_lookup (handle->priv->defs, id) != NULL;
+}
+
+/**
+ * rsvg_handle_set_dpi:
+ * @handle: An #RsvgHandle
+ * @dpi: Dots Per Inch (aka Pixels Per Inch)
+ *
+ * Sets the DPI for the outgoing pixbuf. Common values are
+ * 75, 90, and 300 DPI. Passing a number <= 0 to @dpi will
+ * reset the DPI to whatever the default value happens to be.
+ *
+ * Since: 2.8
+ */
+void
+rsvg_handle_set_dpi (RsvgHandle * handle, double dpi)
+{
+ rsvg_handle_set_dpi_x_y (handle, dpi, dpi);
+}
+
+/**
+ * rsvg_handle_set_dpi_x_y:
+ * @handle: An #RsvgHandle
+ * @dpi_x: Dots Per Inch (aka Pixels Per Inch)
+ * @dpi_y: Dots Per Inch (aka Pixels Per Inch)
+ *
+ * Sets the DPI for the outgoing pixbuf. Common values are
+ * 75, 90, and 300 DPI. Passing a number <= 0 to #dpi_x or @dpi_y will
+ * reset the DPI to whatever the default value happens to be.
+ *
+ * Since: 2.8
+ */
+void
+rsvg_handle_set_dpi_x_y (RsvgHandle * handle, double dpi_x, double dpi_y)
+{
+ g_return_if_fail (handle != NULL);
+
+ if (dpi_x <= 0.)
+ handle->priv->dpi_x = rsvg_internal_dpi_x;
+ else
+ handle->priv->dpi_x = dpi_x;
+
+ if (dpi_y <= 0.)
+ handle->priv->dpi_y = rsvg_internal_dpi_y;
+ else
+ handle->priv->dpi_y = dpi_y;
+}
+
+/**
+ * rsvg_handle_set_size_callback:
+ * @handle: An #RsvgHandle
+ * @size_func: (nullable): A sizing function, or %NULL
+ * @user_data: User data to pass to @size_func, or %NULL
+ * @user_data_destroy: Destroy function for @user_data, or %NULL
+ *
+ * Sets the sizing function for the @handle. This function is called right
+ * after the size of the image has been loaded. The size of the image is passed
+ * in to the function, which may then modify these values to set the real size
+ * of the generated pixbuf. If the image has no associated size, then the size
+ * arguments are set to -1.
+ *
+ * Deprecated: Set up a cairo matrix and use rsvg_handle_render_cairo() instead.
+ * You can call rsvg_handle_get_dimensions() to figure out the size of your SVG,
+ * and then scale it to the desired size via Cairo. For example, the following
+ * code renders an SVG at a specified size, scaled proportionally from whatever
+ * original size it may have had:
+ *
+ * |[<!-- language="C" -->
+ * void
+ * render_scaled_proportionally (RsvgHandle *handle, cairo_t cr, int width, int height)
+ * {
+ * RsvgDimensionData dimensions;
+ * double x_factor, y_factor;
+ * double scale_factor;
+ *
+ * rsvg_handle_get_dimensions (handle, &dimensions);
+ *
+ * x_factor = (double) width / dimensions.width;
+ * y_factor = (double) height / dimensions.height;
+ *
+ * scale_factor = MIN (x_factor, y_factor);
+ *
+ * cairo_scale (cr, scale_factor, scale_factor);
+ *
+ * rsvg_handle_render_cairo (handle, cr);
+ * }
+ * ]|
+ **/
+void
+rsvg_handle_set_size_callback (RsvgHandle * handle,
+ RsvgSizeFunc size_func,
+ gpointer user_data, GDestroyNotify user_data_destroy)
+{
+ g_return_if_fail (handle != NULL);
+
+ if (handle->priv->user_data_destroy)
+ (*handle->priv->user_data_destroy) (handle->priv->user_data);
+
+ handle->priv->size_func = size_func;
+ handle->priv->user_data = user_data;
+ handle->priv->user_data_destroy = user_data_destroy;
+}
+
+/**
+ * _rsvg_handle_internal_set_testing:
+ * @handle: a #RsvgHandle
+ * @testing: Whether to enable testing mode
+ *
+ * Do not call this function. This is intended for librsvg's internal
+ * test suite only.
+ **/
+void
+rsvg_handle_internal_set_testing (RsvgHandle *handle, gboolean testing)
+{
+ g_return_if_fail (RSVG_IS_HANDLE (handle));
+
+ handle->priv->is_testing = testing ? TRUE : FALSE;
+}
diff --git a/rsvg-io.c b/rsvg-io.c
index 7452b73d..de6d61f8 100644
--- a/rsvg-io.c
+++ b/rsvg-io.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
Copyright (C) 2000 Eazel, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Dom Lachowicz <cinamod@hotmail.com>
@@ -66,11 +67,10 @@ uri_decoded_copy (const char *part,
#define BASE64_INDICATOR_LEN (sizeof (";base64") - 1)
static char *
-rsvg_acquire_data_data (const char *uri,
- const char *base_uri,
- char **out_mime_type,
- gsize *out_len,
- GError **error)
+rsvg_decode_data_uri (const char *uri,
+ char **out_mime_type,
+ gsize *out_len,
+ GError **error)
{
const char *comma, *start, *end;
char *mime_type;
@@ -87,7 +87,7 @@ rsvg_acquire_data_data (const char *uri,
if (comma && comma != start) {
/* Deal with MIME type / params */
- if (comma > start + BASE64_INDICATOR_LEN &&
+ if (comma >= start + BASE64_INDICATOR_LEN &&
!g_ascii_strncasecmp (comma - BASE64_INDICATOR_LEN, BASE64_INDICATOR, BASE64_INDICATOR_LEN)) {
end = comma - BASE64_INDICATOR_LEN;
base64 = TRUE;
@@ -124,56 +124,32 @@ rsvg_acquire_data_data (const char *uri,
return data;
}
-gchar *
-_rsvg_io_get_file_path (const gchar * filename,
- const gchar * base_uri)
-{
- gchar *absolute_filename;
-
- if (g_file_test (filename, G_FILE_TEST_EXISTS) || g_path_is_absolute (filename)) {
- absolute_filename = g_strdup (filename);
- } else {
- gchar *tmpcdir;
- gchar *base_filename;
-
- if (base_uri) {
- base_filename = g_filename_from_uri (base_uri, NULL, NULL);
- if (base_filename != NULL) {
- tmpcdir = g_path_get_dirname (base_filename);
- g_free (base_filename);
- } else
- return NULL;
- } else
- tmpcdir = g_get_current_dir ();
-
- absolute_filename = g_build_filename (tmpcdir, filename, NULL);
- g_free (tmpcdir);
- }
-
- return absolute_filename;
-}
-
static char *
-rsvg_acquire_file_data (const char *filename,
- const char *base_uri,
+rsvg_acquire_file_data (const char *uri,
char **out_mime_type,
gsize *out_len,
GCancellable *cancellable,
GError **error)
{
+ GFile *file;
gchar *path, *data;
gsize len;
char *content_type;
- rsvg_return_val_if_fail (filename != NULL, NULL, error);
+ rsvg_return_val_if_fail (uri != NULL, NULL, error);
g_assert (out_len != NULL);
- path = _rsvg_io_get_file_path (filename, base_uri);
- if (path == NULL)
+ file = g_file_new_for_uri (uri);
+ path = g_file_get_path (file);
+
+ if (path == NULL) {
+ g_object_unref (file);
return NULL;
+ }
if (!g_file_get_contents (path, &data, &len, error)) {
g_free (path);
+ g_object_unref (file);
return NULL;
}
@@ -184,6 +160,7 @@ rsvg_acquire_file_data (const char *filename,
}
g_free (path);
+ g_object_unref (file);
*out_len = len;
return data;
@@ -313,9 +290,9 @@ _rsvg_io_acquire_data (const char *href,
len = &llen;
if (strncmp (href, "data:", 5) == 0)
- return rsvg_acquire_data_data (href, NULL, mime_type, len, error);
+ return rsvg_decode_data_uri (href, mime_type, len, error);
- if ((data = rsvg_acquire_file_data (href, base_uri, mime_type, len, cancellable, NULL)))
+ if ((data = rsvg_acquire_file_data (href, mime_type, len, cancellable, NULL)))
return data;
if ((data = rsvg_acquire_gvfs_data (href, base_uri, mime_type, len, cancellable, error)))
@@ -342,13 +319,13 @@ _rsvg_io_acquire_stream (const char *href,
}
if (strncmp (href, "data:", 5) == 0) {
- if (!(data = rsvg_acquire_data_data (href, NULL, mime_type, &len, error)))
+ if (!(data = rsvg_decode_data_uri (href, mime_type, &len, error)))
return NULL;
return g_memory_input_stream_new_from_data (data, len, (GDestroyNotify) g_free);
}
- if ((data = rsvg_acquire_file_data (href, base_uri, mime_type, &len, cancellable, NULL)))
+ if ((data = rsvg_acquire_file_data (href, mime_type, &len, cancellable, NULL)))
return g_memory_input_stream_new_from_data (data, len, (GDestroyNotify) g_free);
if ((stream = rsvg_acquire_gvfs_stream (href, base_uri, mime_type, cancellable, error)))
diff --git a/rsvg-io.h b/rsvg-io.h
index d710ccfe..50e0002b 100644
--- a/rsvg-io.h
+++ b/rsvg-io.h
@@ -26,10 +26,6 @@
#include <glib.h>
#include <gio/gio.h>
-G_GNUC_INTERNAL
-gchar *_rsvg_io_get_file_path (const gchar *filename,
- const gchar *basedir);
-
char *_rsvg_io_acquire_data (const char *uri,
const char *base_uri,
char **mime_type,
diff --git a/rsvg-mask.c b/rsvg-mask.c
deleted file mode 100644
index 664e8dc1..00000000
--- a/rsvg-mask.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* vim: set sw=4 sts=4 expandtab: */
-/*
- rsvg-filter.c: Provides filters
-
- Copyright (C) 2004 Caleb Moore
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA.
-
- Author: Caleb Moore <calebmm@tpg.com.au>
-*/
-
-#include "rsvg-private.h"
-#include "rsvg-mask.h"
-#include "rsvg-styles.h"
-#include "rsvg-css.h"
-#include <string.h>
-
-static void
-rsvg_mask_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
-{
- RsvgMask *mask = impl;
- const char *value;
-
- if ((value = rsvg_property_bag_lookup (atts, "maskUnits"))) {
- if (!strcmp (value, "userSpaceOnUse"))
- mask->maskunits = userSpaceOnUse;
- else
- mask->maskunits = objectBoundingBox;
- }
- if ((value = rsvg_property_bag_lookup (atts, "maskContentUnits"))) {
- if (!strcmp (value, "objectBoundingBox"))
- mask->contentunits = objectBoundingBox;
- else
- mask->contentunits = userSpaceOnUse;
- }
- if ((value = rsvg_property_bag_lookup (atts, "x")))
- mask->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
- if ((value = rsvg_property_bag_lookup (atts, "y")))
- mask->y = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
- if ((value = rsvg_property_bag_lookup (atts, "width")))
- mask->width = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
- if ((value = rsvg_property_bag_lookup (atts, "height")))
- mask->height = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
-}
-
-static void
-rsvg_mask_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
- /* nothing; this gets drawn specially in rsvg-cairo-draw.c */
-}
-
-RsvgNode *
-rsvg_new_mask (const char *element_name, RsvgNode *parent)
-{
- RsvgMask *mask;
-
- mask = g_new0 (RsvgMask, 1);
- mask->maskunits = objectBoundingBox;
- mask->contentunits = userSpaceOnUse;
- mask->x = rsvg_length_parse ("0", LENGTH_DIR_HORIZONTAL);
- mask->y = rsvg_length_parse ("0", LENGTH_DIR_VERTICAL);
- mask->width = rsvg_length_parse ("1", LENGTH_DIR_HORIZONTAL);
- mask->height = rsvg_length_parse ("1", LENGTH_DIR_VERTICAL);
-
- return rsvg_rust_cnode_new (RSVG_NODE_TYPE_MASK,
- parent,
- rsvg_state_new (),
- mask,
- rsvg_mask_set_atts,
- rsvg_mask_draw,
- g_free);
-}
-
-static void
-rsvg_clip_path_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag *atts)
-{
- RsvgClipPath *clip_path = impl;
- const char *value;
-
- if ((value = rsvg_property_bag_lookup (atts, "clipPathUnits"))) {
- if (!strcmp (value, "objectBoundingBox"))
- clip_path->units = objectBoundingBox;
- else
- clip_path->units = userSpaceOnUse;
- }
-}
-
-static void
-rsvg_clip_path_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dominate)
-{
- /* nothing; this gets drawn specially in rsvg-cairo-draw.c */
-}
-
-RsvgNode *
-rsvg_new_clip_path (const char *element_name, RsvgNode *parent)
-{
- RsvgClipPath *clip_path;
-
- clip_path = g_new0 (RsvgClipPath, 1);
- clip_path->units = userSpaceOnUse;
-
- return rsvg_rust_cnode_new (RSVG_NODE_TYPE_CLIP_PATH,
- parent,
- rsvg_state_new (),
- clip_path,
- rsvg_clip_path_set_atts,
- rsvg_clip_path_draw,
- g_free);
-}
diff --git a/rsvg-mask.h b/rsvg-mask.h
index f38e5f64..24368dd5 100644
--- a/rsvg-mask.h
+++ b/rsvg-mask.h
@@ -35,27 +35,41 @@
G_BEGIN_DECLS
-typedef RsvgCoordUnits RsvgMaskUnits;
+/* Implemented in rust/src/mask.rs */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_node_mask_new (const char *element_name, RsvgNode *node);
-typedef struct _RsvgMask RsvgMask;
+/* Implemented in rust/src/mask.rs */
+G_GNUC_INTERNAL
+RsvgLength rsvg_node_mask_get_x (RsvgNode *node);
-struct _RsvgMask {
- RsvgLength x, y, width, height;
- RsvgMaskUnits maskunits;
- RsvgMaskUnits contentunits;
-};
+/* Implemented in rust/src/mask.rs */
+G_GNUC_INTERNAL
+RsvgLength rsvg_node_mask_get_y (RsvgNode *node);
+/* Implemented in rust/src/mask.rs */
G_GNUC_INTERNAL
-RsvgNode *rsvg_new_mask (const char *element_name, RsvgNode *node);
+RsvgLength rsvg_node_mask_get_width (RsvgNode *node);
-typedef struct _RsvgClipPath RsvgClipPath;
+/* Implemented in rust/src/mask.rs */
+G_GNUC_INTERNAL
+RsvgLength rsvg_node_mask_get_height (RsvgNode *node);
-struct _RsvgClipPath {
- RsvgCoordUnits units;
-};
+/* Implemented in rust/src/mask.rs */
+G_GNUC_INTERNAL
+RsvgCoordUnits rsvg_node_mask_get_units (RsvgNode *node);
+
+/* Implemented in rust/src/mask.rs */
+G_GNUC_INTERNAL
+RsvgCoordUnits rsvg_node_mask_get_content_units (RsvgNode *node);
+
+/* Implemented in rust/src/clip_path.rs */
+G_GNUC_INTERNAL
+RsvgNode *rsvg_node_clip_path_new (const char *element_name, RsvgNode *node);
+/* Implemented in rust/src/clip_path.rs */
G_GNUC_INTERNAL
-RsvgNode *rsvg_new_clip_path (const char *element_name, RsvgNode *node);
+RsvgCoordUnits rsvg_node_clip_path_get_units (RsvgNode *node);
G_END_DECLS
#endif
diff --git a/rsvg-private.h b/rsvg-private.h
index a39e5e5a..cc2c700f 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -53,7 +53,6 @@ typedef struct _RsvgState RsvgState;
typedef struct _RsvgDefs RsvgDefs;
typedef struct _RsvgNode RsvgNode;
typedef struct _RsvgFilter RsvgFilter;
-typedef struct _RsvgNodeChars RsvgNodeChars;
/* prepare for gettext */
#ifndef _
@@ -120,7 +119,7 @@ struct RsvgSaxHandler {
void (*free) (RsvgSaxHandler * self);
void (*start_element) (RsvgSaxHandler * self, const char *name, RsvgPropertyBag * atts);
void (*end_element) (RsvgSaxHandler * self, const char *name);
- void (*characters) (RsvgSaxHandler * self, const char *ch, int len);
+ void (*characters) (RsvgSaxHandler * self, const char *ch, gssize len);
};
/* Reading state for an RsvgHandle */
@@ -226,8 +225,8 @@ struct RsvgRender {
void (*free) (RsvgRender * self);
- PangoContext *(*create_pango_context) (RsvgDrawingCtx * ctx);
- void (*render_pango_layout) (RsvgDrawingCtx * ctx, PangoLayout *layout,
+ PangoContext *(*get_pango_context) (RsvgDrawingCtx * ctx);
+ void (*render_pango_layout) (RsvgDrawingCtx * ctx, PangoLayout *layout,
double x, double y);
void (*render_path_builder) (RsvgDrawingCtx * ctx, RsvgPathBuilder *builder);
void (*render_surface) (RsvgDrawingCtx * ctx, cairo_surface_t *surface,
@@ -284,7 +283,8 @@ typedef struct {
} RsvgBbox;
typedef enum {
- objectBoundingBox, userSpaceOnUse
+ userSpaceOnUse,
+ objectBoundingBox
} RsvgCoordUnits;
/* Keep this in sync with rust/src/node.rs:NodeType */
@@ -424,9 +424,9 @@ void rsvg_node_foreach_child (RsvgNode *node, RsvgNodeForeachChildFn fn, gpointe
G_GNUC_INTERNAL
void rsvg_node_draw_children (RsvgNode *node, RsvgDrawingCtx *ctx, int dominate);
-struct _RsvgNodeChars {
- GString *contents;
-};
+/* Implemented in rust/src/chars.rs */
+G_GNUC_INTERNAL
+void rsvg_node_chars_get_string (RsvgNode *node, const char **out_str, gsize *out_len);
typedef void (*RsvgPropertyBagEnumFunc) (const char *key, const char *value, gpointer user_data);
@@ -450,8 +450,6 @@ GdkPixbuf *rsvg_pixbuf_from_data_with_size_data (const guchar * buff,
const char *base_uri, GError ** error);
G_GNUC_INTERNAL
gboolean rsvg_eval_switch_attributes (RsvgPropertyBag * atts, gboolean * p_has_cond);
-G_GNUC_INTERNAL
-gchar *rsvg_get_base_uri_from_filename (const gchar * file_name);
G_GNUC_INTERNAL
void rsvg_pop_discrete_layer (RsvgDrawingCtx * ctx);
@@ -536,6 +534,15 @@ G_GNUC_INTERNAL
void rsvg_drawing_ctx_set_current_state_affine (RsvgDrawingCtx *ctx, cairo_matrix_t *affine);
G_GNUC_INTERNAL
+PangoContext *rsvg_drawing_ctx_get_pango_context (RsvgDrawingCtx *draw_ctx);
+
+G_GNUC_INTERNAL
+void rsvg_drawing_ctx_render_pango_layout (RsvgDrawingCtx *draw_ctx,
+ PangoLayout *layout,
+ double x,
+ double y);
+
+G_GNUC_INTERNAL
double _rsvg_css_accumulate_baseline_shift (RsvgState * state, RsvgDrawingCtx * ctx);
/* Implemented in rust/src/length.rs */
@@ -561,6 +568,15 @@ void rsvg_return_if_fail_warning (const char *pretty_function,
const char *expression, GError ** error);
G_GNUC_INTERNAL
+char *rsvg_handle_resolve_uri (RsvgHandle *handle,
+ const char *uri);
+
+G_GNUC_INTERNAL
+gboolean rsvg_allow_load (GFile *base_gfile,
+ const char *uri,
+ GError **error);
+
+G_GNUC_INTERNAL
char *_rsvg_handle_acquire_data (RsvgHandle *handle,
const char *uri,
char **content_type,
diff --git a/rsvg-styles.c b/rsvg-styles.c
index efba2081..f52d64f4 100644
--- a/rsvg-styles.c
+++ b/rsvg-styles.c
@@ -700,15 +700,15 @@ rsvg_parse_style_pair (RsvgState * state,
state->has_visible = TRUE;
if (g_str_equal (value, "none"))
state->visible = FALSE;
- else if (!g_str_equal (value, "inherit") != 0)
+ else if (!g_str_equal (value, "inherit"))
state->visible = TRUE;
else
state->has_visible = FALSE;
- } else if (g_str_equal (name, "xml:space")) {
+ } else if (g_str_equal (name, "xml:space")) {
state->has_space_preserve = TRUE;
if (g_str_equal (value, "default"))
state->space_preserve = FALSE;
- else if (!g_str_equal (value, "preserve") == 0)
+ else if (g_str_equal (value, "preserve"))
state->space_preserve = TRUE;
else
state->space_preserve = FALSE;
@@ -716,7 +716,7 @@ rsvg_parse_style_pair (RsvgState * state,
state->has_visible = TRUE;
if (g_str_equal (value, "visible"))
state->visible = TRUE;
- else if (!g_str_equal (value, "inherit") != 0)
+ else if (!g_str_equal (value, "inherit"))
state->visible = FALSE; /* collapse or hidden */
else
state->has_visible = FALSE;
@@ -818,14 +818,16 @@ rsvg_parse_style_pair (RsvgState * state,
} else if (g_str_equal (name, "text-decoration")) {
if (g_str_equal (value, "inherit")) {
state->has_font_decor = FALSE;
- state->font_decor = TEXT_NORMAL;
+ state->font_decor.overline = FALSE;
+ state->font_decor.underline = FALSE;
+ state->font_decor.strike = FALSE;
} else {
if (strstr (value, "underline"))
- state->font_decor |= TEXT_UNDERLINE;
+ state->font_decor.underline = TRUE;
if (strstr (value, "overline"))
- state->font_decor |= TEXT_OVERLINE;
+ state->font_decor.overline = TRUE;
if (strstr (value, "strike") || strstr (value, "line-through")) /* strike though or line-through */
- state->font_decor |= TEXT_STRIKE;
+ state->font_decor.strike = TRUE;
state->has_font_decor = TRUE;
}
} else if (g_str_equal (name, "direction")) {
@@ -1737,6 +1739,12 @@ rsvg_state_get_cond_true (RsvgState *state)
return state->cond_true;
}
+void
+rsvg_state_set_cond_true (RsvgState *state, gboolean cond_true)
+{
+ state->cond_true = cond_true;
+}
+
RsvgCssColorSpec *
rsvg_state_get_stop_color (RsvgState *state)
{
@@ -1762,3 +1770,73 @@ rsvg_state_get_current_color (RsvgState *state)
{
return state->current_color;
}
+
+const char *
+rsvg_state_get_language (RsvgState *state)
+{
+ return state->lang;
+}
+
+UnicodeBidi
+rsvg_state_get_unicode_bidi (RsvgState *state)
+{
+ return state->unicode_bidi;
+}
+
+PangoDirection
+rsvg_state_get_text_dir (RsvgState *state)
+{
+ return state->text_dir;
+}
+
+PangoGravity
+rsvg_state_get_text_gravity (RsvgState *state)
+{
+ return state->text_gravity;
+}
+
+const char *
+rsvg_state_get_font_family (RsvgState *state)
+{
+ return state->font_family;
+}
+
+PangoStyle
+rsvg_state_get_font_style (RsvgState *state)
+{
+ return state->font_style;
+}
+
+PangoVariant
+rsvg_state_get_font_variant (RsvgState *state)
+{
+ return state->font_variant;
+}
+
+PangoWeight
+rsvg_state_get_font_weight (RsvgState *state)
+{
+ return state->font_weight;
+}
+
+PangoStretch
+rsvg_state_get_font_stretch (RsvgState *state)
+{
+ return state->font_stretch;
+}
+
+RsvgLength
+rsvg_state_get_letter_spacing (RsvgState *state)
+{
+ return state->letter_spacing;
+}
+
+const TextDecoration *
+rsvg_state_get_font_decor (RsvgState *state)
+{
+ if (state->has_font_decor) {
+ return &state->font_decor;
+ } else {
+ return NULL;
+ }
+}
diff --git a/rsvg-styles.h b/rsvg-styles.h
index 45ff753e..aef6a5f9 100644
--- a/rsvg-styles.h
+++ b/rsvg-styles.h
@@ -36,14 +36,12 @@
G_BEGIN_DECLS
-typedef int TextDecoration;
-
-enum {
- TEXT_NORMAL = 0x00,
- TEXT_OVERLINE = 0x01,
- TEXT_UNDERLINE = 0x02,
- TEXT_STRIKE = 0x04
-};
+/* Keep in sync with rust/src/state.rs:TextDecoration */
+typedef struct {
+ gboolean overline;
+ gboolean underline;
+ gboolean strike;
+} TextDecoration;
typedef enum {
TEXT_ANCHOR_START,
@@ -51,6 +49,7 @@ typedef enum {
TEXT_ANCHOR_END
} TextAnchor;
+/* Keep in sync with rust/src/state.c:UnicodeBidi */
typedef enum {
UNICODE_BIDI_NORMAL = 0,
UNICODE_BIDI_EMBED = 1,
@@ -242,6 +241,9 @@ G_GNUC_INTERNAL
gboolean rsvg_state_get_cond_true (RsvgState *state);
G_GNUC_INTERNAL
+void rsvg_state_set_cond_true (RsvgState *state, gboolean cond_true);
+
+G_GNUC_INTERNAL
RsvgCssColorSpec *rsvg_state_get_stop_color (RsvgState *state);
G_GNUC_INTERNAL
@@ -250,6 +252,39 @@ RsvgOpacitySpec *rsvg_state_get_stop_opacity (RsvgState *state);
G_GNUC_INTERNAL
guint32 rsvg_state_get_current_color (RsvgState *state);
+G_GNUC_INTERNAL
+const char *rsvg_state_get_language (RsvgState *state);
+
+G_GNUC_INTERNAL
+UnicodeBidi rsvg_state_get_unicode_bidi (RsvgState *state);
+
+G_GNUC_INTERNAL
+PangoDirection rsvg_state_get_text_dir (RsvgState *state);
+
+G_GNUC_INTERNAL
+PangoGravity rsvg_state_get_text_gravity (RsvgState *state);
+
+G_GNUC_INTERNAL
+const char *rsvg_state_get_font_family (RsvgState *state);
+
+G_GNUC_INTERNAL
+PangoStyle rsvg_state_get_font_style (RsvgState *state);
+
+G_GNUC_INTERNAL
+PangoVariant rsvg_state_get_font_variant (RsvgState *state);
+
+G_GNUC_INTERNAL
+PangoWeight rsvg_state_get_font_weight (RsvgState *state);
+
+G_GNUC_INTERNAL
+PangoStretch rsvg_state_get_font_stretch (RsvgState *state);
+
+G_GNUC_INTERNAL
+RsvgLength rsvg_state_get_letter_spacing (RsvgState *state);
+
+G_GNUC_INTERNAL
+const TextDecoration *rsvg_state_get_font_decor (RsvgState *state);
+
G_END_DECLS
#endif /* RSVG_STYLES_H */
diff --git a/rsvg-text.c b/rsvg-text.c
index e78abfde..3c69cd9d 100644
--- a/rsvg-text.c
+++ b/rsvg-text.c
@@ -36,6 +36,15 @@
/* what we use for text rendering depends on what cairo has to offer */
#include <pango/pangocairo.h>
+/* Keep in sync with rust/src/space.rs:XmlSpace */
+typedef enum {
+ XML_SPACE_DEFAULT,
+ XML_SPACE_PRESERVE
+} XmlSpace;
+
+/* Implemented in rust/src/space.rs */
+extern char *rsvg_xml_space_normalize (XmlSpace mode, const char *s);
+
typedef struct _RsvgNodeText RsvgNodeText;
struct _RsvgNodeText {
@@ -51,79 +60,6 @@ struct _RsvgNodeTref {
char *link;
};
-char *
-rsvg_make_valid_utf8 (const char *str, int len)
-{
- GString *string;
- const char *remainder, *invalid;
- int remaining_bytes, valid_bytes;
-
- string = NULL;
- remainder = str;
-
- if (len < 0)
- remaining_bytes = strlen (str);
- else
- remaining_bytes = len;
-
- while (remaining_bytes != 0) {
- if (g_utf8_validate (remainder, remaining_bytes, &invalid))
- break;
- valid_bytes = invalid - remainder;
-
- if (string == NULL)
- string = g_string_sized_new (remaining_bytes);
-
- g_string_append_len (string, remainder, valid_bytes);
- g_string_append_c (string, '?');
-
- remaining_bytes -= valid_bytes + 1;
- remainder = invalid + 1;
- }
-
- if (string == NULL)
- return len < 0 ? g_strndup (str, len) : g_strdup (str);
-
- g_string_append (string, remainder);
-
- return g_string_free (string, FALSE);
-}
-
-static GString *
-_rsvg_text_chomp (RsvgState *state, GString * in, gboolean * lastwasspace)
-{
- GString *out;
- guint i;
- out = g_string_new (in->str);
-
- if (!state->space_preserve) {
- for (i = 0; i < out->len;) {
- if (out->str[i] == '\n')
- g_string_erase (out, i, 1);
- else
- i++;
- }
-
- for (i = 0; i < out->len; i++)
- if (out->str[i] == '\t')
- out->str[i] = ' ';
-
- for (i = 0; i < out->len;) {
- if (out->str[i] == ' ' && *lastwasspace)
- g_string_erase (out, i, 1);
- else {
- if (out->str[i] == ' ')
- *lastwasspace = TRUE;
- else
- *lastwasspace = FALSE;
- i++;
- }
- }
- }
-
- return out;
-}
-
static void
set_text_common_atts (RsvgNodeText *text, RsvgPropertyBag *atts)
{
@@ -155,28 +91,46 @@ rsvg_node_text_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, Rsvg
static void rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdouble * y);
static void
-_rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
- gdouble * x, gdouble * y, gboolean * lastwasspace,
- gboolean usetextonly);
+draw_from_children (RsvgNode *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gdouble *y,
+ gboolean usetextonly);
static void
-_rsvg_node_text_type_tspan (RsvgNode *node, RsvgNodeText *self, RsvgDrawingCtx *ctx,
- gdouble *x, gdouble *y, gboolean *lastwasspace,
- gboolean usetextonly);
+draw_tspan (RsvgNode *node,
+ RsvgNodeText *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gdouble *y,
+ gboolean usetextonly);
static void
-_rsvg_node_text_type_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
- gdouble * x, gdouble * y, gboolean * lastwasspace,
- gboolean usetextonly);
+draw_tref (RsvgNodeTref *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gdouble *y,
+ gboolean usetextonly);
typedef struct {
RsvgDrawingCtx *ctx;
gdouble *x;
gdouble *y;
- gboolean *lastwasspace;
gboolean usetextonly;
} DrawTextClosure;
+static XmlSpace
+xml_space_from_current_state (RsvgDrawingCtx *ctx)
+{
+ RsvgState *state = rsvg_current_state (ctx);
+
+ if (state->space_preserve) {
+ return XML_SPACE_PRESERVE;
+ } else {
+ return XML_SPACE_DEFAULT;
+ }
+}
+
static gboolean
draw_text_child (RsvgNode *node, gpointer data)
{
@@ -186,38 +140,42 @@ draw_text_child (RsvgNode *node, gpointer data)
closure = data;
if (type == RSVG_NODE_TYPE_CHARS) {
- RsvgNodeChars *chars = rsvg_rust_cnode_get_impl (node);
- GString *str = _rsvg_text_chomp (rsvg_current_state (closure->ctx), chars->contents, closure->lastwasspace);
- rsvg_text_render_text (closure->ctx, str->str, closure->x, closure->y);
- g_string_free (str, TRUE);
+ const char *chars_str;
+ gsize chars_len;
+ GString *string;
+ char *chomped;
+
+ rsvg_node_chars_get_string (node, &chars_str, &chars_len);
+ string = g_string_new_len (chars_str, chars_len);
+
+ chomped = rsvg_xml_space_normalize (xml_space_from_current_state (closure->ctx), string->str);
+ g_string_free (string, TRUE);
+
+ rsvg_text_render_text (closure->ctx, chomped, closure->x, closure->y);
+ g_free (chomped);
} else {
if (closure->usetextonly) {
- _rsvg_node_text_type_children (node,
- closure->ctx,
- closure->x,
- closure->y,
- closure->lastwasspace,
- closure->usetextonly);
+ draw_from_children (node,
+ closure->ctx,
+ closure->x,
+ closure->y,
+ closure->usetextonly);
} else {
if (type == RSVG_NODE_TYPE_TSPAN) {
RsvgNodeText *tspan = rsvg_rust_cnode_get_impl (node);
- rsvg_state_push (closure->ctx);
- _rsvg_node_text_type_tspan (node,
- tspan,
- closure->ctx,
- closure->x,
- closure->y,
- closure->lastwasspace,
- closure->usetextonly);
- rsvg_state_pop (closure->ctx);
+ draw_tspan (node,
+ tspan,
+ closure->ctx,
+ closure->x,
+ closure->y,
+ closure->usetextonly);
} else if (type == RSVG_NODE_TYPE_TREF) {
RsvgNodeTref *tref = rsvg_rust_cnode_get_impl (node);
- _rsvg_node_text_type_tref (tref,
- closure->ctx,
- closure->x,
- closure->y,
- closure->lastwasspace,
- closure->usetextonly);
+ draw_tref (tref,
+ closure->ctx,
+ closure->x,
+ closure->y,
+ closure->usetextonly);
}
}
}
@@ -227,9 +185,11 @@ draw_text_child (RsvgNode *node, gpointer data)
/* This function is responsible of selecting render for a text element including its children and giving it the drawing context */
static void
-_rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
- gdouble * x, gdouble * y, gboolean * lastwasspace,
- gboolean usetextonly)
+draw_from_children (RsvgNode *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gdouble *y,
+ gboolean usetextonly)
{
DrawTextClosure closure;
@@ -238,7 +198,6 @@ _rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
closure.ctx = ctx;
closure.x = x;
closure.y = y;
- closure.lastwasspace = lastwasspace;
closure.usetextonly = usetextonly;
rsvg_node_foreach_child (self, draw_text_child, &closure);
@@ -247,29 +206,29 @@ _rsvg_node_text_type_children (RsvgNode * self, RsvgDrawingCtx * ctx,
}
static gboolean
-_rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
- gdouble * length, gboolean * lastwasspace,
- gboolean usetextonly);
+compute_length_from_children (RsvgNode *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *length,
+ gboolean usetextonly);
static gboolean
-_rsvg_node_text_length_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
- gdouble * x, gboolean * lastwasspace,
- gboolean usetextonly);
+length_from_tref (RsvgNodeTref *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gboolean usetextonly);
static gboolean
-_rsvg_node_text_length_tspan (RsvgNode *node,
- RsvgNodeText *self,
- RsvgDrawingCtx *ctx,
- gdouble *x,
- gboolean *lastwasspace,
- gboolean usetextonly);
+length_from_tspan (RsvgNode *node,
+ RsvgNodeText *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gboolean usetextonly);
-static gdouble rsvg_text_length_text_as_string (RsvgDrawingCtx * ctx, const char *text);
+static gdouble measure_text (RsvgDrawingCtx * ctx, const char *text);
typedef struct {
RsvgDrawingCtx *ctx;
gdouble *length;
- gboolean *lastwasspace;
gboolean usetextonly;
gboolean done;
} ChildrenLengthClosure;
@@ -288,33 +247,39 @@ compute_child_length (RsvgNode *node, gpointer data)
rsvg_state_reinherit_top (closure->ctx, rsvg_node_get_state (node), 0);
if (type == RSVG_NODE_TYPE_CHARS) {
- RsvgNodeChars *chars = rsvg_rust_cnode_get_impl (node);
- GString *str = _rsvg_text_chomp (rsvg_current_state (closure->ctx), chars->contents, closure->lastwasspace);
- *closure->length += rsvg_text_length_text_as_string (closure->ctx, str->str);
- g_string_free (str, TRUE);
+ const char *chars_str;
+ gsize chars_len;
+ GString *string;
+ char *chomped;
+
+ rsvg_node_chars_get_string (node, &chars_str, &chars_len);
+ string = g_string_new_len (chars_str, chars_len);
+
+ chomped = rsvg_xml_space_normalize (xml_space_from_current_state (closure->ctx), string->str);
+ g_string_free (string, TRUE);
+
+ *closure->length += measure_text (closure->ctx, chomped);
+ g_free (chomped);
} else {
if (closure->usetextonly) {
- done = _rsvg_node_text_length_children (node,
- closure->ctx,
- closure->length,
- closure->lastwasspace,
- closure->usetextonly);
+ done = compute_length_from_children (node,
+ closure->ctx,
+ closure->length,
+ closure->usetextonly);
} else {
if (type == RSVG_NODE_TYPE_TSPAN) {
RsvgNodeText *tspan = rsvg_rust_cnode_get_impl (node);
- done = _rsvg_node_text_length_tspan (node,
- tspan,
- closure->ctx,
- closure->length,
- closure->lastwasspace,
- closure->usetextonly);
+ done = length_from_tspan (node,
+ tspan,
+ closure->ctx,
+ closure->length,
+ closure->usetextonly);
} else if (type == RSVG_NODE_TYPE_TREF) {
RsvgNodeTref *tref = rsvg_rust_cnode_get_impl (node);
- done = _rsvg_node_text_length_tref (tref,
- closure->ctx,
- closure->length,
- closure->lastwasspace,
- closure->usetextonly);
+ done = length_from_tref (tref,
+ closure->ctx,
+ closure->length,
+ closure->usetextonly);
}
}
}
@@ -326,15 +291,15 @@ compute_child_length (RsvgNode *node, gpointer data)
}
static gboolean
-_rsvg_node_text_length_children (RsvgNode * self, RsvgDrawingCtx * ctx,
- gdouble * length, gboolean * lastwasspace,
- gboolean usetextonly)
+compute_length_from_children (RsvgNode *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *length,
+ gboolean usetextonly)
{
ChildrenLengthClosure closure;
closure.ctx = ctx;
closure.length = length;
- closure.lastwasspace = lastwasspace;
closure.usetextonly = usetextonly;
closure.done = FALSE;
@@ -349,7 +314,6 @@ rsvg_node_text_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dom
{
RsvgNodeText *text = impl;
double x, y, dx, dy, length = 0;
- gboolean lastwasspace = TRUE;
rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), dominate);
@@ -359,7 +323,7 @@ rsvg_node_text_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dom
dy = rsvg_length_normalize (&text->dy, ctx);
if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
- _rsvg_node_text_length_children (node, ctx, &length, &lastwasspace, FALSE);
+ compute_length_from_children (node, ctx, &length, FALSE);
if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
length /= 2;
}
@@ -379,8 +343,7 @@ rsvg_node_text_draw (RsvgNode *node, gpointer impl, RsvgDrawingCtx *ctx, int dom
x += dx;
y += dy;
- lastwasspace = TRUE;
- _rsvg_node_text_type_children (node, ctx, &x, &y, &lastwasspace, FALSE);
+ draw_from_children (node, ctx, &x, &y, FALSE);
}
RsvgNode *
@@ -401,20 +364,24 @@ rsvg_new_text (const char *element_name, RsvgNode *parent)
}
static void
-_rsvg_node_text_type_tspan (RsvgNode *node, RsvgNodeText *self, RsvgDrawingCtx *ctx,
- gdouble *x, gdouble *y, gboolean *lastwasspace,
- gboolean usetextonly)
+draw_tspan (RsvgNode *node,
+ RsvgNodeText *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gdouble *y,
+ gboolean usetextonly)
{
double dx, dy, length = 0;
+ rsvg_state_push (ctx);
+
rsvg_state_reinherit_top (ctx, rsvg_node_get_state (node), 0);
dx = rsvg_length_normalize (&self->dx, ctx);
dy = rsvg_length_normalize (&self->dy, ctx);
if (rsvg_current_state (ctx)->text_anchor != TEXT_ANCHOR_START) {
- gboolean lws = *lastwasspace;
- _rsvg_node_text_length_children (node, ctx, &length, &lws, usetextonly);
+ compute_length_from_children (node, ctx, &length, usetextonly);
if (rsvg_current_state (ctx)->text_anchor == TEXT_ANCHOR_MIDDLE)
length /= 2;
}
@@ -442,16 +409,17 @@ _rsvg_node_text_type_tspan (RsvgNode *node, RsvgNodeText *self, RsvgDrawingCtx *
}
}
*y += dy;
- _rsvg_node_text_type_children (node, ctx, x, y, lastwasspace, usetextonly);
+ draw_from_children (node, ctx, x, y, usetextonly);
+
+ rsvg_state_pop (ctx);
}
static gboolean
-_rsvg_node_text_length_tspan (RsvgNode *node,
- RsvgNodeText *self,
- RsvgDrawingCtx *ctx,
- gdouble *length,
- gboolean *lastwasspace,
- gboolean usetextonly)
+length_from_tspan (RsvgNode *node,
+ RsvgNodeText *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *length,
+ gboolean usetextonly)
{
if (self->x_specified || self->y_specified)
return TRUE;
@@ -461,8 +429,7 @@ _rsvg_node_text_length_tspan (RsvgNode *node,
else
*length += rsvg_length_normalize (&self->dx, ctx);
- return _rsvg_node_text_length_children (node, ctx, length,
- lastwasspace, usetextonly);
+ return compute_length_from_children (node, ctx, length, usetextonly);
}
static void
@@ -497,9 +464,11 @@ rsvg_new_tspan (const char *element_name, RsvgNode *parent)
}
static void
-_rsvg_node_text_type_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
- gdouble * x, gdouble * y, gboolean * lastwasspace,
- gboolean usetextonly)
+draw_tref (RsvgNodeTref *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gdouble *y,
+ gboolean usetextonly)
{
RsvgNode *link;
@@ -509,14 +478,16 @@ _rsvg_node_text_type_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx,
if (link == NULL)
return;
- _rsvg_node_text_type_children (link, ctx, x, y, lastwasspace, TRUE);
+ draw_from_children (link, ctx, x, y, TRUE);
rsvg_drawing_ctx_release_node (ctx, link);
}
static gboolean
-_rsvg_node_text_length_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx, gdouble * x,
- gboolean * lastwasspace, gboolean usetextonly)
+length_from_tref (RsvgNodeTref *self,
+ RsvgDrawingCtx *ctx,
+ gdouble *x,
+ gboolean usetextonly)
{
gboolean result;
RsvgNode *link;
@@ -527,7 +498,7 @@ _rsvg_node_text_length_tref (RsvgNodeTref * self, RsvgDrawingCtx * ctx, gdouble
if (link == NULL)
return FALSE;
- result = _rsvg_node_text_length_children (link, ctx, x, lastwasspace, TRUE);
+ result = compute_length_from_children (link, ctx, x, TRUE);
rsvg_drawing_ctx_release_node (ctx, link);
@@ -578,127 +549,18 @@ rsvg_new_tref (const char *element_name, RsvgNode *parent)
rsvg_node_tref_free);
}
-typedef struct _RsvgTextLayout RsvgTextLayout;
-
-struct _RsvgTextLayout {
- PangoLayout *layout;
- RsvgDrawingCtx *ctx;
- TextAnchor anchor;
- gdouble x, y;
-};
+/* Defined in rust/src/text.rs */
+extern PangoLayout *rsvg_text_create_layout (RsvgDrawingCtx *ctx, const char *text);
static void
-rsvg_text_layout_free (RsvgTextLayout * layout)
-{
- g_object_unref (layout->layout);
- g_free (layout);
-}
-
-static PangoLayout *
-rsvg_text_create_layout (RsvgDrawingCtx * ctx, const char *text, PangoContext * context)
-{
- RsvgState *state;
- PangoFontDescription *font_desc;
- PangoLayout *layout;
- PangoAttrList *attr_list;
- PangoAttribute *attribute;
- double dpi_y;
-
- state = rsvg_current_state (ctx);
-
- if (state->lang)
- pango_context_set_language (context, pango_language_from_string (state->lang));
-
- if (state->unicode_bidi == UNICODE_BIDI_OVERRIDE || state->unicode_bidi == UNICODE_BIDI_EMBED)
- pango_context_set_base_dir (context, state->text_dir);
-
- if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity))
- pango_context_set_base_gravity (context, state->text_gravity);
-
- font_desc = pango_font_description_copy (pango_context_get_font_description (context));
-
- if (state->font_family)
- pango_font_description_set_family_static (font_desc, state->font_family);
-
- pango_font_description_set_style (font_desc, state->font_style);
- pango_font_description_set_variant (font_desc, state->font_variant);
- pango_font_description_set_weight (font_desc, state->font_weight);
- pango_font_description_set_stretch (font_desc, state->font_stretch);
-
- rsvg_drawing_ctx_get_dpi (ctx, NULL, &dpi_y);
- pango_font_description_set_size (font_desc,
- rsvg_drawing_ctx_get_normalized_font_size (ctx) * PANGO_SCALE / dpi_y * 72);
-
- layout = pango_layout_new (context);
- pango_layout_set_font_description (layout, font_desc);
- pango_font_description_free (font_desc);
-
- attr_list = pango_attr_list_new ();
- attribute = pango_attr_letter_spacing_new (rsvg_length_normalize (&state->letter_spacing, ctx) * PANGO_SCALE);
- attribute->start_index = 0;
- attribute->end_index = G_MAXINT;
- pango_attr_list_insert (attr_list, attribute);
-
- if (state->has_font_decor && text) {
- if (state->font_decor & TEXT_UNDERLINE) {
- attribute = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
- attribute->start_index = 0;
- attribute->end_index = -1;
- pango_attr_list_insert (attr_list, attribute);
- }
- if (state->font_decor & TEXT_STRIKE) {
- attribute = pango_attr_strikethrough_new (TRUE);
- attribute->start_index = 0;
- attribute->end_index = -1;
- pango_attr_list_insert (attr_list, attribute);
- }
- }
-
- pango_layout_set_attributes (layout, attr_list);
- pango_attr_list_unref (attr_list);
-
- if (text)
- pango_layout_set_text (layout, text, -1);
- else
- pango_layout_set_text (layout, NULL, 0);
-
- pango_layout_set_alignment (layout, (state->text_dir == PANGO_DIRECTION_LTR) ?
- PANGO_ALIGN_LEFT : PANGO_ALIGN_RIGHT);
-
- return layout;
-}
-
-
-static RsvgTextLayout *
-rsvg_text_layout_new (RsvgDrawingCtx * ctx, const char *text)
-{
- RsvgState *state;
- RsvgTextLayout *layout;
-
- state = rsvg_current_state (ctx);
-
- if (ctx->pango_context == NULL)
- ctx->pango_context = ctx->render->create_pango_context (ctx);
-
- layout = g_new0 (RsvgTextLayout, 1);
-
- layout->layout = rsvg_text_create_layout (ctx, text, ctx->pango_context);
- layout->ctx = ctx;
-
- layout->anchor = state->text_anchor;
-
- return layout;
-}
-
-void
rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdouble * y)
{
- PangoContext *context;
PangoLayout *layout;
PangoLayoutIter *iter;
RsvgState *state;
gint w, h;
double offset_x, offset_y, offset;
+ PangoGravity gravity;
state = rsvg_current_state (ctx);
@@ -706,13 +568,15 @@ rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdou
if (state->font_size.length == 0)
return;
- context = ctx->render->create_pango_context (ctx);
- layout = rsvg_text_create_layout (ctx, text, context);
+ layout = rsvg_text_create_layout (ctx, text);
pango_layout_get_size (layout, &w, &h);
iter = pango_layout_get_iter (layout);
offset = pango_layout_iter_get_baseline (iter) / (double) PANGO_SCALE;
offset += _rsvg_css_accumulate_baseline_shift (state, ctx);
- if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity)) {
+
+ gravity = rsvg_state_get_text_gravity (state);
+
+ if (PANGO_GRAVITY_IS_VERTICAL (gravity)) {
offset_x = -offset;
offset_y = 0;
} else {
@@ -720,37 +584,28 @@ rsvg_text_render_text (RsvgDrawingCtx * ctx, const char *text, gdouble * x, gdou
offset_y = offset;
}
pango_layout_iter_free (iter);
- ctx->render->render_pango_layout (ctx, layout, *x - offset_x, *y - offset_y);
- if (PANGO_GRAVITY_IS_VERTICAL (state->text_gravity))
+ rsvg_drawing_ctx_render_pango_layout (ctx, layout, *x - offset_x, *y - offset_y);
+ if (PANGO_GRAVITY_IS_VERTICAL (gravity))
*y += w / (double)PANGO_SCALE;
else
*x += w / (double)PANGO_SCALE;
g_object_unref (layout);
- g_object_unref (context);
}
static gdouble
-rsvg_text_layout_width (RsvgTextLayout * layout)
+measure_text (RsvgDrawingCtx * ctx, const char *text)
{
+ PangoLayout *layout;
gint width;
+ gdouble scaled_width;
- pango_layout_get_size (layout->layout, &width, NULL);
+ layout = rsvg_text_create_layout (ctx, text);
- return width / (double)PANGO_SCALE;
-}
+ pango_layout_get_size (layout, &width, NULL);
+ scaled_width = width / (double)PANGO_SCALE;
-static gdouble
-rsvg_text_length_text_as_string (RsvgDrawingCtx * ctx, const char *text)
-{
- RsvgTextLayout *layout;
- gdouble x;
-
- layout = rsvg_text_layout_new (ctx, text);
- layout->x = layout->y = 0;
-
- x = rsvg_text_layout_width (layout);
+ g_object_unref (layout);
- rsvg_text_layout_free (layout);
- return x;
+ return scaled_width;
}
diff --git a/rsvg-text.h b/rsvg-text.h
index e43b560f..e29d8924 100644
--- a/rsvg-text.h
+++ b/rsvg-text.h
@@ -38,8 +38,6 @@ G_GNUC_INTERNAL
RsvgNode *rsvg_new_tspan (const char *element_name, RsvgNode *parent);
G_GNUC_INTERNAL
RsvgNode *rsvg_new_tref (const char *element_name, RsvgNode *parent);
-G_GNUC_INTERNAL
-char *rsvg_make_valid_utf8 (const char *str, int len);
G_END_DECLS
diff --git a/rsvg.c b/rsvg.c
index 8c993410..cf3e4dba 100644
--- a/rsvg.c
+++ b/rsvg.c
@@ -45,9 +45,8 @@
/**
* rsvg_handle_get_pixbuf_sub:
* @handle: An #RsvgHandle
- * @id: (nullable): The id of an element inside the SVG, or %NULL to
- * render the whole SVG. For example, if you have a layer called
- * "layer1" that you wish to render, pass "##layer1" as the id.
+ * @id: (nullable): An element's id within the SVG, starting with "##", for
+ * example, "##layer1"; or %NULL to use the whole SVG.
*
* Returns the pixbuf loaded by @handle. The pixbuf returned will be reffed, so
* the caller of this function must assume that ref. If insufficient data has
diff --git a/rsvg.h b/rsvg.h
index fdc6aa96..94610853 100644
--- a/rsvg.h
+++ b/rsvg.h
@@ -65,11 +65,6 @@ typedef enum {
#define RSVG_ERROR (rsvg_error_quark ())
GQuark rsvg_error_quark (void) G_GNUC_CONST;
-/**
- * RsvgHandle:
- *
- * The #RsvgHandle is an object representing the parsed form of a SVG
- */
typedef struct _RsvgHandle RsvgHandle;
typedef struct RsvgHandlePrivate RsvgHandlePrivate;
typedef struct _RsvgHandleClass RsvgHandleClass;
@@ -80,7 +75,7 @@ typedef struct _RsvgPositionData RsvgPositionData;
* RsvgHandleClass:
* @parent: parent class
*
- * Class structure for #RsvgHandle
+ * Class structure for #RsvgHandle.
*/
struct _RsvgHandleClass {
GObjectClass parent;
@@ -89,6 +84,12 @@ struct _RsvgHandleClass {
gpointer _abi_padding[15];
};
+/**
+ * RsvgHandle:
+ * @parent: parent instance
+ *
+ * Lets you load SVG data and render it.
+ */
struct _RsvgHandle {
GObject parent;
@@ -219,7 +220,7 @@ void rsvg_handle_free (RsvgHandle * handle);
* Deprecated: Set up a cairo matrix and use rsvg_handle_render_cairo() instead.
* See the documentation for rsvg_handle_set_size_callback() for an example.
*/
-typedef /* RSVG_DEPRECATED */ void (*RsvgSizeFunc) (gint * width, gint * height, gpointer user_data);
+/* RSVG_DEPRECATED */ typedef void (*RsvgSizeFunc) (gint * width, gint * height, gpointer user_data);
RSVG_DEPRECATED
void rsvg_handle_set_size_callback (RsvgHandle * handle,
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 439daab0..a9fcef5c 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -1,3 +1,20 @@
+[root]
+name = "rsvg_internals"
+version = "0.0.1"
+dependencies = [
+ "cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cssparser 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "downcast-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "aho-corasick"
version = "0.6.4"
@@ -8,11 +25,6 @@ dependencies = [
[[package]]
name = "bitflags"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
-[[package]]
-name = "bitflags"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -23,20 +35,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cairo-rs"
-version = "0.2.0"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cairo-sys-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cairo-sys-rs"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -90,6 +102,11 @@ dependencies = [
]
[[package]]
+name = "either"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -105,45 +122,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "glib"
-version = "0.3.1"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "gobject-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glib-sys"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gobject-sys"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "itoa"
-version = "0.3.4"
+name = "itertools"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
-name = "lazy_static"
-version = "0.2.11"
+name = "itoa"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -170,6 +190,31 @@ dependencies = [
]
[[package]]
+name = "pango"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "pango-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "phf"
version = "0.7.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -245,21 +290,6 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
-name = "rsvg_internals"
-version = "0.0.1"
-dependencies = [
- "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cairo-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cairo-sys-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cssparser 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "downcast-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "siphasher"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -326,27 +356,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
-"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6237ac5a4b1e81c213c24c6437964c61e646df910a914b4ab1487b46df20bd13"
-"checksum cairo-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9d336f1b2ff46c17475a14360de7f456707008da475c54824887e52e453ab00"
-"checksum cairo-sys-rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e8a1e2a76ac09b959788c2c30a355d693ce6f7f7d7268f6d1dd5d8c3359c521"
+"checksum cairo-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b5695f59fd036fe5741bc5a4eb20c78fbe42256e3b08a2af26bbcbe8070bf3"
+"checksum cairo-sys-rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6e18fecaeac51809db57f45f4553cc0975225a7eb435a7a7e91e5e8113a84d"
"checksum cssparser 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2debe29d742180c2d5772c82fd3b024dc399b34afaf04fc7a30ed81af3dc6d67"
"checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
"checksum downcast-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "917042ca6e6c9fe735a63cd4d5d4c43c64ea8deb456fc5465d3f78df24e68d86"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum dtoa-short 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "068d4026697c1a18f0b0bb8cfcad1b0c151b90d8edb9bf4c235ad68128920d1d"
+"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
-"checksum glib 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d4da1d7f4bdc5c708d8ce4df1ac440dcb2f9d97d937c989032185a48aeef1d10"
-"checksum glib-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd7d911c5dc610aabe37caae7d3b9d2cfe6d8f4c85ff4c062f3d6f490e75067"
-"checksum gobject-sys 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "edc95561e538381576425264a4ddd08c65d5da218f10b2a47b4479dd147775da"
+"checksum glib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b0452824cc63066940f01adc721804919f0b76cdba3cfab977b00b87f16d4a"
+"checksum glib-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9693049613ff52b93013cc3d2590366d8e530366d288438724b73f6c7dc4be8"
+"checksum gobject-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60d507c87a71b1143c66ed21a969be9b99a76df234b342d733e787e6c9c7d7c2"
+"checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394"
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
-"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
+"checksum pango 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e81c404ab81ea7ea2fc2431a0a7672507b80e4b8bf4b41eac3fc83cc665104e"
+"checksum pango-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34f34a1be107fe16abb2744e0e206bee4b3b07460b5fddd3009a6aaf60bd69ab"
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index f33a50a8..9ae34a7b 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -5,15 +5,15 @@ authors = ["Federico Mena Quintero <federico@gnome.org>"]
[dependencies]
libc = "0.2"
-bitflags = "^0.9.1"
-#glib = "^0.1.3"
-#glib-sys = "^0.3.4"
downcast-rs = "^1.0.0"
regex = "^0.2.1"
+itertools = "0.7.4"
+pango = "0.3.0"
+pango-sys = "0.5.0"
cssparser = "^0.22.1"
[dependencies.cairo-sys-rs]
-version = "0.4.0"
+version = "0.5.0"
#git = "https://github.com/gtk-rs/cairo.git"
#branch = "master"
#git = "https://github.com/federicomenaquintero/cairo.git"
@@ -22,19 +22,19 @@ version = "0.4.0"
#features = ["png"]
[dependencies.cairo-rs]
-version = "0.2.0"
+version = "0.3.0"
#git = "https://github.com/gtk-rs/cairo.git"
#branch = "master"
#git = "file:///home/federico/src/gtk-rs/cairo"
#features = ["png"]
[dependencies.glib]
-version = "0.3.0"
+version = "0.4.0"
#git = "https://github.com/gtk-rs/glib.git"
#branch = "master"
[dependencies.glib-sys]
-version = "0.4.0"
+version = "0.5.0"
#git = "https://github.com/gtk-rs/sys"
#branch = "master"
diff --git a/rust/src/aspect_ratio.rs b/rust/src/aspect_ratio.rs
index 63482ba6..4be55401 100644
--- a/rust/src/aspect_ratio.rs
+++ b/rust/src/aspect_ratio.rs
@@ -1,12 +1,10 @@
-//! Handling of preserveAspectRatio values
+//! Handling of `preserveAspectRatio` values
//!
-//! This module handles preserveAspectRatio values [per the SVG specification][spec].
+//! This module handles `preserveAspectRatio` values [per the SVG specification][spec].
//! We have an [`AspectRatio`] struct which encapsulates such a value.
//!
-//! [`AspectRatio`] implements `FromStr`, so it can be parsed easily:
-//!
//! ```
-//! assert_eq! (AspectRatio::from_str ("xMidYMid"),
+//! assert_eq! (AspectRatio::parse ("xMidYMid", ()),
//! Ok (AspectRatio { defer: false,
//! align: Align::Aligned { align: AlignMode::XmidYmid,
//! fit: FitMode::Meet } }));
@@ -15,9 +13,6 @@
//! [`AspectRatio`]: struct.AspectRatio.html
//! [spec]: https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
-use ::libc;
-use ::glib::translate::*;
-
use parsers::Parse;
use parsers::ParseError;
use error::*;
@@ -71,75 +66,6 @@ fn align_1d (a: Align1D, dest_pos: f64, dest_size: f64, obj_size: f64) -> f64 {
}
impl AspectRatio {
- pub fn from_u32 (val: u32) -> AspectRatio {
- let val = AspectRatioFlags::from_bits (val).unwrap ();
-
- let defer = val.contains (DEFER);
-
- let mut aligned: bool = true;
-
- let align: AlignMode = {
- if val.contains (XMIN_YMIN) { AlignMode::XminYmin }
- else if val.contains (XMID_YMIN) { AlignMode::XmidYmin }
- else if val.contains (XMAX_YMIN) { AlignMode::XmaxYmin }
- else if val.contains (XMIN_YMID) { AlignMode::XminYmid }
- else if val.contains (XMID_YMID) { AlignMode::XmidYmid }
- else if val.contains (XMAX_YMID) { AlignMode::XmaxYmid }
- else if val.contains (XMIN_YMAX) { AlignMode::XminYmax }
- else if val.contains (XMID_YMAX) { AlignMode::XmidYmax }
- else if val.contains (XMAX_YMAX) { AlignMode::XmaxYmax }
- else {
- aligned = false;
- AlignMode::XmidYmid
- }
- };
-
- let fit: FitMode = if val.contains(SLICE) { FitMode::Slice } else { FitMode::Meet };
-
- AspectRatio {
- defer: defer,
- align: if aligned {
- Align::Aligned {
- align: align,
- fit: fit
- }
- } else {
- Align::None
- }
- }
- }
-
- pub fn to_u32 (&self) -> u32 {
- let mut val = AspectRatioFlags::empty ();
-
- if self.defer { val = val | DEFER; }
-
- match self.align {
- Align::None => { },
-
- Align::Aligned { align, fit } => {
- match align {
- AlignMode::XminYmin => { val = val | XMIN_YMIN; },
- AlignMode::XmidYmin => { val = val | XMID_YMIN; },
- AlignMode::XmaxYmin => { val = val | XMAX_YMIN; },
- AlignMode::XminYmid => { val = val | XMIN_YMID; },
- AlignMode::XmidYmid => { val = val | XMID_YMID; },
- AlignMode::XmaxYmid => { val = val | XMAX_YMID; },
- AlignMode::XminYmax => { val = val | XMIN_YMAX; },
- AlignMode::XmidYmax => { val = val | XMID_YMAX; },
- AlignMode::XmaxYmax => { val = val | XMAX_YMAX; },
- }
-
- match fit {
- FitMode::Meet => { },
- FitMode::Slice => { val = val | SLICE; }
- }
- }
- }
-
- val.bits ()
- }
-
pub fn compute (&self,
object_width: f64,
object_height: f64,
@@ -205,23 +131,6 @@ impl Default for AspectRatio {
}
}
-bitflags! {
- struct AspectRatioFlags: u32 {
- const XMIN_YMIN = (1 << 0);
- const XMID_YMIN = (1 << 1);
- const XMAX_YMIN = (1 << 2);
- const XMIN_YMID = (1 << 3);
- const XMID_YMID = (1 << 4);
- const XMAX_YMID = (1 << 5);
- const XMIN_YMAX = (1 << 6);
- const XMID_YMAX = (1 << 7);
- const XMAX_YMAX = (1 << 8);
- const SLICE = (1 << 30);
- const DEFER = (1 << 31);
- }
-}
-
-
fn parse_align_mode (s: &str) -> Option<Align> {
match s {
"none" => { Some (Align::None) },
@@ -267,9 +176,9 @@ impl Parse for AspectRatio {
let mut fit_mode = FitMode::Meet;
let mut state = ParseState::Defer;
- let mut iter = s.split_whitespace ();
- while let Some (v) = iter.next () {
+ for v in s.split_whitespace () {
+
match state {
ParseState::Defer => {
if v == "defer" {
@@ -330,38 +239,6 @@ impl Parse for AspectRatio {
}
}
-#[no_mangle]
-pub extern fn rsvg_aspect_ratio_parse (c_str: *const libc::c_char) -> u32 {
- let my_str = unsafe { &String::from_glib_none (c_str) };
- let parsed = AspectRatio::parse (my_str, ());
-
- match parsed {
- Ok (aspect_ratio) => { aspect_ratio.to_u32 () },
- Err (_) => {
- // We can't propagate the error here, so just return a default value
- let a: AspectRatio = Default::default ();
- a.to_u32 ()
- }
- }
-}
-
-#[no_mangle]
-pub extern fn rsvg_aspect_ratio_compute (aspect: u32,
- object_width: f64,
- object_height: f64,
- dest_x: *mut f64,
- dest_y: *mut f64,
- dest_width: *mut f64,
- dest_height: *mut f64) {
- unsafe {
- let (x, y, w, h) = AspectRatio::from_u32 (aspect).compute (object_width, object_height, *dest_x, *dest_y, *dest_width, *dest_height);
- *dest_x = x;
- *dest_y = y;
- *dest_width = w;
- *dest_height = h;
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -417,20 +294,6 @@ mod tests {
fit: FitMode::Slice } }));
}
- fn test_roundtrip (s: &str) {
- let a = AspectRatio::parse (s, ()).unwrap ();
-
- assert_eq! (AspectRatio::from_u32 (a.to_u32 ()), a);
- }
-
- #[test]
- fn conversion_to_u32_roundtrips () {
- test_roundtrip ("defer xMidYMid");
- test_roundtrip ("defer xMinYMax slice");
- test_roundtrip ("xMaxYMax meet");
- test_roundtrip ("xMinYMid slice");
- }
-
#[test]
fn aligns () {
assert_eq! (AspectRatio::parse ("xMinYMin meet", ()).unwrap().compute (1.0, 10.0, 0.0, 0.0, 10.0, 1.0), (0.0, 0.0, 0.1, 1.0));
diff --git a/rust/src/bbox.rs b/rust/src/bbox.rs
index ba179081..9cf4827b 100644
--- a/rust/src/bbox.rs
+++ b/rust/src/bbox.rs
@@ -41,22 +41,14 @@ pub extern fn rsvg_bbox_insert (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox
return;
}
- let mut xmin: f64;
- let mut ymin: f64;
- let mut xmax: f64;
- let mut ymax: f64;
-
- if !dst.is_virgin () {
- xmin = dst.rect.x;
- ymin = dst.rect.y;
- xmax = dst.rect.x + dst.rect.width;
- ymax = dst.rect.y + dst.rect.height;
+ let (mut xmin, mut ymin, mut xmax, mut ymax) = if !dst.is_virgin () {
+ (dst.rect.x,
+ dst.rect.y,
+ (dst.rect.x + dst.rect.width),
+ (dst.rect.y + dst.rect.height))
} else {
- xmin = 0.0;
- ymin = 0.0;
- xmax = 0.0;
- ymax = 0.0;
- }
+ (0.0, 0.0, 0.0, 0.0)
+ };
let mut affine = dst.affine;
@@ -71,8 +63,8 @@ pub extern fn rsvg_bbox_insert (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox
* the width/height to the first point src.rect.(x, y).
*/
for i in 0..4 {
- let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
- let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
+ let rx: f64 = src.rect.x + src.rect.width * f64::from(i % 2);
+ let ry: f64 = src.rect.y + src.rect.height * f64::from(i / 2);
let x: f64 = affine.xx * rx + affine.xy * ry + affine.x0;
let y: f64 = affine.yx * rx + affine.yy * ry + affine.y0;
@@ -108,22 +100,14 @@ pub extern fn rsvg_bbox_clip (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox)
return;
}
- let mut xmin: f64;
- let mut ymin: f64;
- let mut xmax: f64;
- let mut ymax: f64;
-
- if !dst.is_virgin () {
- xmin = dst.rect.x + dst.rect.width;
- ymin = dst.rect.y + dst.rect.height;
- xmax = dst.rect.x;
- ymax = dst.rect.y;
+ let (mut xmin, mut ymin, mut xmax, mut ymax) = if !dst.is_virgin () {
+ ((dst.rect.x + dst.rect.width),
+ (dst.rect.y + dst.rect.height),
+ dst.rect.x,
+ dst.rect.y)
} else {
- xmin = 0.0;
- ymin = 0.0;
- xmax = 0.0;
- ymax = 0.0;
- }
+ (0.0, 0.0, 0.0, 0.0)
+ };
let mut affine = dst.affine;
@@ -132,8 +116,8 @@ pub extern fn rsvg_bbox_clip (raw_dst: *mut RsvgBbox, raw_src: *const RsvgBbox)
/* This is a trick. See rsvg_bbox_insert() for a description of how it works. */
for i in 0..4 {
- let rx: f64 = src.rect.x + src.rect.width * (i % 2) as f64;
- let ry: f64 = src.rect.y + src.rect.height * (i / 2) as f64;
+ let rx: f64 = src.rect.x + src.rect.width * f64::from(i % 2);
+ let ry: f64 = src.rect.y + src.rect.height * f64::from(i / 2);
let x = affine.xx * rx + affine.xy * ry + affine.x0;
let y = affine.yx * rx + affine.yy * ry + affine.y0;
diff --git a/rust/src/chars.rs b/rust/src/chars.rs
new file mode 100644
index 00000000..3faa5586
--- /dev/null
+++ b/rust/src/chars.rs
@@ -0,0 +1,118 @@
+use libc;
+use std;
+use std::cell::RefCell;
+
+use drawing_ctx::{self, RsvgDrawingCtx};
+use handle::RsvgHandle;
+use node::{NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode, boxed_node_new, rsvg_node_get_state};
+use property_bag::RsvgPropertyBag;
+
+/// Container for XML character data.
+///
+/// In SVG text elements, we use `NodeChars` to store character data. For example,
+/// an element like `<text>Foo Bar</text>` will be a `NodeText` with a single child,
+/// and the child will be a `NodeChars` with "Foo Bar" for its contents.
+/// ```
+///
+/// Text elements can contain `<tspan>` sub-elements. In this case,
+/// those `tspan` nodes will also contain `NodeChars` children.
+///
+/// A text or tspan element can contain more than one `NodeChars` child, for example,
+/// if there is an XML comment that splits the character contents in two:
+///
+/// ```xml
+/// <text>
+/// This sentence will create a NodeChars.
+/// <!-- this comment is ignored -->
+/// This sentence will cretea another NodeChars.
+/// </text>
+/// ```
+///
+/// When rendering a text element, it will take care of concatenating
+/// the strings in its `NodeChars` children as appropriate, depending
+/// on the `xml:space="preserve"` attribute. A `NodeChars` stores the
+/// characters verbatim as they come out of the XML parser, after
+/// ensuring that they are valid UTF-8.
+struct NodeChars {
+ string: RefCell<String>
+}
+
+impl NodeChars {
+ fn new() -> NodeChars {
+ NodeChars {
+ string: RefCell::new(String::new())
+ }
+ }
+
+ fn append(&self, s: &str) {
+ self.string.borrow_mut().push_str(s);
+ }
+}
+
+impl NodeTrait for NodeChars {
+ fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: *const RsvgPropertyBag) -> NodeResult {
+ Ok(())
+ }
+
+ fn draw(&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
+ // nothing
+ }
+
+ fn get_c_impl(&self) -> *const RsvgCNodeImpl {
+ unreachable!();
+ }
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_chars_new(raw_parent: *const RsvgNode) -> *const RsvgNode {
+ let node = boxed_node_new(NodeType::Chars,
+ raw_parent,
+ Box::new(NodeChars::new()));
+
+ let state = rsvg_node_get_state(node);
+ drawing_ctx::state_set_cond_true(state, false);
+
+ node
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_chars_append(raw_node: *const RsvgNode,
+ text: *const libc::c_char,
+ len: isize) {
+ assert!(!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ assert!(!text.is_null());
+ assert!(len >= 0);
+
+ // We don't use from_glib to convert the text here, since we are
+ // not sure that it actually is valid UTF-8. We can't use CStr
+ // because we are not getting passed nul-terminated data. We'll
+ // do this by hand instead.
+
+ let bytes = unsafe { std::slice::from_raw_parts(text as *const u8, len as usize) };
+ let utf8 = String::from_utf8_lossy(bytes);
+
+ node.with_impl(|chars: &NodeChars| {
+ chars.append(&utf8);
+ });
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_chars_get_string(raw_node: *const RsvgNode,
+ out_str: *mut *const libc::c_char,
+ out_len: *mut usize) {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ assert!(!out_str.is_null());
+ assert!(!out_len.is_null());
+
+ node.with_impl(|chars: &NodeChars| {
+ let s = chars.string.borrow();
+ unsafe {
+ *out_str = s.as_ptr() as *const libc::c_char;
+ *out_len = s.len();
+ }
+ });
+}
diff --git a/rust/src/clip_path.rs b/rust/src/clip_path.rs
new file mode 100644
index 00000000..0a3eab05
--- /dev/null
+++ b/rust/src/clip_path.rs
@@ -0,0 +1,59 @@
+use libc;
+use std::cell::Cell;
+
+use drawing_ctx::RsvgDrawingCtx;
+use handle::RsvgHandle;
+use node::{NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode, boxed_node_new};
+use coord_units::CoordUnits;
+use property_bag::{self, RsvgPropertyBag};
+
+coord_units!(ClipPathUnits, CoordUnits::UserSpaceOnUse);
+
+struct NodeClipPath {
+ units: Cell<ClipPathUnits>
+}
+
+impl NodeClipPath {
+ fn new() -> NodeClipPath {
+ NodeClipPath {
+ units: Cell::new(ClipPathUnits::default())
+ }
+ }
+}
+
+impl NodeTrait for NodeClipPath {
+ fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
+ self.units.set(property_bag::parse_or_default(pbag, "clipPathUnits", (), None)?);
+
+ Ok(())
+ }
+
+ fn draw(&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
+ // nothing; clip paths are handled specially
+ }
+
+ fn get_c_impl(&self) -> *const RsvgCNodeImpl {
+ unreachable!();
+ }
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_clip_path_new(_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
+ boxed_node_new(NodeType::ClipPath,
+ raw_parent,
+ Box::new(NodeClipPath::new()))
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_clip_path_get_units(raw_node: *const RsvgNode) -> CoordUnits {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut units = ClipPathUnits::default();
+
+ node.with_impl(|clip_path: &NodeClipPath| {
+ units = clip_path.units.get();
+ });
+
+ CoordUnits::from(units)
+}
diff --git a/rust/src/color.rs b/rust/src/color.rs
index 5928e419..3aa0aff4 100644
--- a/rust/src/color.rs
+++ b/rust/src/color.rs
@@ -108,10 +108,10 @@ impl Color {
}
fn rgba_from_argb (argb: u32) -> cssparser::RGBA {
- cssparser::RGBA::new (((argb & 0x00ff0000) >> 16) as u8,
- ((argb & 0x0000ff00) >> 8) as u8,
- ((argb & 0x000000ff) as u8),
- ((argb & 0xff000000) >> 24) as u8)
+ cssparser::RGBA::new (((argb & 0x00ff_0000) >> 16) as u8,
+ ((argb & 0x0000_ff00) >> 8) as u8,
+ ((argb & 0x0000_00ff) as u8),
+ ((argb & 0xff00_0000) >> 24) as u8)
}
impl From<cssparser::Color> for Color {
@@ -147,10 +147,10 @@ impl From<Result<Color, AttributeError>> for ColorSpec {
Ok (Color::RGBA (rgba)) =>
ColorSpec {
kind: ColorKind::ARGB,
- argb: ((rgba.alpha as u32) << 24 |
- (rgba.red as u32) << 16 |
- (rgba.green as u32) << 8 |
- (rgba.blue as u32))
+ argb: (u32::from(rgba.alpha) << 24 |
+ u32::from(rgba.red) << 16 |
+ u32::from(rgba.green) << 8 |
+ u32::from(rgba.blue))
},
_ =>
diff --git a/rust/src/coord_units.rs b/rust/src/coord_units.rs
new file mode 100644
index 00000000..845961dd
--- /dev/null
+++ b/rust/src/coord_units.rs
@@ -0,0 +1,93 @@
+use error::AttributeError;
+use parsers::{Parse, ParseError};
+
+/// Defines the units to be used for things that can consider a
+/// coordinate system in terms of the current transformation, or in
+/// terms of the current object's bounding box.
+///
+/// Keep in sync with rsvg-private.h:RsvgCoordUnits
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum CoordUnits {
+ UserSpaceOnUse,
+ ObjectBoundingBox
+}
+
+impl Parse for CoordUnits {
+ type Data = ();
+ type Err = AttributeError;
+
+ fn parse (s: &str, _: ()) -> Result<CoordUnits, AttributeError> {
+ match s {
+ "userSpaceOnUse" => Ok (CoordUnits::UserSpaceOnUse),
+ "objectBoundingBox" => Ok (CoordUnits::ObjectBoundingBox),
+ _ => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' or 'objectBoundingBox'")))
+ }
+ }
+}
+
+/// Creates a newtype around `CoordUnits`, with a default value.
+///
+/// SVG attributes that can take `userSpaceOnUse` or
+/// `objectBoundingBox` values often have different default values
+/// depending on the type of SVG element. We use this macro to create
+/// a newtype for each SVG element and attribute that requires values
+/// of this type. The newtype provides an `impl Default` with the
+/// specified `$default` value.
+#[macro_export]
+macro_rules! coord_units {
+ ($name:ident, $default:expr) => {
+ #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+ struct $name(CoordUnits);
+
+ impl Default for $name {
+ fn default() -> Self {
+ $name($default)
+ }
+ }
+
+ impl From<$name> for CoordUnits {
+ fn from(u: $name) -> Self {
+ u.0
+ }
+ }
+
+ impl $crate::parsers::Parse for $name {
+ type Data = ();
+ type Err = $crate::error::AttributeError;
+
+ fn parse(s: &str, _: ()) -> Result<Self, $crate::error::AttributeError> {
+ Ok($name($crate::coord_units::CoordUnits::parse(s, ())?))
+ }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ coord_units!(MyUnits, CoordUnits::ObjectBoundingBox);
+
+ #[test]
+ fn parsing_invalid_strings_yields_error () {
+ assert! (MyUnits::parse ("", ()).is_err ());
+ assert! (MyUnits::parse ("foo", ()).is_err ());
+ }
+
+ #[test]
+ fn parses_paint_server_units () {
+ assert_eq! (MyUnits::parse ("userSpaceOnUse", ()), Ok (MyUnits(CoordUnits::UserSpaceOnUse)));
+ assert_eq! (MyUnits::parse ("objectBoundingBox", ()), Ok (MyUnits(CoordUnits::ObjectBoundingBox)));
+ }
+
+ #[test]
+ fn has_correct_default() {
+ assert_eq!(MyUnits::default(), MyUnits(CoordUnits::ObjectBoundingBox));
+ }
+
+ #[test]
+ fn converts_to_coord_units() {
+ assert_eq!(CoordUnits::from(MyUnits(CoordUnits::ObjectBoundingBox)), CoordUnits::ObjectBoundingBox);
+ }
+}
diff --git a/rust/src/drawing_ctx.rs b/rust/src/drawing_ctx.rs
index ee25c622..b013bd01 100644
--- a/rust/src/drawing_ctx.rs
+++ b/rust/src/drawing_ctx.rs
@@ -1,8 +1,10 @@
-use ::cairo;
-use ::cairo_sys;
-use ::glib_sys;
-use ::glib::translate::*;
-use ::libc;
+use cairo;
+use cairo_sys;
+use glib_sys;
+use glib::translate::*;
+use libc;
+use pango_sys;
+use pango;
use color::*;
use error::*;
@@ -46,6 +48,13 @@ extern "C" {
fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
affine: *const cairo::Matrix);
+ fn rsvg_drawing_ctx_get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> *mut pango_sys::PangoContext;
+
+ fn rsvg_drawing_ctx_render_pango_layout(draw_ctx: *const RsvgDrawingCtx,
+ layout: *const pango_sys::PangoLayout,
+ x: f64,
+ y: f64);
+
fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
x: f64,
y: f64,
@@ -64,6 +73,7 @@ extern "C" {
fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
+ fn rsvg_state_set_cond_true (state: *const RsvgState, cond_true: glib_sys::gboolean);
fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
fn rsvg_state_get_stop_opacity (state: *const RsvgState) -> *const OpacitySpec;
fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;
@@ -173,9 +183,7 @@ pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
unsafe {
let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);
- let cr = cairo::Context::from_glib_none (raw_cr);
-
- cr
+ cairo::Context::from_glib_none (raw_cr)
}
}
@@ -199,6 +207,21 @@ pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo:
}
}
+pub fn get_pango_context(draw_ctx: *const RsvgDrawingCtx) -> pango::Context {
+ unsafe {
+ from_glib_full(rsvg_drawing_ctx_get_pango_context(draw_ctx))
+ }
+}
+
+pub fn render_pango_layout(draw_ctx: *const RsvgDrawingCtx,
+ layout: pango::Layout,
+ x: f64,
+ y: f64) {
+ unsafe {
+ rsvg_drawing_ctx_render_pango_layout(draw_ctx, layout.to_glib_none().0, x, y);
+ }
+}
+
pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
x: f64,
y: f64,
@@ -245,6 +268,10 @@ pub fn state_get_cond_true (state: *const RsvgState) -> bool {
unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}
+pub fn state_set_cond_true (state: *const RsvgState, cond_true: bool) {
+ unsafe { rsvg_state_set_cond_true (state, cond_true.to_glib()); }
+}
+
pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
unsafe {
rsvg_state_push (draw_ctx);
@@ -264,7 +291,7 @@ pub fn state_get_stop_color (state: *const RsvgState) -> Result<Option<Color>, A
if spec_ptr.is_null () {
Ok (None)
} else {
- Color::from_color_spec (&*spec_ptr).map (|color| Some (color))
+ Color::from_color_spec (&*spec_ptr).map (Some)
}
}
}
@@ -276,7 +303,7 @@ pub fn state_get_stop_opacity (state: *const RsvgState) -> Result<Option<Opacity
if opacity_ptr.is_null () {
Ok (None)
} else {
- Opacity::from_opacity_spec (&*opacity_ptr).map (|opacity| Some (opacity))
+ Opacity::from_opacity_spec (&*opacity_ptr).map (Some)
}
}
}
diff --git a/rust/src/error.rs b/rust/src/error.rs
index f1209eef..615415c1 100644
--- a/rust/src/error.rs
+++ b/rust/src/error.rs
@@ -46,8 +46,8 @@ impl NodeError {
impl error::Error for NodeError {
fn description (&self) -> &str {
match self.err {
- AttributeError::Parse (_) => &"parse error",
- AttributeError::Value (_) => &"invalid attribute value"
+ AttributeError::Parse (_) => "parse error",
+ AttributeError::Value (_) => "invalid attribute value"
}
}
}
diff --git a/rust/src/gradient.rs b/rust/src/gradient.rs
index e02b2485..d48bed96 100644
--- a/rust/src/gradient.rs
+++ b/rust/src/gradient.rs
@@ -8,6 +8,7 @@ use std::cell::RefCell;
use cairo::MatrixTrait;
use bbox::*;
+use coord_units::CoordUnits;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use handle::RsvgHandle;
@@ -22,18 +23,20 @@ use util::*;
#[derive(Copy, Clone)]
-pub struct ColorStop {
+struct ColorStop {
pub offset: f64,
pub rgba: u32
}
+coord_units!(GradientUnits, CoordUnits::ObjectBoundingBox);
+
/* Any of the attributes in gradient elements may be omitted. In turn, the missing
* ones can be inherited from the gradient referenced by its "fallback" IRI. We
* represent these possibly-missing attributes as Option<foo>.
*/
#[derive(Clone)]
-pub struct GradientCommon {
- pub units: Option<PaintServerUnits>,
+struct GradientCommon {
+ pub units: Option<GradientUnits>,
pub affine: Option<cairo::Matrix>,
pub spread: Option<PaintServerSpread>,
pub fallback: Option<String>,
@@ -41,7 +44,7 @@ pub struct GradientCommon {
}
#[derive(Copy, Clone)]
-pub enum GradientVariant {
+enum GradientVariant {
Linear {
x1: Option<RsvgLength>,
y1: Option<RsvgLength>,
@@ -59,7 +62,7 @@ pub enum GradientVariant {
}
#[derive(Clone)]
-pub struct Gradient {
+struct Gradient {
pub common: GradientCommon,
pub variant: GradientVariant
}
@@ -118,7 +121,7 @@ impl GradientCommon {
fn resolve_from_defaults (&mut self) {
/* These are per the spec */
- fallback_to! (self.units, Some (PaintServerUnits::default ()));
+ fallback_to! (self.units, Some (GradientUnits::default ()));
fallback_to! (self.affine, Some (cairo::Matrix::identity ()));
fallback_to! (self.spread, Some (PaintServerSpread::default ()));
fallback_to! (self.stops, Some (Vec::<ColorStop>::new ())); // empty array of color stops
@@ -141,11 +144,11 @@ impl GradientCommon {
}
if let Some (ref mut stops) = self.stops {
- let mut last_offset: f64 = 0.0;
-
- if stops.len () > 0 {
- last_offset = stops[stops.len () - 1].offset;
- }
+ let last_offset: f64 = if !stops.is_empty() {
+ stops[stops.len () - 1].offset
+ } else {
+ 0.0
+ };
if last_offset > offset {
offset = last_offset;
@@ -207,7 +210,7 @@ impl GradientVariant {
fn resolve_from_fallback (&mut self, fallback: &GradientVariant) {
match *self {
GradientVariant::Linear { ref mut x1, ref mut y1, ref mut x2, ref mut y2 } => {
- if let &GradientVariant::Linear { x1: x1f, y1: y1f, x2: x2f, y2: y2f } = fallback {
+ if let GradientVariant::Linear { x1: x1f, y1: y1f, x2: x2f, y2: y2f } = *fallback {
fallback_to! (*x1, x1f);
fallback_to! (*y1, y1f);
fallback_to! (*x2, x2f);
@@ -216,7 +219,7 @@ impl GradientVariant {
},
GradientVariant::Radial { ref mut cx, ref mut cy, ref mut r, ref mut fx, ref mut fy } => {
- if let &GradientVariant::Radial { cx: cxf, cy: cyf, r: rf, fx: fxf, fy: fyf } = fallback {
+ if let GradientVariant::Radial { cx: cxf, cy: cyf, r: rf, fx: fxf, fy: fyf } = *fallback {
fallback_to! (*cx, cxf);
fallback_to! (*cy, cyf);
fallback_to! (*r, rf);
@@ -246,19 +249,21 @@ impl Gradient {
fn add_color_stops_from_node (&mut self, node: &RsvgNode) {
assert! (node.get_type () == NodeType::LinearGradient || node.get_type () == NodeType::RadialGradient);
- for child in &*node.children.borrow () {
+ node.foreach_child(|child| {
if child.get_type () != NodeType::Stop {
- continue; // just ignore this child; we are only interested in gradient stops
+ return true; // just ignore this child; we are only interested in gradient stops
}
if child.get_result ().is_err () {
- break; // don't add any more stops
+ return false; // don't add any more stops
}
child.with_impl (|stop: &NodeStop| {
self.add_color_stop (stop.get_offset (), stop.get_rgba ());
});
- }
+
+ true
+ });
}
fn add_color_stop (&mut self, offset: f64, rgba: u32) {
@@ -273,10 +278,10 @@ impl Gradient {
for stop in stops {
let rgba = stop.rgba;
pattern.add_color_stop_rgba (stop.offset,
- ((rgba >> 24) & 0xff) as f64 / 255.0,
- ((rgba >> 16) & 0xff) as f64 / 255.0,
- ((rgba >> 8) & 0xff) as f64 / 255.0,
- (((rgba >> 0) & 0xff) * opacity as u32) as f64 / 255.0 / 255.0);
+ (f64::from((rgba >> 24) & 0xff)) / 255.0,
+ (f64::from((rgba >> 16) & 0xff)) / 255.0,
+ (f64::from((rgba >> 8) & 0xff)) / 255.0,
+ f64::from(((rgba >> 0) & 0xff) * u32::from(opacity)) / 255.0 / 255.0);
}
}
}
@@ -346,7 +351,7 @@ impl FallbackSource for NodeFallbackSource {
self.acquired_nodes.push (fallback_node);
- return Some (node.clone ());
+ Some (node.clone ())
}
}
@@ -362,7 +367,7 @@ fn set_common_on_pattern<P: cairo::Pattern + cairo::Gradient> (gradient: &Gradie
let units = gradient.common.units.unwrap ();
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
let bbox_matrix = cairo::Matrix::new (bbox.rect.width, 0.0,
0.0, bbox.rect.height,
bbox.rect.x, bbox.rect.y);
@@ -385,7 +390,7 @@ fn set_linear_gradient_on_pattern (gradient: &Gradient,
if let GradientVariant::Linear { x1, y1, x2, y2 } = gradient.variant {
let units = gradient.common.units.unwrap ();
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
}
@@ -394,7 +399,7 @@ fn set_linear_gradient_on_pattern (gradient: &Gradient,
x2.as_ref ().unwrap ().normalize (draw_ctx),
y2.as_ref ().unwrap ().normalize (draw_ctx));
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
drawing_ctx::pop_view_box (draw_ctx);
}
@@ -467,7 +472,7 @@ fn set_radial_gradient_on_pattern (gradient: &Gradient,
if let GradientVariant::Radial { cx, cy, r, fx, fy } = gradient.variant {
let units = gradient.common.units.unwrap ();
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
}
@@ -481,7 +486,7 @@ fn set_radial_gradient_on_pattern (gradient: &Gradient,
let mut pattern = cairo::RadialGradient::new (new_fx, new_fy, 0.0, n_cx, n_cy, n_r);
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
drawing_ctx::pop_view_box (draw_ctx);
}
@@ -638,7 +643,7 @@ pub extern fn gradient_resolve_fallbacks_and_set_pattern (raw_node: *const R
let mut did_set_gradient = false;
node.with_impl (|node_gradient: &NodeGradient| {
- let gradient = node_gradient.get_gradient_with_color_stops_from_node (&node);
+ let gradient = node_gradient.get_gradient_with_color_stops_from_node (node);
did_set_gradient = resolve_fallbacks_and_set_pattern (&gradient, draw_ctx, opacity, bbox);
});
diff --git a/rust/src/image.rs b/rust/src/image.rs
index 6b415e4d..514c7fa6 100644
--- a/rust/src/image.rs
+++ b/rust/src/image.rs
@@ -93,21 +93,16 @@ impl NodeTrait for NodeImage {
let aspect = self.aspect.get();
if !drawing_ctx::state_is_overflow(state) {
- match aspect.align {
- Align::Aligned { align: _,
- fit: FitMode::Slice } => {
- drawing_ctx::add_clipping_rect(draw_ctx, x, y, w, h);
- },
-
- _ => ()
+ if let Align::Aligned {fit: FitMode::Slice, ..} = aspect.align {
+ drawing_ctx::add_clipping_rect(draw_ctx, x, y, w, h);
}
}
- let (x, y, w, h) = aspect.compute (surface.get_width() as f64,
- surface.get_height() as f64,
+ let (x, y, w, h) = aspect.compute (f64::from(surface.get_width()),
+ f64::from(surface.get_height()),
x, y, w, h);
- drawing_ctx::render_surface(draw_ctx, &surface, x, y, w, h);
+ drawing_ctx::render_surface(draw_ctx, surface, x, y, w, h);
drawing_ctx::pop_discrete_layer(draw_ctx);
}
diff --git a/rust/src/length.rs b/rust/src/length.rs
index 92c65d5c..54cf65be 100644
--- a/rust/src/length.rs
+++ b/rust/src/length.rs
@@ -82,7 +82,7 @@ pub extern fn rsvg_length_parse (string: *const libc::c_char, dir: LengthDir) ->
let my_string = unsafe { &String::from_glib_none (string) };
// FIXME: this ignores errors; propagate them upstream
- RsvgLength::parse (my_string, dir).unwrap_or (RsvgLength::default ())
+ RsvgLength::parse (my_string, dir).unwrap_or_else(|_| {RsvgLength::default ()})
}
/* https://www.w3.org/TR/SVG/types.html#DataTypeLength
@@ -109,89 +109,11 @@ impl Parse for RsvgLength {
let mut input = ParserInput::new (string);
let mut parser = Parser::new (&mut input);
- let length = {
- let token = parser.next ()
- .map_err (|_| AttributeError::Parse (ParseError::new ("expected number and optional symbol, or number and percentage")))?;
-
- match *token {
- Token::Number { value, .. } => RsvgLength { length: value as f64,
- unit: LengthUnit::Default,
- dir: dir },
-
- Token::Percentage { unit_value, .. } => RsvgLength { length: unit_value as f64,
- unit: LengthUnit::Percent,
- dir: dir },
-
- Token::Dimension { value, ref unit, .. } => {
- let value = value as f64;
-
- match unit.as_ref () {
- "em" => RsvgLength { length: value,
- unit: LengthUnit::FontEm,
- dir: dir },
-
- "ex" => RsvgLength { length: value,
- unit: LengthUnit::FontEx,
- dir: dir },
-
- "pt" => RsvgLength { length: value / POINTS_PER_INCH,
- unit: LengthUnit::Inch,
- dir: dir },
-
- "in" => RsvgLength { length: value,
- unit: LengthUnit::Inch,
- dir: dir },
-
- "cm" => RsvgLength { length: value / CM_PER_INCH,
- unit: LengthUnit::Inch,
- dir: dir },
-
- "mm" => RsvgLength { length: value / MM_PER_INCH,
- unit: LengthUnit::Inch,
- dir: dir },
-
- "pc" => RsvgLength { length: value / PICA_PER_INCH,
- unit: LengthUnit::Inch,
- dir: dir },
-
- "px" => RsvgLength { length: value,
- unit: LengthUnit::Default,
- dir: dir },
-
- _ => return Err (make_err ())
- }
- },
-
- // FIXME: why are the following in Length? They should be in FontSize
- Token::Ident (ref cow) => match cow.as_ref () {
- "larger" => RsvgLength { length: 0.0,
- unit: LengthUnit::RelativeLarger,
- dir: dir },
-
- "smaller" => RsvgLength { length: 0.0,
- unit: LengthUnit::RelativeSmaller,
- dir: dir },
-
- "xx-small" |
- "x-small" |
- "small" |
- "medium" |
- "large" |
- "x-large" |
- "xx-large" => RsvgLength { length: compute_named_size (&*string),
- unit: LengthUnit::Inch,
- dir: dir },
-
- _ => return Err (make_err ())
- },
-
- _ => return Err (make_err ())
- }
- };
+ let length = RsvgLength::from_cssparser(&mut parser, dir)?;
parser.expect_exhausted ().map_err (|_| make_err ())?;
- Ok (length)
+ Ok(length)
}
}
@@ -270,6 +192,91 @@ impl RsvgLength {
_ => { 0.0 }
}
}
+
+ fn from_cssparser(parser: &mut Parser, dir: LengthDir) -> Result <RsvgLength, AttributeError> {
+
+ let length = {
+ let token = parser.next ()
+ .map_err (|_| AttributeError::Parse (ParseError::new ("expected number and optional symbol, or number and percentage")))?;
+
+ match *token {
+ Token::Number { value, .. } => RsvgLength { length: f64::from(value),
+ unit: LengthUnit::Default,
+ dir: dir },
+
+ Token::Percentage { unit_value, .. } => RsvgLength { length: f64::from(unit_value),
+ unit: LengthUnit::Percent,
+ dir: dir },
+
+ Token::Dimension { value, ref unit, .. } => {
+ let value = f64::from(value);
+
+ match unit.as_ref () {
+ "em" => RsvgLength { length: value,
+ unit: LengthUnit::FontEm,
+ dir: dir },
+
+ "ex" => RsvgLength { length: value,
+ unit: LengthUnit::FontEx,
+ dir: dir },
+
+ "pt" => RsvgLength { length: value / POINTS_PER_INCH,
+ unit: LengthUnit::Inch,
+ dir: dir },
+
+ "in" => RsvgLength { length: value,
+ unit: LengthUnit::Inch,
+ dir: dir },
+
+ "cm" => RsvgLength { length: value / CM_PER_INCH,
+ unit: LengthUnit::Inch,
+ dir: dir },
+
+ "mm" => RsvgLength { length: value / MM_PER_INCH,
+ unit: LengthUnit::Inch,
+ dir: dir },
+
+ "pc" => RsvgLength { length: value / PICA_PER_INCH,
+ unit: LengthUnit::Inch,
+ dir: dir },
+
+ "px" => RsvgLength { length: value,
+ unit: LengthUnit::Default,
+ dir: dir },
+
+ _ => return Err (make_err ())
+ }
+ },
+
+ // FIXME: why are the following in Length? They should be in FontSize
+ Token::Ident (ref cow) => match cow.as_ref () {
+ "larger" => RsvgLength { length: 0.0,
+ unit: LengthUnit::RelativeLarger,
+ dir: dir },
+
+ "smaller" => RsvgLength { length: 0.0,
+ unit: LengthUnit::RelativeSmaller,
+ dir: dir },
+
+ "xx-small" |
+ "x-small" |
+ "small" |
+ "medium" |
+ "large" |
+ "x-large" |
+ "xx-large" => RsvgLength { length: compute_named_size (cow),
+ unit: LengthUnit::Inch,
+ dir: dir },
+
+ _ => return Err (make_err ())
+ },
+
+ _ => return Err (make_err ())
+ }
+ };
+
+ Ok (length)
+ }
}
fn viewport_percentage (x: f64, y: f64) -> f64 {
@@ -279,7 +286,7 @@ fn viewport_percentage (x: f64, y: f64) -> f64 {
* percentage is calculated as the specified percentage of
* sqrt((actual-width)**2 + (actual-height)**2))/sqrt(2)."
*/
- return (x * x + y * y).sqrt () / SQRT_2;
+ (x * x + y * y).sqrt () / SQRT_2
}
#[no_mangle]
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 479c1e68..fd308b5b 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -1,20 +1,20 @@
+#![cfg_attr(feature = "cargo-clippy", allow(clone_on_ref_ptr))]
+#![cfg_attr(feature = "cargo-clippy", allow(not_unsafe_ptr_arg_deref))]
+#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))]
+
extern crate cairo;
extern crate cairo_sys;
extern crate cssparser;
extern crate glib;
extern crate glib_sys;
extern crate libc;
+extern crate itertools;
+extern crate pango;
+extern crate pango_sys;
#[macro_use]
-extern crate bitflags;
-#[macro_use]
extern crate downcast_rs;
-pub use aspect_ratio::{
- rsvg_aspect_ratio_parse,
- rsvg_aspect_ratio_compute
-};
-
pub use bbox::{
RsvgBbox,
rsvg_bbox_init,
@@ -22,6 +22,17 @@ pub use bbox::{
rsvg_bbox_clip
};
+pub use chars::{
+ rsvg_node_chars_new,
+ rsvg_node_chars_append,
+ rsvg_node_chars_get_string,
+};
+
+pub use clip_path::{
+ rsvg_node_clip_path_new,
+ rsvg_node_clip_path_get_units
+};
+
pub use cnode::{
rsvg_rust_cnode_new,
rsvg_rust_cnode_get_impl
@@ -58,6 +69,16 @@ pub use marker::{
rsvg_node_marker_new,
};
+pub use mask::{
+ rsvg_node_mask_new,
+ rsvg_node_mask_get_x,
+ rsvg_node_mask_get_y,
+ rsvg_node_mask_get_width,
+ rsvg_node_mask_get_height,
+ rsvg_node_mask_get_units,
+ rsvg_node_mask_get_content_units,
+};
+
pub use node::{
rsvg_node_get_type,
rsvg_node_get_parent,
@@ -103,6 +124,10 @@ pub use shapes::{
rsvg_node_rect_new,
};
+pub use space::{
+ rsvg_xml_space_normalize,
+};
+
pub use stop::{
rsvg_node_stop_new
};
@@ -119,6 +144,10 @@ pub use structure::{
rsvg_node_use_new,
};
+pub use text::{
+ rsvg_text_create_layout,
+};
+
pub use transform::{
rsvg_parse_transform,
};
@@ -128,8 +157,13 @@ pub use viewbox::{
};
+#[macro_use]
+mod coord_units;
+
mod aspect_ratio;
mod bbox;
+mod chars;
+mod clip_path;
mod cnode;
mod color;
mod drawing_ctx;
@@ -139,6 +173,7 @@ mod handle;
mod image;
mod length;
mod marker;
+mod mask;
mod node;
mod opacity;
mod paint_server;
@@ -148,9 +183,11 @@ mod path_parser;
mod pattern;
mod property_bag;
mod shapes;
+mod space;
mod state;
mod stop;
mod structure;
+mod text;
mod transform;
mod util;
mod viewbox;
diff --git a/rust/src/marker.rs b/rust/src/marker.rs
index 092b076f..3d1b5091 100644
--- a/rust/src/marker.rs
+++ b/rust/src/marker.rs
@@ -71,8 +71,8 @@ impl Parse for MarkerOrient {
match s {
"auto" => Ok (MarkerOrient::Auto),
_ => parsers::angle_degrees (s)
- .map (|degrees| MarkerOrient::Degrees (degrees) )
- .map_err (|e| AttributeError::Parse (e))
+ .map (MarkerOrient::Degrees)
+ .map_err (AttributeError::Parse)
}
}
}
@@ -381,17 +381,11 @@ pub fn path_builder_to_segments (builder: &RsvgPathBuilder) -> Vec<Segment> {
}
}
- match state {
- SegmentState::NewSubpath => {
- /* Output a lone point if we started a subpath with a
- * moveto command, but there are no subsequent commands.
- */
- segments.push (make_degenerate (cur_x, cur_y));
- },
-
- _ => {
- }
- }
+ if let SegmentState::NewSubpath = state {
+ // Output a lone point if we started a subpath with a moveto
+ // command, but there are no subsequent commands.
+ segments.push (make_degenerate (cur_x, cur_y));
+ };
segments
}
@@ -672,21 +666,17 @@ fn emit_markers_for_path_builder<E> (builder: &RsvgPathBuilder,
for (i, segment) in segments.iter ().enumerate () {
match *segment {
Segment::Degenerate { .. } => {
- match subpath_state {
- SubpathState::InSubpath => {
- assert! (i > 0);
+ if let SubpathState::InSubpath = subpath_state {
+ assert! (i > 0);
- /* Got a lone point after a subpath; render the subpath's end marker first */
+ /* Got a lone point after a subpath; render the subpath's end marker first */
- let (_, incoming_vx, incoming_vy) = find_incoming_directionality_backwards (&segments, i - 1);
- emit_marker (&segments[i - 1],
- MarkerEndpoint::End,
- MarkerType::End,
- angle_from_vector (incoming_vx, incoming_vy),
- emit_fn);
- },
-
- _ => { }
+ let (_, incoming_vx, incoming_vy) = find_incoming_directionality_backwards (&segments, i - 1);
+ emit_marker (&segments[i - 1],
+ MarkerEndpoint::End,
+ MarkerType::End,
+ angle_from_vector (incoming_vx, incoming_vy),
+ emit_fn);
}
/* Render marker for the lone point; no directionality */
@@ -743,16 +733,12 @@ fn emit_markers_for_path_builder<E> (builder: &RsvgPathBuilder,
/* Finally, render the last point */
- if segments.len() > 0 {
+ if !segments.is_empty() {
let segment = &segments[segments.len() - 1];
- match *segment {
- Segment::LineOrCurve { .. } => {
- let (_, incoming_vx, incoming_vy) = find_incoming_directionality_backwards (&segments, segments.len () - 1);
-
- emit_marker (&segment, MarkerEndpoint::End, MarkerType::End, angle_from_vector (incoming_vx, incoming_vy), emit_fn);
- },
+ if let Segment::LineOrCurve{ .. } = *segment {
+ let (_, incoming_vx, incoming_vy) = find_incoming_directionality_backwards (&segments, segments.len () - 1);
- _ => { }
+ emit_marker (segment, MarkerEndpoint::End, MarkerType::End, angle_from_vector (incoming_vx, incoming_vy), emit_fn);
}
}
}
@@ -1173,7 +1159,7 @@ mod marker_tests {
#[test]
#[ignore]
- // https://bugzilla.gnome.org/show_bug.cgi?id=777854
+ // https://gitlab.gnome.org/GNOME/librsvg/issues/161
fn emits_for_closed_subpath () {
let mut builder = RsvgPathBuilder::new ();
builder.move_to (0.0, 0.0);
diff --git a/rust/src/mask.rs b/rust/src/mask.rs
new file mode 100644
index 00000000..492d0c89
--- /dev/null
+++ b/rust/src/mask.rs
@@ -0,0 +1,172 @@
+use libc;
+use std::cell::Cell;
+
+use coord_units::CoordUnits;
+use drawing_ctx::RsvgDrawingCtx;
+use handle::RsvgHandle;
+use length::{RsvgLength, LengthDir};
+use node::{NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode, boxed_node_new};
+use parsers::Parse;
+use property_bag::{self, RsvgPropertyBag};
+
+coord_units!(MaskUnits, CoordUnits::ObjectBoundingBox);
+coord_units!(MaskContentUnits, CoordUnits::UserSpaceOnUse);
+
+struct NodeMask {
+ x: Cell<RsvgLength>,
+ y: Cell<RsvgLength>,
+ width: Cell<RsvgLength>,
+ height: Cell<RsvgLength>,
+
+ units: Cell<MaskUnits>,
+ content_units: Cell<MaskContentUnits>,
+}
+
+impl NodeMask {
+ fn new() -> NodeMask {
+ NodeMask {
+ x: Cell::new(NodeMask::get_default_pos(LengthDir::Horizontal)),
+ y: Cell::new(NodeMask::get_default_pos(LengthDir::Vertical)),
+
+ width: Cell::new(NodeMask::get_default_size(LengthDir::Horizontal)),
+ height: Cell::new(NodeMask::get_default_size(LengthDir::Vertical)),
+
+ units: Cell::new(MaskUnits::default()),
+ content_units: Cell::new(MaskContentUnits::default())
+ }
+ }
+
+ fn get_default_pos(dir: LengthDir) -> RsvgLength {
+ RsvgLength::parse("-10%", dir).unwrap()
+ }
+
+ fn get_default_size(dir: LengthDir) -> RsvgLength {
+ RsvgLength::parse("120%", dir).unwrap()
+ }
+}
+
+impl NodeTrait for NodeMask {
+ fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
+ self.x.set(property_bag::parse_or_value(pbag, "x",
+ LengthDir::Horizontal,
+ NodeMask::get_default_pos(LengthDir::Horizontal),
+ None)?);
+ self.y.set(property_bag::parse_or_value(pbag, "y",
+ LengthDir::Vertical,
+ NodeMask::get_default_pos(LengthDir::Vertical),
+ None)?);
+
+ self.width.set (property_bag::parse_or_value (pbag, "width",
+ LengthDir::Horizontal,
+ NodeMask::get_default_size(LengthDir::Horizontal),
+ Some(RsvgLength::check_nonnegative))?);
+ self.height.set (property_bag::parse_or_value (pbag, "height",
+ LengthDir::Vertical,
+ NodeMask::get_default_size(LengthDir::Vertical),
+ Some(RsvgLength::check_nonnegative))?);
+
+ self.units.set(property_bag::parse_or_default(pbag, "maskUnits", (), None)?);
+ self.content_units.set(property_bag::parse_or_default(pbag, "maskContentUnits", (), None)?);
+
+ Ok(())
+ }
+
+ fn draw(&self, _: &RsvgNode, _: *const RsvgDrawingCtx, _: i32) {
+ // nothing; masks are handled specially
+ }
+
+ fn get_c_impl(&self) -> *const RsvgCNodeImpl {
+ unreachable!();
+ }
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_new(_: *const libc::c_char, raw_parent: *const RsvgNode) -> *const RsvgNode {
+ boxed_node_new(NodeType::Mask,
+ raw_parent,
+ Box::new(NodeMask::new()))
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_get_x(raw_node: *const RsvgNode) -> RsvgLength {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut v = RsvgLength::default();
+
+ node.with_impl(|mask: &NodeMask| {
+ v = mask.x.get();
+ });
+
+ v
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_get_y(raw_node: *const RsvgNode) -> RsvgLength {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut v = RsvgLength::default();
+
+ node.with_impl(|mask: &NodeMask| {
+ v = mask.y.get();
+ });
+
+ v
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_get_width(raw_node: *const RsvgNode) -> RsvgLength {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut v = RsvgLength::default();
+
+ node.with_impl(|mask: &NodeMask| {
+ v = mask.width.get();
+ });
+
+ v
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_get_height(raw_node: *const RsvgNode) -> RsvgLength {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut v = RsvgLength::default();
+
+ node.with_impl(|mask: &NodeMask| {
+ v = mask.height.get();
+ });
+
+ v
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_get_units(raw_node: *const RsvgNode) -> CoordUnits {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut units = MaskUnits::default();
+
+ node.with_impl(|mask: &NodeMask| {
+ units = mask.units.get();
+ });
+
+ CoordUnits::from(units)
+}
+
+#[no_mangle]
+pub extern fn rsvg_node_mask_get_content_units(raw_node: *const RsvgNode) -> CoordUnits {
+ assert! (!raw_node.is_null ());
+ let node: &RsvgNode = unsafe { & *raw_node };
+
+ let mut units = MaskContentUnits::default();
+
+ node.with_impl(|mask: &NodeMask| {
+ units = mask.content_units.get();
+ });
+
+ CoordUnits::from(units)
+}
diff --git a/rust/src/node.rs b/rust/src/node.rs
index b4b4b440..2aadfd9f 100644
--- a/rust/src/node.rs
+++ b/rust/src/node.rs
@@ -3,8 +3,7 @@ use ::glib_sys;
use ::glib::translate::*;
use ::libc;
-use std::rc::Rc;
-use std::rc::Weak;
+use std::rc::{Rc, Weak};
use std::cell::RefCell;
use std::ptr;
@@ -58,12 +57,12 @@ impl_downcast! (NodeTrait);
pub type NodeResult = Result<(), NodeError>;
pub struct Node {
- node_type: NodeType,
- parent: Option<Weak<Node>>, // optional; weak ref to parent
- pub children: RefCell<Vec<Rc<Node>>>, // strong references to children
- state: *mut RsvgState,
- result: RefCell <NodeResult>,
- node_impl: Box<NodeTrait>
+ node_type: NodeType,
+ parent: Option<Weak<Node>>, // optional; weak ref to parent
+ children: RefCell<Vec<Rc<Node>>>, // strong references to children
+ state: *mut RsvgState,
+ result: RefCell <NodeResult>,
+ node_impl: Box<NodeTrait>
}
/* Keep this in sync with rsvg-private.h:RsvgNodeType */
@@ -208,18 +207,35 @@ impl Node {
drawing_ctx::push_discrete_layer (draw_ctx);
}
- for child in &*self.children.borrow () {
+ self.foreach_child(|child| {
let boxed_child = box_node (child.clone ());
drawing_ctx::draw_node_from_stack (draw_ctx, boxed_child, 0);
rsvg_node_unref (boxed_child);
- }
+
+ true
+ });
if dominate != -1 {
drawing_ctx::pop_discrete_layer (draw_ctx);
}
}
+
+ pub fn foreach_child<F>(&self, mut f: F)
+ where F: FnMut(Rc<Node>) -> bool
+ {
+ for c in &*self.children.borrow() {
+ let next = f(c.clone());
+ if !next {
+ break;
+ }
+ }
+ }
+
+ pub fn has_children(&self) -> bool {
+ self.children.borrow().len() > 0
+ }
}
// Sigh, rsvg_state_free() is only available if we are being linked into
@@ -383,17 +399,15 @@ pub extern fn rsvg_node_foreach_child (raw_node: *const RsvgNode, func: NodeFore
assert! (!raw_node.is_null ());
let node: &RsvgNode = unsafe { & *raw_node };
- for child in &*node.children.borrow () {
+ node.foreach_child(|child| {
let boxed_child = box_node (child.clone ());
let next: bool = unsafe { from_glib (func (boxed_child, data)) };
rsvg_node_unref (boxed_child);
- if !next {
- break;
- }
- }
+ next
+ });
}
#[no_mangle]
diff --git a/rust/src/opacity.rs b/rust/src/opacity.rs
index 84f29073..50b3b555 100644
--- a/rust/src/opacity.rs
+++ b/rust/src/opacity.rs
@@ -1,5 +1,5 @@
/// Struct to represent an inheritable opacity property
-/// https://www.w3.org/TR/SVG/masking.html#OpacityProperty
+/// <https://www.w3.org/TR/SVG/masking.html#OpacityProperty>
use ::cssparser::{Parser, ParserInput, Token};
use ::libc;
@@ -93,7 +93,7 @@ impl FromStr for Opacity {
} else if value > 1.0 {
Opacity::Specified (1.0)
} else {
- Opacity::Specified (value as f64)
+ Opacity::Specified (f64::from(value))
}
},
@@ -112,7 +112,7 @@ impl Opacity {
match *spec {
OpacitySpec { kind: OpacityKind::Inherit, .. } => Ok (Opacity::Inherit),
- OpacitySpec { kind: OpacityKind::Specified, opacity } => Ok (Opacity::Specified (opacity as f64 / 255.0)),
+ OpacitySpec { kind: OpacityKind::Specified, opacity } => Ok (Opacity::Specified (f64::from(opacity) / 255.0)),
OpacitySpec { kind: OpacityKind::ParseError, .. } => Err (AttributeError::Parse (ParseError::new ("parse error")))
}
diff --git a/rust/src/paint_server.rs b/rust/src/paint_server.rs
index 3e5af590..b6246448 100644
--- a/rust/src/paint_server.rs
+++ b/rust/src/paint_server.rs
@@ -4,34 +4,6 @@ use error::*;
use parsers::Parse;
use parsers::ParseError;
-/// Defines the units to be used for scaling paint servers, per the [svg specification].
-///
-/// [svg spec]: https://www.w3.org/TR/SVG/pservers.html
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum PaintServerUnits {
- UserSpaceOnUse,
- ObjectBoundingBox
-}
-
-impl Parse for PaintServerUnits {
- type Data = ();
- type Err = AttributeError;
-
- fn parse (s: &str, _: ()) -> Result<PaintServerUnits, AttributeError> {
- match s {
- "userSpaceOnUse" => Ok (PaintServerUnits::UserSpaceOnUse),
- "objectBoundingBox" => Ok (PaintServerUnits::ObjectBoundingBox),
- _ => Err (AttributeError::Parse (ParseError::new ("expected 'userSpaceOnUse' or 'objectBoundingBox'")))
- }
- }
-}
-
-impl Default for PaintServerUnits {
- fn default () -> PaintServerUnits {
- PaintServerUnits::ObjectBoundingBox
- }
-}
-
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PaintServerSpread (pub cairo::enums::Extend);
@@ -60,18 +32,6 @@ mod tests {
use super::*;
#[test]
- fn parsing_invalid_strings_yields_error () {
- assert! (PaintServerUnits::parse ("", ()).is_err ());
- assert! (PaintServerUnits::parse ("foo", ()).is_err ());
- }
-
- #[test]
- fn parses_paint_server_units () {
- assert_eq! (PaintServerUnits::parse ("userSpaceOnUse", ()), Ok (PaintServerUnits::UserSpaceOnUse));
- assert_eq! (PaintServerUnits::parse ("objectBoundingBox", ()), Ok (PaintServerUnits::ObjectBoundingBox));
- }
-
- #[test]
fn parses_spread_method () {
assert_eq! (PaintServerSpread::parse ("pad", ()),
Ok (PaintServerSpread (cairo::enums::Extend::Pad)));
diff --git a/rust/src/parsers.rs b/rust/src/parsers.rs
index 17f4557a..61c6c119 100644
--- a/rust/src/parsers.rs
+++ b/rust/src/parsers.rs
@@ -49,10 +49,10 @@ pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
.map_err (|_| ParseError::new ("expected angle"))?;
match *token {
- Token::Number { value, .. } => value as f64,
+ Token::Number { value, .. } => f64::from(value),
Token::Dimension { value, ref unit, .. } => {
- let value = value as f64;
+ let value = f64::from(value);
match unit.as_ref () {
"deg" => value,
@@ -84,7 +84,7 @@ pub fn number_optional_number (s: &str) -> Result <(f64, f64), ParseError> {
let mut input = ParserInput::new (s);
let mut parser = Parser::new (&mut input);
- let x = parser.expect_number ()? as f64;
+ let x = f64::from(parser.expect_number ()?);
if !parser.is_exhausted () {
let state = parser.state ();
@@ -94,7 +94,7 @@ pub fn number_optional_number (s: &str) -> Result <(f64, f64), ParseError> {
_ => parser.reset (&state)
};
- let y = parser.expect_number ()? as f64;
+ let y = f64::from(parser.expect_number ()?);
parser.expect_exhausted ()?;
@@ -144,11 +144,11 @@ pub fn list_of_points (string: &str) -> Result <Vec<(f64, f64)>, ParseError> {
let mut v = Vec::new ();
loop {
- let x = parser.expect_number ()? as f64;
+ let x = f64::from(parser.expect_number ()?);
optional_comma (&mut parser);
- let y = parser.expect_number ()? as f64;
+ let y = f64::from(parser.expect_number ()?);
v.push ((x, y));
@@ -192,7 +192,7 @@ pub fn number_list (s: &str, length: ListLength) -> Result <Vec<f64>, NumberList
let mut v = Vec::<f64>::with_capacity (n);
for i in 0..n {
- v.push (parser.expect_number ().map_err (|_| NumberListError::Parse (ParseError::new ("expected number")))? as f64);
+ v.push (f64::from(parser.expect_number ().map_err (|_| NumberListError::Parse (ParseError::new ("expected number")))?));
if i != n - 1 {
optional_comma (&mut parser);
diff --git a/rust/src/path_builder.rs b/rust/src/path_builder.rs
index f4361df2..9e11e2bf 100644
--- a/rust/src/path_builder.rs
+++ b/rust/src/path_builder.rs
@@ -25,13 +25,17 @@ pub struct RsvgPathBuilder {
path_commands: Vec<PathCommand>,
}
-impl RsvgPathBuilder {
- pub fn new () -> RsvgPathBuilder {
- let builder = RsvgPathBuilder {
+impl Default for RsvgPathBuilder {
+ fn default() -> RsvgPathBuilder {
+ RsvgPathBuilder {
path_commands: Vec::new ()
- };
+ }
+ }
+}
- builder
+impl RsvgPathBuilder {
+ pub fn new () -> RsvgPathBuilder {
+ RsvgPathBuilder::default()
}
pub fn move_to (&mut self, x: f64, y: f64) {
@@ -186,12 +190,12 @@ impl RsvgPathBuilder {
/* Now draw the arc */
n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs ().ceil () as i32;
- let n_segs_dbl = n_segs as f64;
+ let n_segs_dbl = f64::from(n_segs);
for i in 0 .. n_segs {
self.arc_segment (cx, cy,
- theta1 + i as f64 * delta_theta / n_segs_dbl,
- theta1 + (i + 1) as f64 * delta_theta / n_segs_dbl,
+ theta1 + f64::from(i) * delta_theta / n_segs_dbl,
+ theta1 + f64::from(i + 1) * delta_theta / n_segs_dbl,
rx, ry,
x_axis_rotation);
}
diff --git a/rust/src/path_parser.rs b/rust/src/path_parser.rs
index ad3b35b4..857e3a27 100644
--- a/rust/src/path_parser.rs
+++ b/rust/src/path_parser.rs
@@ -90,9 +90,9 @@ impl<'b> PathParser<'b> {
fn parse (&mut self) -> bool {
self.getchar ();
- return self.optional_whitespace () &&
+ self.optional_whitespace () &&
self.moveto_drawto_command_groups () &&
- self.optional_whitespace ();
+ self.optional_whitespace ()
}
fn getchar (&mut self) {
@@ -219,7 +219,7 @@ impl<'b> PathParser<'b> {
/* Integer part */
while self.lookahead_is_digit (&mut c) {
- value = value * 10.0 + char_to_digit (c) as f64;
+ value = value * 10.0 + f64::from(char_to_digit (c));
assert! (self.match_char (c));
}
@@ -232,8 +232,8 @@ impl<'b> PathParser<'b> {
let mut c: char = ' ';
while self.lookahead_is_digit (&mut c) {
- fraction = fraction / 10.0;
- value += fraction * char_to_digit (c) as f64;
+ fraction /= 10.0;
+ value += fraction * f64::from(char_to_digit (c));
assert! (self.match_char (c));
}
@@ -254,7 +254,7 @@ impl<'b> PathParser<'b> {
if self.lookahead_is_digit (&mut c) {
while self.lookahead_is_digit (&mut c) {
- exponent = exponent * 10.0 + char_to_digit (c) as f64;
+ exponent = exponent * 10.0 + f64::from(char_to_digit (c));
assert! (self.match_char (c));
}
@@ -272,11 +272,11 @@ impl<'b> PathParser<'b> {
fn flag (&mut self) -> Option <bool> {
if self.match_char ('0') {
- return Some (false);
+ Some (false)
} else if self.match_char ('1') {
- return Some (true);
+ Some (true)
} else {
- return None;
+ None
}
}
@@ -446,14 +446,12 @@ impl<'b> PathParser<'b> {
fn moveto (&mut self, is_initial_moveto: bool) -> bool {
if self.lookahead_is ('M') || self.lookahead_is ('m') {
- let absolute: bool;
-
- if self.match_char ('M') {
- absolute = true;
+ let absolute = if self.match_char ('M') {
+ true
} else {
assert! (self.match_char ('m'));
- absolute = false;
- }
+ false
+ };
return self.optional_whitespace () &&
self.moveto_argument_sequence (absolute, is_initial_moveto);
@@ -464,8 +462,8 @@ impl<'b> PathParser<'b> {
fn moveto_drawto_command_group (&mut self, is_initial_moveto: bool) -> bool {
if self.moveto (is_initial_moveto) {
- return self.optional_whitespace () &&
- self.optional_drawto_commands ();
+ self.optional_whitespace () &&
+ self.optional_drawto_commands ()
} else {
false
}
@@ -500,7 +498,7 @@ impl<'b> PathParser<'b> {
}
fn drawto_command (&mut self) -> bool {
- return self.close_path () ||
+ self.close_path () ||
self.line_to () ||
self.horizontal_line_to () ||
self.vertical_line_to () ||
@@ -508,7 +506,7 @@ impl<'b> PathParser<'b> {
self.smooth_curve_to () ||
self.quadratic_bezier_curve_to () ||
self.smooth_quadratic_bezier_curve_to () ||
- self.elliptical_arc ();
+ self.elliptical_arc ()
}
fn close_path (&mut self) -> bool {
@@ -522,14 +520,12 @@ impl<'b> PathParser<'b> {
fn line_to (&mut self) -> bool {
if self.lookahead_is ('L') || self.lookahead_is ('l') {
- let absolute: bool;
-
- if self.match_char ('L') {
- absolute = true;
+ let absolute = if self.match_char ('L') {
+ true
} else {
assert! (self.match_char ('l'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -574,14 +570,12 @@ impl<'b> PathParser<'b> {
fn horizontal_line_to (&mut self) -> bool {
if self.lookahead_is ('H') || self.lookahead_is ('h') {
- let absolute: bool;
-
- if self.match_char ('H') {
- absolute = true;
+ let absolute = if self.match_char ('H') {
+ true
} else {
assert! (self.match_char ('h'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -626,14 +620,12 @@ impl<'b> PathParser<'b> {
fn vertical_line_to (&mut self) -> bool {
if self.lookahead_is ('V') || self.lookahead_is ('v') {
- let absolute: bool;
-
- if self.match_char ('V') {
- absolute = true;
+ let absolute = if self.match_char ('V') {
+ true
} else {
assert! (self.match_char ('v'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -731,14 +723,12 @@ impl<'b> PathParser<'b> {
fn curve_to (&mut self) -> bool {
if self.lookahead_is ('C') || self.lookahead_is ('c') {
- let absolute: bool;
-
- if self.match_char ('C') {
- absolute = true;
+ let absolute = if self.match_char ('C') {
+ true
} else {
assert! (self.match_char ('c'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -754,14 +744,12 @@ impl<'b> PathParser<'b> {
fn smooth_curve_to (&mut self) -> bool {
if self.lookahead_is ('S') || self.lookahead_is ('s') {
- let absolute: bool;
-
- if self.match_char ('S') {
- absolute = true;
+ let absolute = if self.match_char ('S') {
+ true
} else {
assert! (self.match_char ('s'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -813,14 +801,12 @@ impl<'b> PathParser<'b> {
fn quadratic_bezier_curve_to (&mut self) -> bool {
if self.lookahead_is ('Q') || self.lookahead_is ('q') {
- let absolute: bool;
-
- if self.match_char ('Q') {
- absolute = true;
+ let absolute = if self.match_char ('Q') {
+ true
} else {
assert! (self.match_char ('q'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -867,14 +853,12 @@ impl<'b> PathParser<'b> {
fn smooth_quadratic_bezier_curve_to (&mut self) -> bool {
if self.lookahead_is ('T') || self.lookahead_is ('t') {
- let absolute: bool;
-
- if self.match_char ('T') {
- absolute = true;
+ let absolute = if self.match_char ('T') {
+ true
} else {
assert! (self.match_char ('t'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
@@ -905,9 +889,10 @@ impl<'b> PathParser<'b> {
if let Some (sweep_flag) = self.flag () {
assert! (self.optional_comma_whitespace ());
- let sweep = match sweep_flag {
- false => Sweep::Negative,
- true => Sweep::Positive
+ let sweep = if sweep_flag {
+ Sweep::Positive
+ } else {
+ Sweep::Negative
};
if let Some ((mut x, mut y)) = self.coordinate_pair () {
@@ -957,14 +942,12 @@ impl<'b> PathParser<'b> {
fn elliptical_arc (&mut self) -> bool {
if self.lookahead_is ('A') || self.lookahead_is ('a') {
- let absolute: bool;
-
- if self.match_char ('A') {
- absolute = true;
+ let absolute = if self.match_char ('A') {
+ true
} else {
assert! (self.match_char ('a'));
- absolute = false;
- }
+ false
+ };
self.optional_whitespace ();
diff --git a/rust/src/pattern.rs b/rust/src/pattern.rs
index c601edf1..03bac235 100644
--- a/rust/src/pattern.rs
+++ b/rust/src/pattern.rs
@@ -11,22 +11,23 @@ use cairo::Pattern as CairoPattern;
use aspect_ratio::*;
use bbox::*;
+use coord_units::CoordUnits;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
-use error::*;
use handle::RsvgHandle;
use length::*;
use node::*;
-use paint_server::*;
-use parsers::Parse;
use property_bag;
use property_bag::*;
use util::*;
use viewbox::*;
+coord_units!(PatternUnits, CoordUnits::ObjectBoundingBox);
+coord_units!(PatternContentUnits, CoordUnits::UserSpaceOnUse);
+
#[derive(Clone)]
-pub struct Pattern {
- pub units: Option<PaintServerUnits>,
+ struct Pattern {
+ pub units: Option<PatternUnits>,
pub content_units: Option<PatternContentUnits>,
// This Option<Option<ViewBox>> is a bit strange. We want a field
// with value None to mean, "this field isn't resolved yet". However,
@@ -63,43 +64,13 @@ impl Default for Pattern {
}
}
-// A pattern's patternUnits attribute (in our Pattern::units field) defines the coordinate
-// system relative to the x/y/width/height of the Pattern. However, patterns also
-// have a patternContentUnits attribute, which refers to the pattern's contents (i.e. the
-// objects which it references. We define PatternContentUnits as a newtype, so that
-// it can have its own default value, different from the one in PaintServerUnits.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub struct PatternContentUnits(PaintServerUnits);
-
-impl From<PaintServerUnits> for PatternContentUnits {
- fn from (units: PaintServerUnits) -> PatternContentUnits {
- PatternContentUnits(units)
- }
-}
-
-impl Default for PatternContentUnits {
- fn default () -> PatternContentUnits {
- PatternContentUnits (PaintServerUnits::UserSpaceOnUse)
- }
-}
-
-impl Parse for PatternContentUnits {
- type Data = ();
- type Err = AttributeError;
-
- fn parse (s: &str, _: ()) -> Result<PatternContentUnits, AttributeError> {
- Ok (PatternContentUnits::from (PaintServerUnits::parse (s, ())?))
- }
-}
-
fn node_has_children (node: &Option<Weak<Node>>) -> bool {
match *node {
None => false,
Some (ref weak) => {
let ref strong_node = weak.clone ().upgrade ().unwrap ();
- let has_children = strong_node.children.borrow ().len () > 0;
- has_children
+ strong_node.has_children()
}
}
}
@@ -144,7 +115,7 @@ impl Pattern {
fn resolve_from_defaults (&mut self) {
/* These are per the spec */
- fallback_to! (self.units, Some (PaintServerUnits::default ()));
+ fallback_to! (self.units, Some (PatternUnits::default ()));
fallback_to! (self.content_units, Some (PatternContentUnits::default ()));
fallback_to! (self.vbox, Some (None));
fallback_to! (self.preserve_aspect_ratio, Some (AspectRatio::default ()));
@@ -305,7 +276,7 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
let vbox = pattern.vbox.unwrap ();
let preserve_aspect_ratio = pattern.preserve_aspect_ratio.unwrap ();
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
drawing_ctx::push_view_box (draw_ctx, 1.0, 1.0);
}
@@ -314,7 +285,7 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
let pattern_width = pattern.width.unwrap ().normalize (draw_ctx);
let pattern_height = pattern.height.unwrap ().normalize (draw_ctx);
- if units == PaintServerUnits::ObjectBoundingBox {
+ if units == PatternUnits(CoordUnits::ObjectBoundingBox) {
drawing_ctx::pop_view_box (draw_ctx);
}
@@ -324,12 +295,12 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
let bbhscale: f64;
match units {
- PaintServerUnits::ObjectBoundingBox => {
+ PatternUnits(CoordUnits::ObjectBoundingBox) => {
bbwscale = bbox.rect.width;
bbhscale = bbox.rect.height;
},
- PaintServerUnits::UserSpaceOnUse => {
+ PatternUnits(CoordUnits::UserSpaceOnUse) => {
bbwscale = 1.0;
bbhscale = 1.0;
}
@@ -351,19 +322,19 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
return false;
}
- scwscale = pw as f64 / scaled_width;
- schscale = ph as f64 / scaled_height;
+ scwscale = f64::from(pw) / scaled_width;
+ schscale = f64::from(ph) / scaled_height;
let mut affine: cairo::Matrix = cairo::Matrix::identity ();
// Create the pattern coordinate system
match units {
- PaintServerUnits::ObjectBoundingBox => {
+ PatternUnits(CoordUnits::ObjectBoundingBox) => {
affine.translate (bbox.rect.x + pattern_x * bbox.rect.width,
bbox.rect.y + pattern_y * bbox.rect.height);
},
- PaintServerUnits::UserSpaceOnUse => {
+ PatternUnits(CoordUnits::UserSpaceOnUse) => {
affine.translate (pattern_x, pattern_y);
}
}
@@ -397,7 +368,7 @@ fn set_pattern_on_draw_context (pattern: &Pattern,
drawing_ctx::push_view_box (draw_ctx, vbox.0.width, vbox.0.height);
pushed_view_box = true;
- } else if content_units == PatternContentUnits (PaintServerUnits::ObjectBoundingBox) {
+ } else if content_units == PatternContentUnits (CoordUnits::ObjectBoundingBox) {
// If coords are in terms of the bounding box, use them
caffine = cairo::Matrix::identity ();
diff --git a/rust/src/property_bag.rs b/rust/src/property_bag.rs
index 2c8d09a6..59b615ab 100644
--- a/rust/src/property_bag.rs
+++ b/rust/src/property_bag.rs
@@ -45,7 +45,7 @@ pub fn parse_or_none<T> (pbag: *const RsvgPropertyBag,
.and_then (|v|
if let Some(validate) = validate {
validate(v)
- .map(|v| Some(v))
+ .map(Some)
} else {
Ok(Some(v))
})
diff --git a/rust/src/shapes.rs b/rust/src/shapes.rs
index 38277026..07516bce 100644
--- a/rust/src/shapes.rs
+++ b/rust/src/shapes.rs
@@ -92,7 +92,7 @@ impl NodeTrait for NodePath {
if let Some (value) = property_bag::lookup (pbag, "d") {
let mut builder = self.builder.borrow_mut ();
- if let Err (_) = path_parser::parse_path_into_builder (&value, &mut *builder) {
+ if path_parser::parse_path_into_builder (&value, &mut *builder).is_err() {
// FIXME: we don't propagate errors upstream, but creating a partial
// path is OK per the spec
}
@@ -136,7 +136,7 @@ impl NodeTrait for NodePoly {
fn set_atts (&self, _: &RsvgNode, _: *const RsvgHandle, pbag: *const RsvgPropertyBag) -> NodeResult {
// support for svg < 1.0 which used verts
- for name in vec! ["verts", "points"] {
+ for name in &["verts", "points"] {
if let Some (value) = property_bag::lookup (pbag, name) {
let result = parsers::list_of_points (value.trim ());
diff --git a/rust/src/space.rs b/rust/src/space.rs
new file mode 100644
index 00000000..788d57f8
--- /dev/null
+++ b/rust/src/space.rs
@@ -0,0 +1,103 @@
+use libc;
+use glib::translate::*;
+use itertools::Itertools;
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum XmlSpace {
+ Default,
+ Preserve
+}
+
+/// Implements `xml:space` handling per the SVG spec
+///
+/// Normalizes a string as it comes out of the XML parser's handler
+/// for character data according to the SVG rules in
+/// <https://www.w3.org/TR/SVG/text.html#WhiteSpace>
+pub fn xml_space_normalize(mode: XmlSpace, s: &str) -> String {
+ match mode {
+ XmlSpace::Default => normalize_default(s),
+ XmlSpace::Preserve => normalize_preserve(s)
+ }
+}
+
+// From https://www.w3.org/TR/SVG/text.html#WhiteSpace
+//
+// When xml:space="default", the SVG user agent will do the following
+// using a copy of the original character data content. First, it will
+// remove all newline characters. Then it will convert all tab
+// characters into space characters. Then, it will strip off all
+// leading and trailing space characters. Then, all contiguous space
+// characters will be consolidated.
+fn normalize_default(s: &str) -> String {
+ s.trim()
+ .chars()
+ .filter(|ch| *ch != '\n')
+ .map(|ch| match ch {
+ '\t' => ' ',
+ c => c,
+ })
+ .coalesce(|current, next| match (current, next) {
+ (' ', ' ') => Ok(' '),
+ (_, _) => Err((current, next)),
+ })
+ .collect::<String>()
+}
+
+// From https://www.w3.org/TR/SVG/text.html#WhiteSpace
+//
+// When xml:space="preserve", the SVG user agent will do the following
+// using a copy of the original character data content. It will
+// convert all newline and tab characters into space characters. Then,
+// it will draw all space characters, including leading, trailing and
+// multiple contiguous space characters. Thus, when drawn with
+// xml:space="preserve", the string "a b" (three spaces between "a"
+// and "b") will produce a larger separation between "a" and "b" than
+// "a b" (one space between "a" and "b").
+fn normalize_preserve(s: &str) -> String {
+ s.chars()
+ .map(|ch| {
+ match ch {
+ '\n' | '\t' => ' ',
+
+ c => c
+ }
+ })
+ .collect()
+}
+
+#[no_mangle]
+pub extern fn rsvg_xml_space_normalize(mode: XmlSpace, s: *const libc::c_char) -> *const libc::c_char {
+ let rs = unsafe { String::from_glib_none (s) };
+
+ xml_space_normalize(mode, &rs).to_glib_full()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn xml_space_default() {
+ assert_eq!(xml_space_normalize(XmlSpace::Default, "\n WS example\n indented lines\n "),
+ "WS example indented lines");
+ assert_eq!(xml_space_normalize(XmlSpace::Default, "\n \t \tWS \t\t\texample\n \t indented lines\t\t \n "),
+ "WS example indented lines");
+ assert_eq!(xml_space_normalize(XmlSpace::Default, "\n \t \tWS \t\t\texample\n \t duplicate letters\t\t \n "),
+ "WS example duplicate letters");
+ assert_eq!(xml_space_normalize(XmlSpace::Default, "\nWS example\nnon-indented lines\n "),
+ "WS examplenon-indented lines");
+ assert_eq!(xml_space_normalize(XmlSpace::Default, "\nWS example\tnon-indented lines\n "),
+ "WS example non-indented lines");
+ }
+
+ #[test]
+ fn xml_space_preserve() {
+ assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n WS example\n indented lines\n "),
+ " WS example indented lines ");
+ assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n \t \tWS \t\t\texample\n \t indented lines\t\t \n "),
+ " WS example indented lines ");
+ assert_eq!(xml_space_normalize(XmlSpace::Preserve, "\n \t \tWS \t\t\texample\n \t duplicate letters\t\t \n "),
+ " WS example duplicate letters ");
+ }
+}
diff --git a/rust/src/state.rs b/rust/src/state.rs
index cd157d0a..0a5a9447 100644
--- a/rust/src/state.rs
+++ b/rust/src/state.rs
@@ -1 +1,109 @@
+use libc;
+use glib::translate::*;
+use glib_sys;
+use pango;
+use pango_sys;
+
+use length::RsvgLength;
+
pub enum RsvgState {}
+
+// Keep in sync with rsvg-styles.h:UnicodeBidi
+#[repr(C)]
+pub enum UnicodeBidi {
+ Normal,
+ Embed,
+ Override,
+}
+
+// Keep in sync with rsvg-styles.h:TextDecoration
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct TextDecoration {
+ overline: glib_sys::gboolean,
+ underline: glib_sys::gboolean,
+ strike: glib_sys::gboolean
+}
+
+pub struct FontDecor {
+ pub overline: bool,
+ pub underline: bool,
+ pub strike: bool,
+}
+
+impl From<TextDecoration> for FontDecor {
+ fn from(td: TextDecoration) -> FontDecor {
+ FontDecor {
+ overline: from_glib(td.overline),
+ underline: from_glib(td.underline),
+ strike: from_glib(td.strike),
+ }
+ }
+}
+
+extern "C" {
+ fn rsvg_state_get_language (state: *const RsvgState) -> *const libc::c_char;
+ fn rsvg_state_get_unicode_bidi (state: *const RsvgState) -> UnicodeBidi;
+ fn rsvg_state_get_text_dir (state: *const RsvgState) -> pango_sys::PangoDirection;
+ fn rsvg_state_get_text_gravity (state: *const RsvgState) -> pango_sys::PangoGravity;
+ fn rsvg_state_get_font_family (state: *const RsvgState) -> *const libc::c_char;
+ fn rsvg_state_get_font_style (state: *const RsvgState) -> pango_sys::PangoStyle;
+ fn rsvg_state_get_font_variant (state: *const RsvgState) -> pango_sys::PangoVariant;
+ fn rsvg_state_get_font_weight (state: *const RsvgState) -> pango_sys::PangoWeight;
+ fn rsvg_state_get_font_stretch (state: *const RsvgState) -> pango_sys::PangoStretch;
+ fn rsvg_state_get_letter_spacing (state: *const RsvgState) -> RsvgLength;
+ fn rsvg_state_get_font_decor (state: *const RsvgState) -> *const TextDecoration;
+}
+
+pub fn get_language(state: *const RsvgState) -> Option<String> {
+ unsafe {
+ from_glib_none(rsvg_state_get_language(state))
+ }
+}
+
+pub fn get_unicode_bidi(state: *const RsvgState) -> UnicodeBidi {
+ unsafe { rsvg_state_get_unicode_bidi(state) }
+}
+
+pub fn get_text_dir(state: *const RsvgState) -> pango::Direction {
+ unsafe { from_glib(rsvg_state_get_text_dir(state)) }
+}
+
+pub fn get_text_gravity(state: *const RsvgState) -> pango::Gravity {
+ unsafe { from_glib(rsvg_state_get_text_gravity(state)) }
+}
+
+pub fn get_font_family(state: *const RsvgState) -> Option<String> {
+ unsafe { from_glib_none(rsvg_state_get_font_family(state)) }
+}
+
+pub fn get_font_style(state: *const RsvgState) -> pango::Style {
+ unsafe { from_glib(rsvg_state_get_font_style(state)) }
+}
+
+pub fn get_font_variant(state: *const RsvgState) -> pango::Variant {
+ unsafe { from_glib(rsvg_state_get_font_variant(state)) }
+}
+
+pub fn get_font_weight(state: *const RsvgState) -> pango::Weight {
+ unsafe { from_glib(rsvg_state_get_font_weight(state)) }
+}
+
+pub fn get_font_stretch(state: *const RsvgState) -> pango::Stretch {
+ unsafe { from_glib(rsvg_state_get_font_stretch(state)) }
+}
+
+pub fn get_letter_spacing(state: *const RsvgState) -> RsvgLength {
+ unsafe { rsvg_state_get_letter_spacing(state) }
+}
+
+pub fn get_font_decor(state: *const RsvgState) -> Option<FontDecor> {
+ unsafe {
+ let td = rsvg_state_get_font_decor(state);
+ if td.is_null() {
+ None
+ } else {
+ Some(FontDecor::from(*td))
+ }
+ }
+}
diff --git a/rust/src/stop.rs b/rust/src/stop.rs
index cc396f5b..8defca78 100644
--- a/rust/src/stop.rs
+++ b/rust/src/stop.rs
@@ -166,10 +166,10 @@ impl NodeTrait for NodeStop {
}
fn u32_from_rgba (rgba: cssparser::RGBA) -> u32 {
- ((rgba.red as u32) << 24) |
- ((rgba.green as u32) << 16) |
- ((rgba.blue as u32) << 8) |
- (rgba.alpha as u32)
+ (u32::from(rgba.red) << 24) |
+ (u32::from(rgba.green) << 16) |
+ (u32::from(rgba.blue) << 8) |
+ u32::from(rgba.alpha)
}
extern "C" {
diff --git a/rust/src/structure.rs b/rust/src/structure.rs
index 507a2a52..23771920 100644
--- a/rust/src/structure.rs
+++ b/rust/src/structure.rs
@@ -88,7 +88,7 @@ impl NodeTrait for NodeSwitch {
drawing_ctx::push_discrete_layer (draw_ctx);
- for child in &*node.children.borrow () {
+ node.foreach_child(|child| {
if drawing_ctx::state_get_cond_true (child.get_state ()) {
let boxed_child = box_node (child.clone ());
@@ -96,9 +96,11 @@ impl NodeTrait for NodeSwitch {
rsvg_node_unref (boxed_child);
- break;
+ false // just draw this child
+ } else {
+ true
}
- }
+ });
drawing_ctx::pop_discrete_layer (draw_ctx);
}
@@ -166,12 +168,14 @@ impl NodeTrait for NodeSvg {
Ok (())
}
- fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, _dominate: i32) {
+ fn draw (&self, node: &RsvgNode, draw_ctx: *const RsvgDrawingCtx, dominate: i32) {
let nx = self.x.get ().normalize (draw_ctx);
let ny = self.y.get ().normalize (draw_ctx);
let nw = self.w.get ().normalize (draw_ctx);
let nh = self.h.get ().normalize (draw_ctx);
+ drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);
+
let state = drawing_ctx::get_current_state (draw_ctx);
let do_clip = !drawing_ctx::state_is_overflow (state) && node.get_parent ().is_some ();
@@ -269,9 +273,9 @@ impl NodeTrait for NodeUse {
// From https://www.w3.org/TR/SVG/struct.html#UseElement in
// "If the ‘use’ element references a ‘symbol’ element"
- let nw = self.w.get ().unwrap_or (RsvgLength::parse ("100%", LengthDir::Horizontal).unwrap ())
+ let nw = self.w.get ().unwrap_or_else(|| { RsvgLength::parse ("100%", LengthDir::Horizontal).unwrap ()})
.normalize (draw_ctx);
- let nh = self.h.get ().unwrap_or (RsvgLength::parse ("100%", LengthDir::Vertical).unwrap ())
+ let nh = self.h.get ().unwrap_or_else(|| { RsvgLength::parse ("100%", LengthDir::Vertical).unwrap ()})
.normalize (draw_ctx);
// width or height set to 0 disables rendering of the element
@@ -296,6 +300,7 @@ impl NodeTrait for NodeUse {
drawing_ctx::draw_node_from_stack (draw_ctx, boxed_child, 1);
rsvg_node_unref (boxed_child);
+ drawing_ctx::release_node (draw_ctx, raw_child);
drawing_ctx::pop_discrete_layer (draw_ctx);
} else {
child.with_impl (|symbol: &NodeSymbol| {
@@ -316,9 +321,9 @@ impl NodeTrait for NodeUse {
drawing_ctx::state_pop(draw_ctx);
});
});
- }
- drawing_ctx::release_node (draw_ctx, raw_child);
+ drawing_ctx::release_node (draw_ctx, raw_child);
+ }
}
fn get_c_impl (&self) -> *const RsvgCNodeImpl {
diff --git a/rust/src/text.rs b/rust/src/text.rs
new file mode 100644
index 00000000..04ee437e
--- /dev/null
+++ b/rust/src/text.rs
@@ -0,0 +1,102 @@
+use libc;
+use glib::translate::*;
+use pango::{self, ContextExt, LayoutExt};
+use pango_sys;
+
+use drawing_ctx::{self, RsvgDrawingCtx};
+use state::{self, UnicodeBidi};
+
+// FIXME: should the pango crate provide this like PANGO_GRAVITY_IS_VERTICAL() / PANGO_GRAVITY_IS_IMPROPER()?
+fn gravity_is_vertical(gravity: pango::Gravity) -> bool {
+ match gravity {
+ pango::Gravity::East | pango::Gravity::West => true,
+ _ => false
+ }
+}
+
+fn to_pango_units(v: f64) -> i32 {
+ (v * f64::from(pango::SCALE)) as i32
+}
+
+fn create_pango_layout(draw_ctx: *const RsvgDrawingCtx, text: &str) -> pango::Layout {
+ let state = drawing_ctx::get_current_state(draw_ctx);
+ let pango_context = drawing_ctx::get_pango_context(draw_ctx);
+
+ if let Some(lang) = state::get_language(state) {
+ let pango_lang = pango::Language::from_string(&lang);
+ pango_context.set_language(&pango_lang);
+ }
+
+ let unicode_bidi = state::get_unicode_bidi(state);
+ match unicode_bidi {
+ UnicodeBidi::Override | UnicodeBidi::Embed => {
+ pango_context.set_base_dir(state::get_text_dir(state));
+ },
+
+ _ => ()
+ }
+
+ let gravity = state::get_text_gravity(state);
+ if gravity_is_vertical(gravity) {
+ pango_context.set_base_gravity(gravity);
+ }
+
+ let mut font_desc = pango_context.get_font_description().unwrap();
+
+ if let Some(font_family) = state::get_font_family(state) {
+ font_desc.set_family(&font_family);
+ }
+
+ font_desc.set_style(state::get_font_style(state));
+ font_desc.set_variant(state::get_font_variant(state));
+ font_desc.set_weight(state::get_font_weight(state));
+ font_desc.set_stretch(state::get_font_stretch(state));
+
+ let (_, dpi_y) = drawing_ctx::get_dpi(draw_ctx);
+ font_desc.set_size(to_pango_units(drawing_ctx::get_normalized_font_size(draw_ctx) / dpi_y * 72.0));
+
+ let layout = pango::Layout::new(&pango_context);
+ layout.set_font_description(&font_desc);
+
+ let attr_list = pango::AttrList::new();
+
+ attr_list.insert(
+ pango::Attribute::new_letter_spacing(
+ to_pango_units(state::get_letter_spacing(state).normalize(draw_ctx))
+ ).unwrap());
+
+ if let Some(font_decor) = state::get_font_decor(state) {
+ if font_decor.underline {
+ attr_list.insert(pango::Attribute::new_underline(pango::Underline::Single)
+ .unwrap());
+ }
+
+ if font_decor.strike {
+ attr_list.insert(pango::Attribute::new_strikethrough(true)
+ .unwrap());
+ }
+ }
+
+ layout.set_attributes(&attr_list);
+
+ layout.set_alignment(
+ match state::get_text_dir(state) {
+ pango::Direction::Ltr => pango::Alignment::Left,
+ _ => pango::Alignment::Right,
+ }
+ );
+
+ layout.set_text(text);
+
+ layout
+}
+
+#[no_mangle]
+pub extern fn rsvg_text_create_layout(draw_ctx: *const RsvgDrawingCtx,
+ text: *const libc::c_char) -> *const pango_sys::PangoLayout {
+ assert!(!text.is_null());
+ let s = unsafe { String::from_glib_none(text) };
+ let layout = create_pango_layout(draw_ctx, &s);
+
+ layout.to_glib_full()
+}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 03304d30..6a4b9610 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1,5 +1,8 @@
include $(top_srcdir)/glib-tap.mk
+EXTRA_DIST += \
+ README.md
+
test_programs = \
loading \
rsvg-test \
diff --git a/tests/README.md b/tests/README.md
index 91a741b2..533048bc 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,27 +1,61 @@
Librsvg test suite
==================
-Librsvg's test harness is built upon Glib's GTest utility functions.
-These let you define tests in the C language.
+Librsvg's test harness is built upon [Glib's GTest utility
+functions][gtest]. These let you define tests in the C language.
-There are three different styles of tests:
+There are several different styles of tests:
-* crash - Ensures that loading and parsing (but not rendering) a
- particular SVG doesn't yield a GError.
+* `rsvg-test` - The main test suite; loads, parses, and renders SVGs and
+ compares the results against reference PNG images.
-* styles - Loads and parses an SVG, and checks that a particular SVG
- object has a certain style.
+* `loading` - Tests that compressed and uncompressed SVGs are loaded
+ correctly even if read one or two bytes at a time. This is
+ basically a test for the state machines in the loading code.
-* rsvg-test - The main test suite; loads, parses, and renders SVGs and
- compares the results against reference PNG images.
+* `crash` - Ensures that loading and parsing (but not rendering) a
+ particular SVG doesn't crash or yield a GError.
+
+* `render-crash` - Ensures that rendering a loaded SVG doesn't crash.
+
+* `dimensions` - Loads an SVG, and tests that librsvg computes the
+ correct dimensions for the toplevel SVG element, or one of the
+ individual sub-elements.
+
+* `styles` - Loads and parses an SVG, and checks that a particular SVG
+ object has a certain style. These tests are currently disabled,
+ since they depend on internal APIs of librsvg.
These are all "black box tests": they run the library with its public
API, and test the results. They do not test the library's internals;
just the output.
+
+Unit tests
+----------
+
Additionally, the library's source code has smaller unit tests for
particular sections of the code.
+**It is better to catch errors early**, in the unit tests, if
+possible. The test suite in this directory is for black box tests,
+which run the library as a normal program would use it.
+
+* **What should be in a unit test** - a small test of an algorithm; a
+ check for computed values given some starting values; checks for
+ edge cases.
+
+* **What should be in these black-box tests** - rendering tests that
+ exercise a particular part of the code; CSS cascading tests; images
+ that expose bugs and that we want to avoid regressing on later.
+
+For example, there are unit tests of the path data parser (the `<path
+d="M10 10 L20 20 ...">` element and its `d` attribute, to ensure that
+the parser handles all the path commands and catches errors
+appropriately. Correspondingly, there are a bunch of black-box tests
+that exercise particular features of path rendering ("does this
+actually draw a line, or an arc?").
+
Running the test suite
----------------------
@@ -31,7 +65,8 @@ directory and run `make check`. This will run both the small unit
tests and the black box tests in this `librsvg/tests` directory.
If you want to run just the black box tests, go into this
-`librsvg/tests` directory and run `make check`.
+`librsvg/tests` directory and run `make check`. If you want to run
+the unit tests, go to `librsvg/rust` and run `cargo test`.
Those commands will yield exit code 0 if all the tests pass, or
nonzero if some tests fail.
@@ -39,10 +74,9 @@ nonzero if some tests fail.
Running `make check` will produce a `test/test-suite.log` file. You can
see this file for the details of failed tests.
-Additionally, all three sets of black box tests (crash, styles,
-rsvg-test) will produce a test report in a text file. In the tests
-directory, you can see `crash.log`, `styles.log`, `rsvg-test.log`,
-respectively.
+Additionally, all the black box tests (rsvg-test, crash, etc.) will
+produce a test report in a text file. In the tests directory, you can
+see `rsvg-test.log`, `crash.log`, etc., respectively.
# Tests and test fixtures
@@ -56,31 +90,35 @@ Each image-based reference test uses two files: `foo.svg` and
`foo-ref.png`. The test harness will render `foo.svg` and compare the
results to `foo-ref.png`. Currently we assume a pixel-perfect match.
If there are differences in the output, the test will fail; see
-"Examining failed reference tests" below.
+"[Examining failed reference tests](#examining-failed-reference-tests)" below.
These files can go anywhere under the `fixtures/reftests`
directory; the `rsvg-test` program will recursively look inside
`fixtures/reftests` for all SVG files, render them, and compare them to
the `-ref.png` reference images.
-SVG test files or entire subdirectories in fixtures/reftests whose
-names begin with "ignore" will be skipped from the tests. That is,
-anything that matches "fixtures/reftests/ignore*" will not be included
-in the tests. You can use this to skip a few problematic files
-temporarily.
+**Ignoring tests:** SVG test files or entire subdirectories in
+`fixtures/reftests` whose names begin with "`ignore`" will be skipped from
+the tests. That is, anything that matches "`fixtures/reftests/ignore*`"
+will not be included in the tests. You can use this to skip a few
+problematic files temporarily.
As of 2016/Nov/03 we have an informal organization of these files:
-* `fixtures/reftests/*.svg` - Tests for special situations
- that arose during development.
+* `fixtures/reftests/svg1.1` - Tests from the W3C's SVG test suite.
+ These are supposed to test all of SVG's features; we will add them one
+ by one as librsvg starts implementing the features.
* `fixtures/reftests/bugs/*.svg` - Tests for particular bug numbers.
- Please use the bug number from Bugzilla, like 123456.svg, and the
- corresponding 123456-ref.png for the known-good reference image.
+ Please use the bug number from Gitlab, like `1234.svg`, and the
+ corresponding `1234-ref.png` for the known-good reference image.
+
+ **Note:** Librsvg migrated from git.gnome.org and bugzilla.gnome.org
+ to gitlab.gnome.org. Bug numbers in Bugzilla were around 6 digits
+ in length; in Gitlab, they are small numbers.
-* `fixtures/reftests/svg1.1` - Tests from the W3C's SVG test suite.
- These are supposed to test all of SVG's features; we'll add them one
- by one as librsvg starts implementing the features.
+* `fixtures/reftests/*.svg` - Tests for special situations
+ that arose during development.
### Examining failed reference tests
@@ -101,7 +139,7 @@ This means that the test named
autogenerated test names from GTest. In this case, it means that the
test file `fixtures/reftests/svg1.1/paths-data-18-f.svg` got rendered,
and produced incorrect output when compared to
-`fixtures/reftests/svg1.1/paths-data-18-f-out.png`.
+`fixtures/reftests/svg1.1/paths-data-18-f-ref.png`.
When a test fails, rsvg-test creates two images in `/tmp`:
@@ -121,29 +159,27 @@ It is up to you to decide what to do next:
with respect to the `foo-ref.png` reference image is that
antialiased edges look different, or font rendering is slightly
different due to the font-rendering machinery in your system, you
- can just regenerate the test image. See "Regenerating reference
- images" below.
+ can just regenerate the test image. See
+ "[Regenerating reference images](#regenerating-reference-images)" below.
* If the `foo-out.png` image is obviously wrong when compared to the
- `foo-ref.png` reference, you can file a bug in
- https://bugzilla.gnome.org. You can wait until someone fixes it, or
- try to fix the bug yourself!
+ `foo-ref.png` reference, you can [file a bug][bug]. You can wait
+ until someone fixes it, or try to [fix the bug yourself][pull-requests]!
-* Any other situation of course deserves attention. Feel free to ask
- the maintainers about it; even if you figure out the problem
+* Any other situation of course deserves attention. Feel free to [ask
+ the maintainers][maintainer] about it; even if you figure out the problem
yourself, a failed test almost always indicates a problem that is
- not just on your end. See the `librsvg/MAINTAINERS` file for where
- to reach them.
+ not just on your end.
### Regenerating reference images
Let's continue with the example above, where the test
-`/rsvg-test/reftests/svg1.1/paths-data-18-f.svg` failed. Let's say you
-fix the bug, or determine that the output image is in fact correct,
-and just differs from the reference image due to antialiasing
-artifacts. In this case, you'll want to regenerate the reference
-image so the test passes again.
+`/rsvg-test/reftests/svg1.1/paths-data-18-f.svg` failed. Let's say
+you fix the bug, or determine that the output image is in fact
+correct, and just differs from the reference image due to antialiasing
+artifacts. In this case, your next step is to regenerate the
+reference image so the test passes again.
If you want to regenerate the reference image
`fixtures/reftests/foo/bar-ref.png` from the corresponding `bar.svg`, you can run
@@ -174,7 +210,7 @@ around the whole viewport, defined like this:
<rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
```
-This specifies no stroke with, so it uses 1 by default. The desired
+This specifies no stroke width, so it uses 1 by default. The desired
effect is "stroke this rectangle with a 1-pixel wide line".
However, notice that the (x, y) coordinates of the rect are (1, 1).
@@ -188,27 +224,34 @@ suite are pixel-aligned, and some are not, like the example test-frame
above. It looks like their renderer uses a (0.5, 0.5) offset just for
strokes, but not for fills, which sounds hackish.
-Our test suite doesn't use special offsets so that SVG images not from
-the official test suite are rendered "normally". This means that the
-reference images from the official test suite will always fail
-initially, since stroke outlines will be fuzzy in librsvg, but not in
-the test suite (and conversely, SVGs *not* from the test suite would
-be crips in librsvg but probably not in the test suite's renderer
-renderer).
+Our test suite **does not** use special offsets, so that SVG images
+not from the official test suite are rendered "normally". **This means
+that the reference images from the official test suite will always
+fail initially**, since stroke outlines will be fuzzy in librsvg, but
+not in the test suite (and conversely, SVGs *not* from the test suite
+would be crisp in librsvg but probably not in the test suite's
+renderer renderer).
-Also, the original reference PNGs either use fonts that are different
-from those usually on free software systems, or they use SVG fonts
-which librsvg currently doesn't support (with glyph shapes referenced
-from a secondary SVG).
+Also, the original reference PNGs from the SVG 1.1 test suite either
+use fonts that are different from those usually on free software
+systems, or they use SVG fonts which librsvg currently doesn't support
+(i.e. with glyph shapes referenced from a secondary SVG).
In any case, look at the results by hand, and compare them by eye to
the official reference image. If the thing being tested looks
correct, and just the outlines are fuzzy — and also it is just the
actual font shapes that are different — then the test is probably
-correct. Follow the procedure as in "Regenerating reference images"
+correct. Follow the procedure as in
+"[Regenerating reference images](#regenerating-reference-images)"
listed above in order to have a reference image suitable for librsvg.
+## Loading tests for `loading.c`
+
+These test the code that decompresses compressed SVGs and feeds the
+XML reader, by tring to load SVG data one or two bytes at a time. The
+SVG and SVGZ images are in the `fixtures/loading` directory.
+
## Crash tests for `crash.c`
These load and parse an SVG, and ensure that there are no errors in
@@ -219,9 +262,24 @@ program will look recursively look inside `fixtures/crash` for all SVG
files, load them, and ensure that no GError was produced while loading
each file.
+## Rendering crash tests for `render-crash.c`
+
+We use these tests to ensure there are no regressions after fixing a
+bug where a particular SVG loads fine, but it crashes the renderer.
+The test files are in the `fixtures/render-crash` directory.
+
+## Dimensions tests for `dimensions.c`
+
+Here we test that librsvg computes the correct dimensions for objects
+in an SVG file. The test files are in the `fixtures/dimensions`
+directory. The expected dimensions are declared in the test fixtures
+in `dimensions.c`.
## Style tests for `styles.c`
+These tests are currently disabled, since they depend on internal APIs
+that are not visible to the test suite.
+
These load and parse an SVG, ask librsvg to fetch an SVG object by its
id, and ensure that the object has certain style properties with
particular values.
@@ -229,3 +287,9 @@ particular values.
The SVG images live in the `fixtures/styles` directory. The
corresponding object IDs and values to be tested for are in the
`styles.c` source code.
+
+
+[gtest]: https://developer.gnome.org/glib/stable/glib-Testing.html
+[bug]: ../CONTRIBUTING.md#reporting-bugs
+[pull-requests]: ../CONTRIBUTING.md#pull-requests
+[maintainer]: README.md#maintainers
diff --git a/tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype-ref.png b/tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype-ref.png
new file mode 100644
index 00000000..f64627ea
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype.svg b/tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype.svg
new file mode 100644
index 00000000..d98053de
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/152-image-data-with-no-mimetype.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="100" height="100" viewBox="0 0 100 100" version="1.1">
+ <image width="16" height="16" preserveAspectRatio="none"
+ xlink:href="data:;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAFklEQVQoz2P8z0AaYGIY1TCqYdhqAABALgEfsZDCTQAAAABJRU5ErkJggg=="/>
+</svg>
diff --git a/tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg-ref.png b/tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg-ref.png
new file mode 100644
index 00000000..147134b3
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg.svg b/tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg.svg
new file mode 100644
index 00000000..cb4fdf04
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/181-inheritable-attrs-in-svg.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" fill="red" opacity="0.5">
+ <circle cx="64" cy="64" r="32"/>
+</svg>
diff --git a/tests/fixtures/reftests/bugs/340047-ref.png b/tests/fixtures/reftests/bugs/340047-ref.png
index 92be7e3b..95283a8e 100644
--- a/tests/fixtures/reftests/bugs/340047-ref.png
+++ b/tests/fixtures/reftests/bugs/340047-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/587721-text-transform-ref.png b/tests/fixtures/reftests/bugs/587721-text-transform-ref.png
index f9c7ec0a..b6ee89c4 100644
--- a/tests/fixtures/reftests/bugs/587721-text-transform-ref.png
+++ b/tests/fixtures/reftests/bugs/587721-text-transform-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/749415-ref.png b/tests/fixtures/reftests/bugs/749415-ref.png
index 86da5005..896a4131 100644
--- a/tests/fixtures/reftests/bugs/749415-ref.png
+++ b/tests/fixtures/reftests/bugs/749415-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/760180-ref.png b/tests/fixtures/reftests/bugs/760180-ref.png
new file mode 100644
index 00000000..d2010513
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/760180-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/760180.svg b/tests/fixtures/reftests/bugs/760180.svg
new file mode 100644
index 00000000..c1929f81
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/760180.svg
@@ -0,0 +1,159 @@
+<svg id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="AG" author="ED" status="accepted"
+ version="$Revision: 1.9 $" testname="$RCSfile: painting-marker-06-f.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/painting.html#MarkerElement">
+ <p>
+ Tests the basic support for markers. For the three tests, there
+ should be two identical paths with markers drawn. The path on the left is
+ rendered using the marker elements. The path on the right is rendered using
+ the equivalent SVG, showing what the marked path should look like.
+ </p>
+ <p>
+ This test is similar to the painting-marker-01-f.svg test, but has some viewBox attributes
+ that have a non-zero offset.
+ </p>
+ <p>
+ The top test examines the basic support for the marker element and style. The markers are purple rectangles.
+ </p>
+ <p>
+ The middle test examines the support for the different styles of marker properties. The
+ "marker-start" property defines the marker to use at the first vertex of the marked path,
+ in this case a purple rectangle. The "marker-end" property defines the marker to use at the
+ last vertex of the marked path, in this case a blue triangle. The "marker-mid" property
+ defines the marker to use at all vertices, other than the first and last, of the marked path,
+ in this case a green circle.
+ </p>
+ <p>
+ The bottom test examines the support for marker orientation along the
+ path direction. The second vertex, the top right corner of the path, has a marker that
+ is rotated 45 degrees, since that is the average of the horizontal and vertical segments
+ each side. The last vertex, the bottom right corner of the path, has a marker rotated 90
+ degrees since that is the direction of the last path segment.
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The rendered picture should match the reference image, except for possible
+ variations in the labelling text (per CSS2 rules).
+ </p>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: painting-marker-06-f.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <defs>
+ <!-- ===================================================================== -->
+ <!-- Define a few simple marker elements -->
+ <!-- ===================================================================== -->
+ <marker id="marker1" viewBox="20 20 10 10" markerWidth="2" markerHeight="2" refX="25" refY="25" markerUnits="strokeWidth">
+ <rect x="20" y="20" width="10" height="10" fill="purple" stroke="none"/>
+ </marker>
+ <marker id="marker2" viewBox="-5 -5 10 10" markerWidth="2" markerHeight="2" markerUnits="strokeWidth" orient="auto">
+ <path d="M 0 -5 L 5 5 L -5 5 Z" fill="blue" stroke="none"/>
+ </marker>
+ <marker id="markerStart" viewBox="0 0 10 10" markerWidth="2" markerHeight="2" refX="5" refY="5" markerUnits="strokeWidth">
+ <rect width="10" height="10" fill="purple" stroke="none"/>
+ </marker>
+ <marker id="markerMiddle" viewBox="0 0 10 10" markerWidth="2" markerHeight="2" refX="5" refY="5" markerUnits="strokeWidth">
+ <circle cx="5" cy="5" r="5" fill="green" stroke="none"/>
+ </marker>
+ <marker id="markerEnd" viewBox="0 0 10 10" markerWidth="2" markerHeight="2" refX="5" refY="5" markerUnits="strokeWidth">
+ <path d="M 5 0 L 10 10 L 0 10 Z" fill="blue" stroke="none"/>
+ </marker>
+ </defs>
+ <!-- ===================================================================== -->
+ <!-- Basic Marker Test -->
+ <!-- ===================================================================== -->
+ <text x="170" y="30" font-size="14">Basic Markers</text>
+ <path fill="none" stroke="black" stroke-width="8" marker-start="url(#marker1)" marker-mid="url(#marker1)" marker-end="url(#marker1)" d="M 130 40 L 180 40 L 180 90"/>
+ <!-- ===================================================================== -->
+ <!-- Generate the equivalent SVG -->
+ <!-- ===================================================================== -->
+ <g transform="translate(120,0)">
+ <path fill="none" stroke="black" stroke-width="8" d="M 130 40 L 180 40 L 180 90"/>
+ <g transform="translate(130,40) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <rect width="10" height="10" fill="purple" stroke="none"/>
+ </g>
+ <g transform="translate(180,40) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <rect width="10" height="10" fill="purple" stroke="none"/>
+ </g>
+ <g transform="translate(180,90) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <rect width="10" height="10" fill="purple" stroke="none"/>
+ </g>
+ </g>
+ <!-- ===================================================================== -->
+ <!-- Start, Middle and End Marker Test -->
+ <!-- ===================================================================== -->
+ <text x="145" y="125" font-size="14">Start, Middle and End</text>
+ <path fill="none" stroke="black" stroke-width="8" marker-start="url(#markerStart)" marker-mid="url(#markerMiddle)" marker-end="url(#markerEnd)" d="M 130 135 L 180 135 L 180 185"/>
+ <!-- ===================================================================== -->
+ <!-- Generate the equivalent SVG -->
+ <!-- ===================================================================== -->
+ <g transform="translate(120,0)">
+ <path fill="none" stroke="black" stroke-width="8" d="M 130 135 L 180 135 L 180 185"/>
+ <g transform="translate(130,135) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <rect width="10" height="10" fill="purple" stroke="none"/>
+ </g>
+ <g transform="translate(180,135) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <circle cx="5" cy="5" r="5" fill="green" stroke="none"/>
+ </g>
+ <g transform="translate(180,185) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <path d="M 5 0 L 10 10 L 0 10 Z" fill="blue" stroke="none"/>
+ </g>
+ </g>
+ <!-- ===================================================================== -->
+ <!-- Auto Orientation Marker Test -->
+ <!-- ===================================================================== -->
+ <text x="145" y="220" font-size="14">Automatic Orientation</text>
+ <path fill="none" stroke="black" stroke-width="8" marker-start="url(#marker2)" marker-mid="url(#marker2)" marker-end="url(#marker2)" d="M 130 230 L 180 230 L 180 280"/>
+ <!-- ===================================================================== -->
+ <!-- Generate the equivalent SVG -->
+ <!-- ===================================================================== -->
+ <g transform="translate(120,0)">
+ <path fill="none" stroke="black" stroke-width="8" d="M 130 230 L 180 230 L 180 280"/>
+ <g transform="translate(130,230) rotate(0) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <path d="M 5 0 L 10 10 L 0 10 Z" fill="blue" stroke="none"/>
+ </g>
+ <g transform="translate(180,230) rotate(45) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <path d="M 5 0 L 10 10 L 0 10 Z" fill="blue" stroke="none"/>
+ </g>
+ <g transform="translate(180,280) rotate(90) scale(8) scale(0.2, 0.2) translate(-5, -5)" fill="none" stroke="black" stroke-width="8">
+ <path d="M 5 0 L 10 10 L 0 10 Z" fill="blue" stroke="none"/>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/fixtures/reftests/bugs/761175-recursive-masks-ref.png b/tests/fixtures/reftests/bugs/761175-recursive-masks-ref.png
new file mode 100644
index 00000000..aceb5d20
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/761175-recursive-masks-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/761175-recursive-masks.svg b/tests/fixtures/reftests/bugs/761175-recursive-masks.svg
new file mode 100644
index 00000000..22482664
--- /dev/null
+++ b/tests/fixtures/reftests/bugs/761175-recursive-masks.svg
@@ -0,0 +1,50 @@
+<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" stroke-linecap="round" stroke-linejoin="round" fill-rule="evenodd" width="321.00" height="27.00" viewBox="0 0 6420 540">
+ <metadata>
+ <rdf:RDF>
+ <rdf:Description>
+ <dc:description>MSS/MilX-Export to SVG</dc:description>
+ <dc:publisher>gs-soft AG</dc:publisher>
+ </rdf:Description>
+ </rdf:RDF>
+ </metadata>
+ <defs>
+ <style type="text/css">
+ <![CDATA[
+ .Pen0 {fill:none;stroke:black;stroke-width:42;}
+ .Pen1 {fill:none;stroke:black;stroke-width:44;}
+ ]]>
+ </style>
+ <mask id="Mask_ClipObj0_ex_ClipObj1" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540">
+ <g>
+ <use xlink:href="#ClipObj0" fill="white"/>
+ <use xlink:href="#ClipObj1" fill="black"/>
+ </g>
+ </mask>
+ <g id="ClipObj0_ex_ClipObj1">
+ <use xlink:href="#ClipObj0" mask="url(#Mask_ClipObj0_ex_ClipObj1)"/>
+ </g>
+ <mask id="Region0" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540" fill-rule="nonzero">
+ <use xlink:href="#ClipObj0_ex_ClipObj1" fill="white"/>
+ </mask>
+ <mask id="Region1" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540" fill-rule="nonzero">
+ <use xlink:href="#ClipObj0" fill="white"/>
+ </mask>
+ <rect id="ClipObj0" x="0" y="0" width="6420" height="540"/>
+ <polygon id="ClipObj1" points="2760,20 3660,20 3660,500 2760,500"/>
+ <g id="Block1">
+ <g transform="matrix(0.068 0 0 0.068 2 2)">
+ <polyline points="480,0 300,300" class="Pen1"/>
+ </g>
+ </g>
+ </defs>
+ <g mask="url(#Region0)">
+ <g transform="matrix(1.66667 0 0 1.66667 0 0)">
+ <polyline points="30,156 3810,156" class="Pen0"/>
+ </g>
+ </g>
+ <g mask="url(#Region1)">
+ <g transform="matrix(19.529 0 0 19.1333 2751.67 21.6667)">
+ <use xlink:href="#Block1"/>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/tests/fixtures/reftests/bugs/776297-marker-on-non-path-elements-ref.png b/tests/fixtures/reftests/bugs/776297-marker-on-non-path-elements-ref.png
index 1b5634c1..e71ff168 100644
--- a/tests/fixtures/reftests/bugs/776297-marker-on-non-path-elements-ref.png
+++ b/tests/fixtures/reftests/bugs/776297-marker-on-non-path-elements-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/bugs/777834-empty-text-children-ref.png b/tests/fixtures/reftests/bugs/777834-empty-text-children-ref.png
index 58a4c034..59ce8fad 100644
--- a/tests/fixtures/reftests/bugs/777834-empty-text-children-ref.png
+++ b/tests/fixtures/reftests/bugs/777834-empty-text-children-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-01-b-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-01-b-ref.png
index 09f6ffa2..03d60c84 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-02-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-02-t-ref.png
index a177f04a..f1c14abd 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-02-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-02-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-03-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-03-t-ref.png
index 879f964c..6b573d51 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-03-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-03-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-04-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-04-t-ref.png
index efe6f84b..ed9fcd5b 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-04-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-04-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-05-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-05-t-ref.png
index cad92ea2..40e8223f 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-05-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-05-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-06-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-06-t-ref.png
index 9862811f..1124101e 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-06-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-06-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-07-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-07-t-ref.png
index cf63c7d6..dda47ff9 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-07-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-07-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-08-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-08-t-ref.png
index ef003bb9..1acdd4d2 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-08-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-08-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-trans-09-t-ref.png b/tests/fixtures/reftests/svg1.1/coords-trans-09-t-ref.png
index c8b8ccfe..fe7b8b41 100644
--- a/tests/fixtures/reftests/svg1.1/coords-trans-09-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-trans-09-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-viewattr-01-b-ref.png b/tests/fixtures/reftests/svg1.1/coords-viewattr-01-b-ref.png
index 4ee3ddba..ed3e6b64 100644
--- a/tests/fixtures/reftests/svg1.1/coords-viewattr-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-viewattr-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-viewattr-02-b-ref.png b/tests/fixtures/reftests/svg1.1/coords-viewattr-02-b-ref.png
index b08714a7..52eb2e58 100644
--- a/tests/fixtures/reftests/svg1.1/coords-viewattr-02-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-viewattr-02-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/coords-viewattr-03-b-ref.png b/tests/fixtures/reftests/svg1.1/coords-viewattr-03-b-ref.png
index 9b7608e6..c6b3ad76 100644
--- a/tests/fixtures/reftests/svg1.1/coords-viewattr-03-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/coords-viewattr-03-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/filters-color-02-b-ref.png b/tests/fixtures/reftests/svg1.1/filters-color-02-b-ref.png
index 6a7d5661..f0be4764 100644
--- a/tests/fixtures/reftests/svg1.1/filters-color-02-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/filters-color-02-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/filters-composite-02-b-ref.png b/tests/fixtures/reftests/svg1.1/filters-composite-02-b-ref.png
index 7688baf6..9e87d522 100644
--- a/tests/fixtures/reftests/svg1.1/filters-composite-02-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/filters-composite-02-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-intro-01-f-ref.png b/tests/fixtures/reftests/svg1.1/masking-intro-01-f-ref.png
index ea430147..39420a06 100644
--- a/tests/fixtures/reftests/svg1.1/masking-intro-01-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-intro-01-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-mask-01-b-ref.png b/tests/fixtures/reftests/svg1.1/masking-mask-01-b-ref.png
index a0065d90..c18d061d 100644
--- a/tests/fixtures/reftests/svg1.1/masking-mask-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-mask-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-mask-02-f-ref.png b/tests/fixtures/reftests/svg1.1/masking-mask-02-f-ref.png
index 58b475ad..d6cbe306 100644
--- a/tests/fixtures/reftests/svg1.1/masking-mask-02-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-mask-02-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-opacity-01-b-ref.png b/tests/fixtures/reftests/svg1.1/masking-opacity-01-b-ref.png
index fa6bfeac..c9473f6d 100644
--- a/tests/fixtures/reftests/svg1.1/masking-opacity-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-opacity-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-path-01-b-ref.png b/tests/fixtures/reftests/svg1.1/masking-path-01-b-ref.png
index a5de871c..24067038 100644
--- a/tests/fixtures/reftests/svg1.1/masking-path-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-path-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-path-02-b-ref.png b/tests/fixtures/reftests/svg1.1/masking-path-02-b-ref.png
index 8948b23e..3a77cbe3 100644
--- a/tests/fixtures/reftests/svg1.1/masking-path-02-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-path-02-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-path-03-b-ref.png b/tests/fixtures/reftests/svg1.1/masking-path-03-b-ref.png
index 8d80406f..552bdd33 100644
--- a/tests/fixtures/reftests/svg1.1/masking-path-03-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-path-03-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-path-04-b-ref.png b/tests/fixtures/reftests/svg1.1/masking-path-04-b-ref.png
index 5c3e1d13..4512db5c 100644
--- a/tests/fixtures/reftests/svg1.1/masking-path-04-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/masking-path-04-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-path-05-f-ref.png b/tests/fixtures/reftests/svg1.1/masking-path-05-f-ref.png
new file mode 100644
index 00000000..8fa5a7ff
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/masking-path-05-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/masking-path-05-f.svg b/tests/fixtures/reftests/svg1.1/masking-path-05-f.svg
new file mode 100644
index 00000000..e6146eab
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/masking-path-05-f.svg
@@ -0,0 +1,78 @@
+<svg version="1.1" baseProfile="basic" id="svg-root"
+ width="100%" height="100%" viewBox="0 0 480 360"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= SVG 1.1 2nd Edition Test Case =-->
+ <!--======================================================================-->
+ <!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="SVGWG" author="Haroon Sheikh" status="accepted"
+ version="$Revision: 1.6 $" testname="$RCSfile: masking-path-05-f.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/masking.html#ClippingPaths">
+ <p>
+ Test to see if clip-rule property has been implemented properly.
+ </p>
+ <p>
+ The test at the top shows a red rectangle that has been clipped by a
+ clipping path that overlaps itself.
+ </p>
+ <p>
+ The test at the bottom shows a blue rectangle that has been clipped by a
+ clipping path that overlaps itself.
+ </p>
+ <p>
+ The rendered picture should match the reference image exactly, except for possible
+ variations in the labelling text (per CSS2 rules).
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ In the first rectangle, the clip-rule is defined to be evenodd so the overlap should have a hole in it.
+ The clip-rule is defined to be nonzero so the overlap should be filled.
+ </p>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: masking-path-05-f.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <g shape-rendering="geometricPrecision">
+ <text font-size="14" x="150" y="20">Test for clip-rule property.</text>
+ <clipPath id="clip1">
+ <path clip-rule="evenodd" d="M200,40l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z"/>
+ </clipPath>
+ <rect x="50" y="30" width="350" height="100" fill="red" clip-path="url(#clip1)"/>
+ <text font-size="12" x="100" y="140">clip-rule=evenodd</text>
+ <clipPath id="clip2">
+ <path clip-rule="nonzero" d="M200,170l20,0 0,60 20,0 0,-20 -60,0 0,-20 80,0 0,60 -60,0 0,-80z"/>
+ </clipPath>
+ <rect x="50" y="160" width="350" height="100" fill="blue" clip-path="url(#clip2)"/>
+ <text font-size="12" x="100" y="270">cliprule=nonzero</text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-01-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-01-f-ref.png
index e003fd20..c9296414 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-01-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-01-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-02-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-02-f-ref.png
index ad1c3c4f..60beab2e 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-02-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-02-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-03-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-03-f-ref.png
index 5a8ca5d6..ad69aca9 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-03-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-03-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-04-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-04-f-ref.png
index ce6709bb..9bab4d9b 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-04-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-04-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-06-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-06-f-ref.png
index dda63fc7..d2010513 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-06-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-06-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-07-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-07-f-ref.png
index dacd1942..84064a48 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-07-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-07-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/painting-marker-properties-01-f-ref.png b/tests/fixtures/reftests/svg1.1/painting-marker-properties-01-f-ref.png
index 198a3389..f885f1da 100644
--- a/tests/fixtures/reftests/svg1.1/painting-marker-properties-01-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/painting-marker-properties-01-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-01-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-01-t-ref.png
index 24028ea0..75342791 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-01-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-01-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-02-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-02-t-ref.png
index d9d0d045..cfdeaf63 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-02-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-02-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-03-f-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-03-f-ref.png
index 685dc52d..22b41888 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-03-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-03-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-04-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-04-t-ref.png
index 717df668..0fef0f56 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-04-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-04-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-05-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-05-t-ref.png
index 7eec461e..1c56225a 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-05-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-05-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-06-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-06-t-ref.png
index 7e416e90..ecbce292 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-06-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-06-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-07-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-07-t-ref.png
index 088968ae..d30b57f9 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-07-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-07-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-08-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-08-t-ref.png
index 112c3982..8ef25d37 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-08-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-08-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-09-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-09-t-ref.png
index 39718e22..fb88cd43 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-09-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-09-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-10-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-10-t-ref.png
index d3f98532..bd03e994 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-10-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-10-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-12-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-12-t-ref.png
index 8f9ac653..b36b0c75 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-12-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-12-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-13-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-13-t-ref.png
index 9de9435b..09ce359e 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-13-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-13-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-14-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-14-t-ref.png
index ea658ad6..ed0c4616 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-14-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-14-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-15-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-15-t-ref.png
index d294d90c..5fa5f1bb 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-15-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-15-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-16-t-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-16-t-ref.png
index a23ed484..52a69608 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-16-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-16-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-17-f-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-17-f-ref.png
index c27f1e33..0f1e4212 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-17-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-17-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-18-f-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-18-f-ref.png
index baafb1f6..92c07e70 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-18-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-18-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-19-f-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-19-f-ref.png
index 638f0bba..fb1458b2 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-19-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-19-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/paths-data-20-f-ref.png b/tests/fixtures/reftests/svg1.1/paths-data-20-f-ref.png
index 2da2620d..3e6e6165 100644
--- a/tests/fixtures/reftests/svg1.1/paths-data-20-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/paths-data-20-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-01-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-01-b-ref.png
index a291725f..ca817258 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-02-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-02-b-ref.png
index 62cb8e52..db6b81db 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-02-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-02-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-03-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-03-b-ref.png
index 61010b0a..5bc13580 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-03-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-03-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-04-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-04-b-ref.png
index a0da181f..84b6f89d 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-04-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-04-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-05-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-05-b-ref.png
index 4185e16d..34dc3fb3 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-05-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-05-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-06-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-06-b-ref.png
index 9e99fcb8..2715e4e7 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-06-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-06-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-07-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-07-b-ref.png
index 0ea7fd36..443063ae 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-07-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-07-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-08-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-08-b-ref.png
index 98270659..a0da8e08 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-08-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-08-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-09-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-09-b-ref.png
index d1042a7f..13936128 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-09-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-09-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-10-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-10-b-ref.png
index 9eea7bd3..12c1d259 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-10-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-10-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-11-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-11-b-ref.png
index d0b45300..2f47d1dd 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-11-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-11-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-12-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-12-b-ref.png
index 76554705..5fb15af1 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-12-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-12-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-13-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-13-b-ref.png
index cd6c3677..c271709c 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-13-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-13-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-14-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-14-b-ref.png
index 5eb15017..01fa8100 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-14-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-14-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-15-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-15-b-ref.png
index bd392ffe..ff51beb5 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-15-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-15-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-16-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-16-b-ref.png
index 65506fa1..9e18d1c9 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-16-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-16-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-18-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-18-b-ref.png
index 94224646..3a63d34a 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-18-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-18-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-21-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-21-b-ref.png
index 744233ec..363d0173 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-21-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-21-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-22-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-22-b-ref.png
index fcf5e2cd..b0406c27 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-22-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-22-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-23-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-23-f-ref.png
index 6984bd02..162fc0c7 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-23-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-23-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-24-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-24-f-ref.png
index 33d4aac8..2eeeb69e 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-24-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-24-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-grad-stops-01-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-grad-stops-01-f-ref.png
index 0b90dc21..fdbb2af0 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-grad-stops-01-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-grad-stops-01-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-01-b-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-01-b-ref.png
index d3e738cd..5796a812 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-02-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-02-f-ref.png
index 5124493b..97833ee3 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-02-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-02-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-03-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-03-f-ref.png
index dc7c7ff5..fa6b7faa 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-03-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-03-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-04-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-04-f-ref.png
index f24faa7e..63f49ccb 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-04-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-04-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-05-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-05-f-ref.png
index e58959f4..3a5dfcc5 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-05-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-05-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-06-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-06-f-ref.png
index a5363cfc..a3c326e4 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-06-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-06-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-07-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-07-f-ref.png
index d6cad2a2..15a90761 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-07-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-07-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-08-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-08-f-ref.png
index cafa92a1..0c740f00 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-08-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-08-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/pservers-pattern-09-f-ref.png b/tests/fixtures/reftests/svg1.1/pservers-pattern-09-f-ref.png
index 8d03731a..17e85951 100644
--- a/tests/fixtures/reftests/svg1.1/pservers-pattern-09-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/pservers-pattern-09-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-cond-01-t-ref.png b/tests/fixtures/reftests/svg1.1/struct-cond-01-t-ref.png
index 0eddb8f4..4046059d 100644
--- a/tests/fixtures/reftests/svg1.1/struct-cond-01-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-cond-01-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-cond-03-t-ref.png b/tests/fixtures/reftests/svg1.1/struct-cond-03-t-ref.png
index 9a6a1319..ad141d2d 100644
--- a/tests/fixtures/reftests/svg1.1/struct-cond-03-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-cond-03-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-svg-03-f-ref.png b/tests/fixtures/reftests/svg1.1/struct-svg-03-f-ref.png
index ef61c302..7d96f5f3 100644
--- a/tests/fixtures/reftests/svg1.1/struct-svg-03-f-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-svg-03-f-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-symbol-01-b-ref.png b/tests/fixtures/reftests/svg1.1/struct-symbol-01-b-ref.png
index 6fe638bb..35bba991 100644
--- a/tests/fixtures/reftests/svg1.1/struct-symbol-01-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-symbol-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-use-01-t-ref.png b/tests/fixtures/reftests/svg1.1/struct-use-01-t-ref.png
index 48738c06..60692afb 100644
--- a/tests/fixtures/reftests/svg1.1/struct-use-01-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-use-01-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-use-03-t-ref.png b/tests/fixtures/reftests/svg1.1/struct-use-03-t-ref.png
index 67243734..281b8850 100644
--- a/tests/fixtures/reftests/svg1.1/struct-use-03-t-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-use-03-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-use-04-b-ref.png b/tests/fixtures/reftests/svg1.1/struct-use-04-b-ref.png
index 7e42785e..d54ba9f7 100644
--- a/tests/fixtures/reftests/svg1.1/struct-use-04-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-use-04-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/struct-use-09-b-ref.png b/tests/fixtures/reftests/svg1.1/struct-use-09-b-ref.png
index 969a848e..2777a440 100644
--- a/tests/fixtures/reftests/svg1.1/struct-use-09-b-ref.png
+++ b/tests/fixtures/reftests/svg1.1/struct-use-09-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/text-align-01-b-ref.png b/tests/fixtures/reftests/svg1.1/text-align-01-b-ref.png
new file mode 100644
index 00000000..1b226908
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-align-01-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/text-align-01-b.svg b/tests/fixtures/reftests/svg1.1/text-align-01-b.svg
new file mode 100644
index 00000000..d6d6eb5a
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-align-01-b.svg
@@ -0,0 +1,80 @@
+<svg version="1.1" baseProfile="basic" id="svg-root"
+ width="100%" height="100%" viewBox="0 0 480 360"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= SVG 1.1 2nd Edition Test Case =-->
+ <!--======================================================================-->
+ <!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="SVGWG" author="Jon Ferraiolo" status="accepted"
+ version="$Revision: 1.8 $" testname="$RCSfile: text-align-01-b.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/text.html#AlignmentProperties">
+ <p>
+ Test 'text-anchor' property (horizontal).
+ </p>
+ <p>
+ The three lines test the three values for property 'text-anchor': start, middle and end.
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The lines in pink, 'text-anchor:none' and 'text-anchor:start', should both start from the same horizontal position (indicated by the black circle on each line) and extend to the right.
+ The green line, 'text-anchor:middle', should be centered horizontally around the black circle.
+ The blue line, 'text-anchor:end', should be aligned such that the end of the text meets the black circle.
+ </p>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: text-align-01-b.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text font-size="34" x="5" y="40">Test 'text-anchor' (horizontal)</text>
+ <g id="text-anchor" font-size="14">
+ <g transform="translate(230,130)">
+ <line stroke="black" x2="50"/>
+ <circle r="3"/>
+ <text font-size="30" fill="fuchsia">text-anchor:none</text>
+ </g>
+ <g transform="translate(230,180)">
+ <line stroke="black" x2="50"/>
+ <circle r="3"/>
+ <text font-size="30" text-anchor="start" fill="fuchsia">text-anchor:start</text>
+ </g>
+ <g transform="translate(230,230)">
+ <line stroke="black" x1="-25" x2="25"/>
+ <circle r="3"/>
+ <text font-size="30" text-anchor="middle" fill="green">text-anchor:middle</text>
+ </g>
+ <g transform="translate(230,280)">
+ <line stroke="black" x1="-50" x2="0"/>
+ <circle r="3"/>
+ <text font-size="30" text-anchor="end" fill="blue">text-anchor:end</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.8 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/fixtures/reftests/svg1.1/text-align-03-b-ref.png b/tests/fixtures/reftests/svg1.1/text-align-03-b-ref.png
new file mode 100644
index 00000000..cb1bf686
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-align-03-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/text-align-03-b.svg b/tests/fixtures/reftests/svg1.1/text-align-03-b.svg
new file mode 100644
index 00000000..19bbf7c5
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-align-03-b.svg
@@ -0,0 +1,82 @@
+<svg version="1.1" baseProfile="basic" id="svg-root"
+ width="100%" height="100%" viewBox="0 0 480 360"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= SVG 1.1 2nd Edition Test Case =-->
+ <!--======================================================================-->
+ <!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="SVGWG" author="Lofton Henderson" status="accepted"
+ version="$Revision: 1.7 $" testname="$RCSfile: text-align-03-b.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/text.html#AlignmentProperties">
+ <p>
+ Test for viewer capibility to handle the basics of the 'textAnchor'
+ alignment property for 'text' and related elements.
+ </p>
+ <p>
+ This test verify that
+ the interpreter correctly handles and applies the text-anchor
+ properties when present on "chunks", which are comprised of tspan elements
+ with absolute positioning, within the containing 'text' element.
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The test is passed if
+ </p>
+ <ul>
+ <li>
+ The text "Begin with "end"," ends just to the left of the vertical pink
+ line.
+ </li>
+ <li>
+ The text "switch to "middle" in a tspan," is split by the vertical pink
+ line roughly through the second 'd' in the world "middle".
+ </li>
+ <li>
+ The text "and "start" ends it." begins just to the right of the
+ vertical pink line.
+ </li>
+ </ul>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: text-align-03-b.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="5" y="40" font-size="40" fill="black">Test of 'text-anchor'</text>
+
+ <!-- Test cases -->
+ <line x1="225" y1="75" x2="225" y2="225" stroke="fuchsia"/>
+ <g font-size="30" fill="blue">
+ <text x="225" y="110" text-anchor="end">
+ Begin with "end",<tspan x="225" y="160" xml:space="preserve" text-anchor="middle"> switch to "middle" in a tspan, </tspan><tspan x="225" y="210" text-anchor="start">and "start" ends it.</tspan>
+ </text>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.7 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/fixtures/reftests/svg1.1/text-text-03-b-ref.png b/tests/fixtures/reftests/svg1.1/text-text-03-b-ref.png
new file mode 100644
index 00000000..0469b1f9
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-text-03-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/text-text-03-b.svg b/tests/fixtures/reftests/svg1.1/text-text-03-b.svg
new file mode 100644
index 00000000..5f8617b7
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-text-03-b.svg
@@ -0,0 +1,94 @@
+<svg version="1.1" baseProfile="basic" id="svg-root"
+ width="100%" height="100%" viewBox="0 0 480 360"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= SVG 1.1 2nd Edition Test Case =-->
+ <!--======================================================================-->
+ <!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="SVGWG" author="Shenxue Zhou" status="accepted"
+ version="$Revision: 1.9 $" testname="$RCSfile: text-text-03-b.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/text.html#TextElement">
+ <p>
+ Test text element, tspan element and various text decorations
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The test is passed if:
+ </p>
+ <ul>
+ <li>the word "Plain" is displayed using a blue serif font</li>
+ <li>the word "Italic" is displayed using a blue italic serif font</li>
+ <li>the word "Bold" is displayed using a blue serif bold font</li>
+ <li>the words "Line through" are displayed with a line through, using a pink serif font</li>
+ <li>the word "Underline" is displayed underlined using a blue serif font</li>
+ <li>the words "Bold, italic and underlined" are displayed underlined using a bold italic serif font</li>
+ </ul>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: text-text-03-b.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ <font-face font-family="FreeSerif" unicode-range="U+0-7F" font-weight="400">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/FreeSerif.svg#FreeSerif"/>
+ </font-face-src>
+ </font-face>
+ <font-face font-family="FreeSerif" unicode-range="U+0-7F" font-weight="700">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/FreeSerifBold.svg#FreeSerifBold"/>
+ </font-face-src>
+ </font-face>
+ <font-face font-family="FreeSerif" unicode-range="U+0-7F" font-weight="400" font-style="italic">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/FreeSerifItalic.svg#FreeSerifItalic"/>
+ </font-face-src>
+ </font-face>
+ <font-face font-family="FreeSerif" unicode-range="U+0-7F" font-weight="700" font-style="italic">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/FreeSerifBoldItalic.svg#FreeSerifBoldItalic"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="FreeSerif, serif" font-size="18">
+ <text x="19" y="61" font-size="32" fill="blue">Plain</text>
+ <text x="142" y="61" font-size="32" font-style="italic" fill="blue">Italic</text>
+ <text x="257" y="60" font-size="32" font-weight="bold" fill="blue">Bold</text>
+ <text x="224" y="110" font-size="32" fill="blue" text-decoration="underline">Underline</text>
+ <text x="39" y="147" font-size="32" fill="fuchsia" text-decoration="line-through">Line through</text>
+ <text x="1" y="200" font-size="32" font-style="italic" font-weight="bold" fill="black" text-decoration="underline">Bold, italic and underlined</text>
+ <g>
+ <rect x="50" y="225" width="380" height="64" fill="none" stroke="black" stroke-width="2"/>
+ <g font-family="SVGFreeSansASCII,sans-serif">
+ <text x="55" y="245" font-size="24" fill="black">Each line of text which flows in a </text>
+ <text x="55" y="265" font-size="24" fill="black">rectangular box has to be broken</text>
+ <text x="55" y="285" font-size="24" fill="black">into separated lines.</text>
+ </g>
+ </g>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.9 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/fixtures/reftests/svg1.1/text-text-08-b-ref.png b/tests/fixtures/reftests/svg1.1/text-text-08-b-ref.png
new file mode 100644
index 00000000..1058f5a6
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-text-08-b-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/text-text-08-b.svg b/tests/fixtures/reftests/svg1.1/text-text-08-b.svg
new file mode 100644
index 00000000..b3938c1d
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-text-08-b.svg
@@ -0,0 +1,64 @@
+<svg version="1.1" baseProfile="basic" id="svg-root"
+ width="100%" height="100%" viewBox="0 0 480 360"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= SVG 1.1 2nd Edition Test Case =-->
+ <!--======================================================================-->
+ <!--= Copyright 2009 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="DJ" author="SH" status="accepted"
+ version="$Revision" testname="$RCSfile: text-text-08-b.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/text.html#TextElement">
+ <p>
+ The three opacity properties (fill-opacity,
+ stroke-opacity, and opacity) of 'text' elements are
+ covered in this test.
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The test is passed if:
+ </p>
+ <ul>
+ <li>The text "Normal Text" has a pink stroke with no opacity and a blue fill with no opacity.</li>
+ <li>The text "Fill Opacity" has a pink stroke with no opacity and a blue fill with 50% opacity.</li>
+ <li>The text "Stroke Opacity" has a pink stroke with 50% opacity and a blue fill with no opacity.</li>
+ <li>The text "Opacity" has a pink stroke and a blue fill both with 50% opacity.</li>
+ </ul>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: text-text-08-b.svg,v $</title>
+ <defs>
+ <font-face font-family="SVGFreeSansASCII" unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+ <text x="19" y="60" font-size="64" font-family="Verdana" fill="blue" stroke="fuchsia" stroke-width="2">Normal Text</text>
+ <text x="19" y="120" font-size="64" font-family="Verdana" fill="blue" stroke="fuchsia" stroke-width="2" fill-opacity="0.50">Fill opacity</text>
+ <text x="19" y="180" font-size="64" font-family="Verdana" fill="blue" stroke="fuchsia" stroke-width="2" stroke-opacity="0.50">Stroke opacity</text>
+ <text x="19" y="240" font-size="64" font-family="Verdana" fill="blue" stroke="fuchsia" stroke-width="2" opacity="0.50">Opacity</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none" fill="black">$Revision: 1.6 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000000"/>
+ <!-- comment out this watermark once the test is approved -->
+ <!--<g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/fixtures/reftests/svg1.1/text-text-10-t-ref.png b/tests/fixtures/reftests/svg1.1/text-text-10-t-ref.png
new file mode 100644
index 00000000..f9860895
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-text-10-t-ref.png
Binary files differ
diff --git a/tests/fixtures/reftests/svg1.1/text-text-10-t.svg b/tests/fixtures/reftests/svg1.1/text-text-10-t.svg
new file mode 100644
index 00000000..57b0e1b9
--- /dev/null
+++ b/tests/fixtures/reftests/svg1.1/text-text-10-t.svg
@@ -0,0 +1,76 @@
+<svg id="svg-root" width="100%" height="100%"
+ viewBox="0 0 480 360" xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!--======================================================================-->
+ <!--= Copyright 2008 World Wide Web Consortium, (Massachusetts =-->
+ <!--= Institute of Technology, European Research Consortium for =-->
+ <!--= Informatics and Mathematics (ERCIM), Keio University). =-->
+ <!--= All Rights Reserved. =-->
+ <!--= See http://www.w3.org/Consortium/Legal/. =-->
+ <!--======================================================================-->
+ <d:SVGTestCase xmlns:d="http://www.w3.org/2000/02/svg/testsuite/description/"
+ template-version="1.4" reviewer="CL" author="ED" status="accepted"
+ version="$Revision: 1.3 $" testname="$RCSfile: text-text-10-t.svg,v $">
+ <d:testDescription xmlns="http://www.w3.org/1999/xhtml" href="http://www.w3.org/TR/SVG11/text.html#TextElement">
+ <p>
+ Test rendering of text rotated by a transform attribute.
+ </p>
+ </d:testDescription>
+ <d:operatorScript xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ Run the test. No interaction required.
+ </p>
+ </d:operatorScript>
+ <d:passCriteria xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ The test has passed if the image shows text rotated by various different angles, the result should closely match the reference image.
+ </p>
+ </d:passCriteria>
+ </d:SVGTestCase>
+ <title id="test-title">$RCSfile: text-text-10-t.svg,v $</title>
+ <defs>
+ <font-face
+ font-family="SVGFreeSansASCII"
+ unicode-range="U+0-7F">
+ <font-face-src>
+ <font-face-uri xlink:href="../resources/SVGFreeSans.svg#ascii"/>
+ </font-face-src>
+ </font-face>
+ </defs>
+ <g id="test-body-content" font-family="SVGFreeSansASCII,sans-serif" font-size="18">
+
+ <text transform="rotate(90) translate(120 -100)" text-anchor="middle">Rotated 90 degrees</text>
+ <text transform="rotate(-90) translate(-120 140)" text-anchor="middle">Rotated -90 degrees</text>
+ <text transform="rotate(180) translate(-120 -250)" text-anchor="middle">Rotated 180 degrees</text>
+ <text transform="rotate(360) translate(120 230)" text-anchor="middle">Unrotated text</text>
+ <text transform="translate(250 180) rotate(85 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(75 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(65 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(55 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(45 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(35 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(25 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(15 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(5 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-5 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-15 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-25 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-35 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-45 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-55 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-65 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-75 0 0)">Rotated by 10 degrees</text>
+ <text transform="translate(250 180) rotate(-85 0 0)">Rotated by 10 degrees</text>
+ </g>
+ <g font-family="SVGFreeSansASCII,sans-serif" font-size="32">
+ <text id="revision" x="10" y="340" stroke="none"
+ fill="black">$Revision: 1.3 $</text>
+ </g>
+ <rect id="test-frame" x="1" y="1" width="478" height="358" fill="none" stroke="#000"/>
+ <!-- comment out this watermark once the test is approved
+ <g id="draft-watermark">
+ <rect x="1" y="1" width="478" height="20" fill="red" stroke="black" stroke-width="1"/>
+ <text font-family="SVGFreeSansASCII,sans-serif" font-weight="bold" font-size="20" x="240"
+ text-anchor="middle" y="18" stroke-width="0.5" stroke="black" fill="white">DRAFT</text>
+ </g>-->
+</svg>
diff --git a/tests/resources/LiberationSans-Regular.ttf b/tests/resources/LiberationSans-Regular.ttf
deleted file mode 100644
index 4159df6c..00000000
--- a/tests/resources/LiberationSans-Regular.ttf
+++ /dev/null
Binary files differ
diff --git a/tests/resources/Roboto-Bold.ttf b/tests/resources/Roboto-Bold.ttf
new file mode 100644
index 00000000..a8129aed
--- /dev/null
+++ b/tests/resources/Roboto-Bold.ttf
Binary files differ
diff --git a/tests/resources/Roboto-BoldItalic.ttf b/tests/resources/Roboto-BoldItalic.ttf
new file mode 100644
index 00000000..aaf75154
--- /dev/null
+++ b/tests/resources/Roboto-BoldItalic.ttf
Binary files differ
diff --git a/tests/resources/Roboto-Italic.ttf b/tests/resources/Roboto-Italic.ttf
new file mode 100644
index 00000000..73ddfd04
--- /dev/null
+++ b/tests/resources/Roboto-Italic.ttf
Binary files differ
diff --git a/tests/resources/Roboto-Regular.ttf b/tests/resources/Roboto-Regular.ttf
new file mode 100644
index 00000000..37492803
--- /dev/null
+++ b/tests/resources/Roboto-Regular.ttf
Binary files differ
diff --git a/tests/styles.c b/tests/styles.c
index ae90f620..1af4f0bc 100644
--- a/tests/styles.c
+++ b/tests/styles.c
@@ -117,7 +117,6 @@ main (int argc, char *argv[])
RSVG_G_TYPE_INIT;
g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
for (i = 0; i < n_fixtures; i++)
g_test_add_data_func (fixtures[i].test_name, &fixtures[i], (void*)test_value);
diff --git a/win32/rsvg-rust.mak b/win32/rsvg-rust.mak
index fdde4365..6561d156 100644
--- a/win32/rsvg-rust.mak
+++ b/win32/rsvg-rust.mak
@@ -32,9 +32,9 @@ CARGO_CMD = $(CARGO) build $(CARGO_TARGET) --release
CARGO_CMD = $(CARGO) build $(CARGO_TARGET)
!endif
-all: vs$(VSVER)\$(CFG)\$(PLAT)\obj\rsvg_internals\$(CFG)\rsvg_internals.lib
+all: vs$(VSVER)\$(CFG)\$(PLAT)\obj\rsvg_internals\$(RUST_TARGET)-pc-windows-msvc\$(CFG)\rsvg_internals.lib
-vs$(VSVER)\$(CFG)\$(PLAT)\obj\rsvg_internals\$(CFG)\rsvg_internals.lib:
+vs$(VSVER)\$(CFG)\$(PLAT)\obj\rsvg_internals\$(RUST_TARGET)-pc-windows-msvc\$(CFG)\rsvg_internals.lib:
@set CARGO_TARGET_DIR=..\win32\vs$(VSVER)\$(CFG)\$(PLAT)\obj\rsvg_internals
@set GTK_LIB_DIR=..\..\vs$(VSVER)\$(PLAT)\lib;$(LIB)
$(RUSTUP_CMD)
diff --git a/win32/vs12/rsvg-build-defines.props b/win32/vs12/rsvg-build-defines.props
index 31416ddd..a330d6a5 100644
--- a/win32/vs12/rsvg-build-defines.props
+++ b/win32/vs12/rsvg-build-defines.props
@@ -12,6 +12,8 @@
<Gtk3IncPath>$(GlibEtcInstallRoot)\include\gtk-3.0;$(GlibEtcInstallRoot)\include\atk-1.0;$(LibRsvgIncPath)</Gtk3IncPath>
<Gtk3Libs>gtk-3.0.lib;gdk-3.0.lib</Gtk3Libs>
<RsvgPixbufLoaderCFlags>GDK_PIXBUF_ENABLE_BACKEND;G_LOG_DOMAIN="libpixbufloader-svg"</RsvgPixbufLoaderCFlags>
+ <RustTargetArch Condition="'$(Platform)' == 'x64'">x86_64</RustTargetArch>
+ <RustTargetArch Condition="'$(Platform)' == 'Win32'">i686</RustTargetArch>
<RsvgRustNMakeCmd>
cd ..
set VCInstallDir=$(VCInstallDir)
@@ -61,5 +63,8 @@ nmake -f rsvg-rust.mak CFG=$(Configuration)</RsvgRustNMakeCmd>
<BuildMacro Include="RsvgRustNMakeCmd">
<Value>$(RsvgRustNMakeCmd)</Value>
</BuildMacro>
+ <BuildMacro Include="RustTargetArch">
+ <Value>$(RustTargetArch)</Value>
+ </BuildMacro>
</ItemGroup>
</Project>
diff --git a/win32/vs12/rsvg-rust.vcxproj b/win32/vs12/rsvg-rust.vcxproj
index 2a04e779..4ee2891f 100644
--- a/win32/vs12/rsvg-rust.vcxproj
+++ b/win32/vs12/rsvg-rust.vcxproj
@@ -71,25 +71,25 @@
<NMakeBuildCommandLine>$(RsvgRustNMakeCmd)</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(RsvgRustNMakeCmd) clean all</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(RsvgRustNMakeCmd) clean</NMakeCleanCommandLine>
- <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(Configuration)\rsvg_internals.lib</NMakeOutput>
+ <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(RustTargetArch)-pc-windows-msvc\$(Configuration)\rsvg_internals.lib</NMakeOutput>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<NMakeBuildCommandLine>$(RsvgRustNMakeCmd)</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(RsvgRustNMakeCmd) clean all</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(RsvgRustNMakeCmd) clean</NMakeCleanCommandLine>
- <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(Configuration)\rsvg_internals.lib</NMakeOutput>
+ <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(RustTargetArch)-pc-windows-msvc\$(Configuration)\rsvg_internals.lib</NMakeOutput>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>$(RsvgRustNMakeCmd)</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(RsvgRustNMakeCmd) clean all</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(RsvgRustNMakeCmd) clean</NMakeCleanCommandLine>
- <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(Configuration)\rsvg_internals.lib</NMakeOutput>
+ <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(RustTargetArch)-pc-windows-msvc\$(Configuration)\rsvg_internals.lib</NMakeOutput>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>$(RsvgRustNMakeCmd)</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>$(RsvgRustNMakeCmd) clean all</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>$(RsvgRustNMakeCmd) clean</NMakeCleanCommandLine>
- <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(Configuration)\rsvg_internals.lib</NMakeOutput>
+ <NMakeOutput>$(SolutionDir)\$(Configuration)\$(Platform)\obj\rsvg_internals\$(RustTargetArch)-pc-windows-msvc\$(Configuration)\rsvg_internals.lib</NMakeOutput>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">