Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

svgタグ内の改行がbrタグに変換される #38

Closed
butameron opened this issue Aug 13, 2020 · 17 comments
Closed

svgタグ内の改行がbrタグに変換される #38

butameron opened this issue Aug 13, 2020 · 17 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@butameron
Copy link

Describe the bug
svgタグをVFM内に直接記述した場合、タグ内部の改行がbrタグに変換されます

To Reproduce

入力

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 width="100%" height="100%" viewBox="0 0 3000 3000">
<image width="3000" height="3000" xlink:href="../image/cover.jpg"/>
</svg>

出力

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 3000 3000"><br></br>
<image width="3000" height="3000" xlink:href="../image/cover.jpg"></image><br></br>
</svg></p>
</body>
</html>

上記のように、svgタグ内の改行がbrタグに変換されています。

Expected behavior

改行がbrタグに変換されず、以下のように出力されるのが期待される結果です。

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 3000 3000">
<image width="3000" height="3000" xlink:href="../image/cover.jpg"></image>
</svg></p>
</body>
</html>

Additional context

Markdownの中でインラインSVGを使用するケース自体がレアかもしれませんが、今回のケースでは、EPUBと印刷物の制作を一つのmarkdownから行うことを目的として、電書協やKADOKAWAのepub制作ガイドラインで推奨されている「SVGラッピング」と呼ばれる手法を用いる必要があったためインラインSVGを使用したものです。

svgタグの内部に改行を含めないようにすることで回避可能ですが、うっかり改行によりbrタグが入り込んでいてもビューワによって挙動が異なるため、気付かないリスクがあります。例えば、Chrome上のVivliostyle Viewerでは恐らくbrタグがあっても正常に表示されますが、Kindle Previewerなどでは異常な表示となります。

電子書籍と印刷物をワンソースで制作するというのはVFMの想定ユースケースとそれほどズレないと思いますので、svgタグ内部の改行をbrタグに変換しないようにするという対応が必要と考えます。

加えて、 画像の構文![xxx](./path/to/img)を拡張してSVGラッピングでレンダリングされるオプションを追加する(例:![xxx](./path/to/img =3000x3000,svg))というような対応があると便利かもしれません。ただ、SVGラッピング自体が過渡的なハックに過ぎないようにも思えるため、あえてVFMの構文の仕様を弄るべきかというとかなり微妙なような気もします。

@butameron butameron added the bug Something isn't working label Aug 13, 2020
@akabekobeko
Copy link
Member

改行に対応する <br> の自動挿入は remark-breaks によって「常に」処理されます。VFM の設計方針として 2021/1/9 の開発者会議で CommonMark/GFM 互換を維持して、これらを上書きする挙動はオプション扱いすることになりました。

この対応は #50 の一貫として実施されます。

@akabekobeko akabekobeko self-assigned this Jan 16, 2021
@akabekobeko
Copy link
Member

akabekobeko commented Jan 22, 2021

@butameron
VFM は明示的にオプション指定しない限り改行の <br> 処理をしないようにしました→ #50

この変更は v1.0.0-alpha.16 に反映されましたので、ご確認ください。以下はこのバージョンを CLI で実行した例です。

オプション指定なし (<br> 処理なし)

$ vfm sample.md                                                                                                     [~/Downloads]
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 3000 3000">
<image width="3000" height="3000" xlink:href="../image/cover.jpg"></image>
</svg></p>
</body>
</html>

オプション指定あり (<br> 処理あり)

$ vfm sample.md --hard-line-breaks                                                                                  [~/Downloads]
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<p><svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 3000 3000"><br></br>
<image width="3000" height="3000" xlink:href="../image/cover.jpg"></image><br></br>
</svg></p>
</body>
</html>

@spring-raining
Copy link
Member

spring-raining commented Jan 22, 2021

上記の回避策とは別に、--hard-line-breakオプションありであっても、htmlコンテキスト内で改行が<br>に置換される動作はおかしいと思います。基本的に、XMLタグ内のテキストはMarkdownとして解釈されない仕様のはずです。

@akabekobeko
Copy link
Member

たしかにそうですね。改行を担当している remark-breaks の実装を読むと unist-util-visittext に対して処理しているのですが SVG も対象に含まれています。よって

  1. SVG が text として扱われないようにする
  2. remark-breaks で HTML/XML タグを回避できるように正規表現を修正する要望を出す
  3. remark-breaks を VFM に移植して方法 2 を自前で処理する

などの方法で対応する必要があります。

@akabekobeko
Copy link
Member

akabekobeko commented Jan 23, 2021

remark-parse v9 以降の調査用に作成した以下のプロジェクトで試したら <svg></svg> の MDAST は html になってました。

なので前述の方法でいう 1 になるのが正しそうです。この方向で VFM 側も継続調査します。

@akabekobeko
Copy link
Member

原因判明。<svg><image> は MDAST で html となるが、そこに含まれる \n などは text になるため remark-breaks の対象になってしまう。また

基本的に、XMLタグ内のテキストはMarkdownとして解釈されない仕様のはずです。

を考慮すると VFM が追加している構文でも unist-util-visit を利用して text を処理すると同じ問題が発生する可能性がある。

@akabekobeko
Copy link
Member

akabekobeko commented Jan 23, 2021

table タグは子も含めてひとつの html になる。<svg>...</svg> は子が独立して解析される。akabekobeko/examples-remark-plugin-old

const md = `{a|b}
<table>
<tbody>
  <tr><td>aaa</td></tr>
</tbody>
</table>

<svg xmlns="http://www.w3.org/2000/svg" version="1.1"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  width="100%" height="100%" viewBox="0 0 3000 3000">
<image width="3000" height="3000" xlink:href="../image/cover.jpg"/>
</svg>`

