Skip to content

Commit

Permalink
put svg with xmlns in img src tag (#1538)
Browse files Browse the repository at this point in the history
  • Loading branch information
jkrumbiegel authored Mar 17, 2021
1 parent 22d4e43 commit a7df180
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@

* ![Bugfix][badge-bugfix] A bad `repo` argument to `deploydocs` containing a protocol now throws an error instead of being misinterpreted. ([#1531][github-1531], [#1533][github-1533])

* ![Bugfix][badge-bugfix] SVG images generated by `@example` blocks are now properly scaled to page width by URI-encoding the images, instead of directly embedding the SVG tags into the HTML. ([#1537][github-1537], [#1538][github-1538])

* ![Maintenance][badge-maintenance] Documenter is no longer compatible with IOCapture v0.1 and now requires IOCapture v0.2. ([#1549][github-1549])


## Version `v0.26.3`

* ![Maintenance][badge-maintenance] The internal naming of the temporary modules used to run doctests changed to accommodate upcoming printing changes in Julia. ([JuliaLang/julia#39841][julia-39841], [#1540][github-1540])
Expand Down Expand Up @@ -766,6 +769,8 @@
[github-1529]: https://github.com/JuliaDocs/Documenter.jl/pull/1529
[github-1531]: https://github.com/JuliaDocs/Documenter.jl/issues/1531
[github-1533]: https://github.com/JuliaDocs/Documenter.jl/pull/1533
[github-1537]: https://github.com/JuliaDocs/Documenter.jl/issues/1537
[github-1538]: https://github.com/JuliaDocs/Documenter.jl/pull/1538
[github-1540]: https://github.com/JuliaDocs/Documenter.jl/pull/1540
[github-1549]: https://github.com/JuliaDocs/Documenter.jl/pull/1549
[github-1551]: https://github.com/JuliaDocs/Documenter.jl/pull/1551
Expand Down
44 changes: 43 additions & 1 deletion src/Writers/HTMLWriter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1748,7 +1748,49 @@ function mdconvert(d::Dict{MIME,Any}, parent; kwargs...)
if haskey(d, MIME"text/html"())
out = Documents.RawHTML(d[MIME"text/html"()])
elseif haskey(d, MIME"image/svg+xml"())
out = Documents.RawHTML(d[MIME"image/svg+xml"()])
svg = d[MIME"image/svg+xml"()]
svg_tag_match = match(r"<svg[^>]*>", svg)
if svg_tag_match === nothing
# There is no svg tag so we don't do any more advanced
# processing and just return the svg as RawHTML.
# The svg string should be invalid but that's not our concern here.
out = Documents.RawHTML(svg)
else
# The xmlns attribute has to be present for data:image/svg+xml
# to work (https://stackoverflow.com/questions/18467982).
# If it doesn't exist, we splice it into the first svg tag.
# This should never invalidate otherwise valid svg.
svg_tag = svg_tag_match.match
xmlns_present = occursin("xmlns", svg_tag)
if !xmlns_present
svg = replace(svg, "<svg" => "<svg xmlns=\"http://www.w3.org/2000/svg\"", count = 1)
end

# We can leave the svg as utf8, but the minimum safety precaution we need
# is to ensure the src string separator is not in the svg.
# That can be either " or ', and the svg will most likely use only one of them
# so we check which one occurs more often and use the other as the separator.
# This should leave most svg basically intact.

# Replace % with %25 and # with %23 https://github.com/jakubpawlowicz/clean-css/issues/763#issuecomment-215283553
svg = replace(svg, "%" => "%25")
svg = replace(svg, "#" => "%23")

singles = count(==('\''), svg)
doubles = count(==('"'), svg)
if singles > doubles
# Replace every " with %22 because it terminates the src=" string otherwise
svg = replace(svg, "\"" => "%22")
sep = "\""
else
# Replace every ' with %27 because it terminates the src=' string otherwise
svg = replace(svg, "\'" => "%27")
sep = "'"
end

out = Documents.RawHTML(string("<img src=", sep, "data:image/svg+xml;utf-8,", svg, sep, "/>"))
end

elseif haskey(d, MIME"image/png"())
out = Documents.RawHTML(string("<img src=\"data:image/png;base64,", d[MIME"image/png"()], "\" />"))
elseif haskey(d, MIME"image/webp"())
Expand Down
77 changes: 77 additions & 0 deletions test/examples/src/man/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ Base.show(io, ::MIME"image/svg+xml", svg::SVG) = write(io, svg.code)
end # module
```

Without xmlns tag:

```@example inlinesvg
using .InlineSVG
SVG("""
Expand All @@ -195,6 +197,81 @@ SVG("""
""")
```

With xmlns tag:

```@example inlinesvg
using .InlineSVG
SVG("""
<svg width="82" height="76" xmlns="http://www.w3.org/2000/svg">
<g style="stroke-width: 3">
<circle cx="20" cy="56" r="16" style="stroke: #cb3c33; fill: #d5635c" />
<circle cx="41" cy="20" r="16" style="stroke: #389826; fill: #60ad51" />
<circle cx="62" cy="56" r="16" style="stroke: #9558b2; fill: #aa79c1" />
</g>
</svg>
""")
```

With single quotes:

```@example inlinesvg
using .InlineSVG
SVG("""
<svg width='82' height='76' xmlns='http://www.w3.org/2000/svg'>
<g style='stroke-width: 3'>
<circle cx='20' cy='56' r='16' style='stroke: #cb3c33; fill: #d5635c' />
<circle cx='41' cy='20' r='16' style='stroke: #389826; fill: #60ad51' />
<circle cx='62' cy='56' r='16' style='stroke: #9558b2; fill: #aa79c1' />
</g>
</svg>
""")
```

With a mixture of single and double quotes:

```@example inlinesvg
using .InlineSVG
SVG("""
<svg width='82' height='76' xmlns='http://www.w3.org/2000/svg'>
<g style='stroke-width: 3'>
<circle cx='20' cy='56' r='16' style='stroke: #cb3c33; fill: #d5635c' />
<circle cx="41" cy="20" r="16" style="stroke: #389826; fill: #60ad51" />
<circle cx='62' cy='56' r='16' style='stroke: #9558b2; fill: #aa79c1' />
</g>
</svg>
""")
```

With viewBox and without xmlns, making the svg really large to test that it is resized correctly:

```@example inlinesvg
using .InlineSVG
SVG("""
<svg width="8200" height="7600" viewBox="0 0 82 76">
<g style="stroke-width: 3">
<circle cx="20" cy="56" r="16" style="stroke: #cb3c33; fill: #d5635c" />
<circle cx="41" cy="20" r="16" style="stroke: #389826; fill: #60ad51" />
<circle cx="62" cy="56" r="16" style="stroke: #9558b2; fill: #aa79c1" />
</g>
</svg>
""")
```

Without viewBox and without xmlns, making the svg really large to test that it is resized correctly:

```@example inlinesvg
using .InlineSVG
SVG("""
<svg width="8200" height="7600">
<g style="stroke-width: 300">
<circle cx="2000" cy="5600" r="1600" style="stroke: #cb3c33; fill: #d5635c" />
<circle cx="4100" cy="2000" r="1600" style="stroke: #389826; fill: #60ad51" />
<circle cx="6200" cy="5600" r="1600" style="stroke: #9558b2; fill: #aa79c1" />
</g>
</svg>
""")
```

_Note: we can't define the `show` method in the `@example` block due to the world age
counter in Julia 0.6 (Documenter's `makedocs` is not aware of any of the new method
definitions happening in `eval`s)._
Expand Down

0 comments on commit a7df180

Please sign in to comment.