Skip to content

Commit

Permalink
New: Flag to control xlink prefix on href
Browse files Browse the repository at this point in the history
After some extensive testing it seems that some browsers, in some cases, will not display SVG if the `href` attribute is prefixed with `xlink`, a change that was introduced with SVG 2.0. This is not yet a recognized specification, but the changes in browsers are being enacted nevertheless.

On the other hand, some strict SVG 1.1 clients will not render the SVG correctly if it *doesn't* include the `xlink:` prefix. In my testing this included Inkscape.

Given that the most likely target for Verovio output is browsers, but still wishing to retain backwards compatibility, this PR changes the default behaviour from producing `xlink:href` to simply `href`. Clients that need the full attribute name can set `--svg-include-xlink` which will insert the xlink prefix on the href attributes.

References previous discussions on this topic: #1158, #332
  • Loading branch information
ahankinson committed Feb 26, 2021
1 parent 0eac85d commit f5487d8
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 1 deletion.
1 change: 1 addition & 0 deletions include/vrv/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ class Options {
OptionBool m_svgViewBox;
OptionBool m_svgHtml5;
OptionBool m_svgFormatRaw;
OptionBool m_svgIncludeXlink;
OptionInt m_unit;
OptionBool m_useFacsimile;
OptionBool m_usePgFooterForAll;
Expand Down
7 changes: 7 additions & 0 deletions include/vrv/svgdevicecontext.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ class SvgDeviceContext : public DeviceContext {
* Set the SVG to have 'raw' formatting, with no extraneous whitespace or newlines.
*/
void SetFormatRaw(bool rawFormat) { m_formatRaw = rawFormat; }

/**
* Set the xlink: prefex on href attributes
*/
void SetXlinkOnHref(bool includeXlink) { m_includeXlink = includeXlink; }

private:
/**
Expand Down Expand Up @@ -279,6 +284,8 @@ class SvgDeviceContext : public DeviceContext {
bool m_html5;
// format output as raw, stripping extraneous whitespace and non-content newlines
bool m_formatRaw;
// include xlink on href attributes
bool m_includeXlink;
// indentation value (-1 for tabs)
int m_indent;
};
Expand Down
5 changes: 5 additions & 0 deletions src/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,11 @@ Options::Options()
"Raw formatting for SVG output", "Writes SVG out with no line indenting or non-content newlines.");
m_svgFormatRaw.Init(false);
this->Register(&m_svgFormatRaw, "svgFormatRaw", &m_general);

m_svgIncludeXlink.SetInfo(
"Include xlink: on href attributes", "Includes the xlink: prefix on href attributes for compatibility with older SVG viewers.");
m_svgIncludeXlink.Init(false);
this->Register(&m_svgIncludeXlink, "svgIncludeXlink", &m_general);

m_unit.SetInfo("Unit", "The MEI unit (1⁄2 of the distance between the staff lines)");
m_unit.Init(9, 6, 20, true);
Expand Down
9 changes: 8 additions & 1 deletion src/svgdevicecontext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ SvgDeviceContext::SvgDeviceContext() : DeviceContext()
m_svgViewBox = false;
m_html5 = false;
m_formatRaw = false;
m_includeXlink = false;
m_facsimile = false;
m_indent = 2;

Expand Down Expand Up @@ -857,6 +858,12 @@ void SvgDeviceContext::DrawMusicText(const std::wstring &text, int x, int y, boo

int w, h, gx, gy;

// include the `xlink:` prefix for backwards compatibility with older SVG viewers.
std::string hrefAttrib = "href";
if (m_includeXlink) {
hrefAttrib.insert(0, "xlink:");
}

// print chars one by one
for (unsigned int i = 0; i < text.length(); ++i) {
wchar_t c = text.at(i);
Expand All @@ -872,7 +879,7 @@ void SvgDeviceContext::DrawMusicText(const std::wstring &text, int x, int y, boo

// Write the char in the SVG
pugi::xml_node useChild = AppendChild("use");
useChild.append_attribute("xlink:href") = StringFormat("#%s", glyph->GetCodeStr().c_str()).c_str();
useChild.append_attribute(hrefAttrib.c_str()) = StringFormat("#%s", glyph->GetCodeStr().c_str()).c_str();
useChild.append_attribute("x") = x;
useChild.append_attribute("y") = y;
useChild.append_attribute("height") = StringFormat("%dpx", m_fontStack.top()->GetPointSize()).c_str();
Expand Down
1 change: 1 addition & 0 deletions src/toolkit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,7 @@ std::string Toolkit::RenderToSVG(int pageNo, bool xml_declaration)

svg.SetHtml5(m_options->m_svgHtml5.GetValue());
svg.SetFormatRaw(m_options->m_svgFormatRaw.GetValue());
svg.SetXlinkOnHref(m_options->m_svgIncludeXlink.GetValue());

// render the page
RenderToDeviceContext(pageNo, &svg);
Expand Down

0 comments on commit f5487d8

Please sign in to comment.