を指定した結果を出力すると以下となった。

    root[3]
    ├─0 paragraph[1]
    │   └─0 ruby[1]
    │       │ data: {"hName":"ruby","rubyText":"b"}
    │       └─0 text "a"
    ├─1 html "<table>\n<tbody>\n  <tr><td>aaa</td></tr>\n</tbody>\n</table>"
    └─2 paragraph[5]
        ├─0 html "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n  xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n  width=\"100%\" height=\"100%\" viewBox=\"0 0 3000 3000\">"
        ├─1 text "\n"
        ├─2 html "<image width=\"3000\" height=\"3000\" xlink:href=\"../image/cover.jpg\"/>"
        ├─3 text "\n"
        └─4 html "</svg>"

期待値としては <table> と同様に <svg>...</svg> が一つの html になることだが、そうなっていない。また HTML/XML として親子関係にもならない。

@akabekobeko
Copy link
Member

akabekobeko commented Jan 23, 2021

最新の remark-parse v9.0.0 を利用している akabekobeko/examples-remark-plugin-micromark で試しても再現。おそらく <math> でも起きるだろう、と試したら想定通り子要素がすべて個別に解析された。

remark-parse v8 は本体、v9 以降は本体と remark-gfm<svg><math> などの解析に関する仕様、設定、issue がないか調べる。

@akabekobeko
Copy link
Member

<svg><math> だけでなく <a> タグも

<a href="sample.jpg">test</a>

にすると

├─3 paragraph[3]
    │   ├─0 html "<a href=\"sample.jpg\">"
    │   ├─1 text "test"
    │   └─2 html "</a>"

のように分解される。改行を入れたならば

<a href="sample.jpg">
test
</a>

以下のように単一 html になる。

├─3 html "<a href=\"sample.jpg\">\ntest\n</a>"

ただし <svg><math> は単一行、複数行のどちらにしても分解される。<table> はどちらでも単一 html になった。法則性が謎。

remark の issues を調べてもそれらしいものは見つけられなかった。改めて issue 登録することを検討する。

@akabekobeko
Copy link
Member

remark 側に issue 登録して修正されたとしても修正は最新の v9 系になると思われる。そのため v8 系を採用する VFM v1.0 として反映できない可能性あり。remark に期待せず VFM として対応するとしたら、あまりよい方法ではないけれど以下はどうか。

  1. unist-util-visithtml を検索して見つかったら次へ
  2. 内容となる HTML の開始と終了タグが不一致なら次へ
  3. parent.children を走査してゆき終了タグまでを Array へ収集
  4. parent.children で自身から終了タグまでを 3 から生成した単一 html に置き換える

この処理タイミングは remark-parse (v9 以降は remark-gfm も) の直後とする。以降は <table> のように単一 html 化されるため unist-util-visittext を回避できるはず。

「あまりよい方法ではない」理由は対処療法であるため。ここまでの調査結果で出力された MDAST に依存している。本来は remark 本家として対策ないしは仕様としてアナウンスされることが望ましい。

@akabekobeko
Copy link
Member

この現象のみを検証用するプロジェクトを用意した。最新の remark-parse v9 で検証。

v9 の場合、<svg><math> 以外は改行の有無に関わらず適切に単一 html となるようだ。しかしこれらのタグに関する問題は解決していないため、このプロジェクトを提示しつつ remark プロジェクトに issue を登録してみる予定。

@akabekobeko
Copy link
Member

remark プロジェクトの issue として報告してみた。

並行して前述の対処療法も実装する予定。

@akabekobeko
Copy link
Member

issue に返信があった。いわく

This behavior is the same as CommonMark (see it’s AST tab).

To treat “tags” as “blocks”, have only that tag on the line, which you have done with the case:

とのことで close された。本件の挙動は CommonMark と同様であり、ブロック (単一 html) にしたければそのタグのみを一行に記述する必要がある。しかし <table> は複数行、複数タグで構成されている。この点について更に質問してみるべきだろうか?

@akabekobeko
Copy link
Member

<table> タグと他との差について質問した。返答待ち。

ただ remark として本件の対応は望めなさそうなことは察せられたので

  1. 前述の対処療法を実装して VFM 側で対策する
  2. remark の見解を踏襲して VFM の仕様 (本件は未対応) とする

について検討する必要あり。1 で考えていたが CommonMark の挙動と乖離するのはどうか?という課題が生じた。

@akabekobeko
Copy link
Member

issue に返信あり。<table> などは CommonMark の仕様としてブロック扱いされる特別なタグで現行 remark のエンジンである micromark はそれに基づいて処理しているとのこと。

空白や改行に関する定義もなされており、特別なタグであってもそのルールでブロックにならないことも例示していただいた。

以上を踏まえると本件対応は VFM 既定ではなくオプションにするのがよさそう。ただし改行ではなくタグのブロック扱いに関するものなので --hard-line-breaks とは別に定義することとなるだろう。

2021/2/6 (土) に予定している開発者会議の議題に挙げてみる。

@akabekobeko
Copy link
Member

#4 の影響を検討する必要あり

@akabekobeko akabekobeko added this to the v1.0.0 milestone Apr 3, 2021
@akabekobeko
Copy link
Member

VFM v1.0 としては自動改行をオプション化することで明示的に有効化しない限り本件は発生しなくなりました。また前述のコメントどおり HTML タグ処理における CommonMark 仕様を踏襲しているため、自動改行が有効化された際に起きる本件の問題も当面は仕様とします。

改めて「自動改行有効 + <svg> などはそれを回避」を希望される場合は別途 issue 登録をお願いします。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants