控えめ-「裸」CでのオープンHTMLレンダリングエンジンの開発

みなさんこんにちは! 私の名前はAlexander Borisovです。Modestを開発しています。これは、外部依存関係を使用せずに「裸の」CでオープンHTMLレンダリングエンジン(以下、エンジン)を開発しています。 「外部依存関係なし」という意味を明確にしたいだけです。すべてのコードはゼロから作成され、コードはどこにも借用されません。



私の最後の出版以来かなりの時間が経ちました。 この間、多くのことが変わりました。開発の成果を皆さんと共有したいと思います。



プロジェクトについて



プロジェクトの主なアイデアは、その気取らないことです。



-Cがある任意のデバイスでコンパイル/インストールする機能

-作業速度

-最小の可能なリソース消費



この開発の最終製品の1つは、高速で軽量、フル機能のブラウザーです。



まず最初に



Cがある任意のデバイスでコンパイル/インストールする機能



Cはほぼすべての場所にあるため、どのハードウェアでもコンパイル/インストールできるというだけでなく、エンジンを別のプログラミング言語に接続して、この言語のエンジンAPIの全範囲を明らかにするという考え方もあります。 簡単に言えば、プログラミング言語のバインディングを簡単に作成できることです。



他の言語のバインディングは何を提供しますか?



エンジンのシンプルでわかりやすいAPIにより、JavaScriptを使用せずに、お気に入りのプログラミング言語を介してHTMLツリー、CSS、レンダーツリー/レイヤー(レンダーツリー/レイヤー)を直接操作できます。



実際には、これは次のことを意味します。



  1. 要素/レイヤーの高速アクセス、作成、変更。
  2. HTML / DOM Events / CSSのすべての機能を使用して、使い慣れたプログラミング言語でインターフェース、ゲーム、アプリケーションを簡単に作成できます。


さらに、私は先に進み、以下をテストしました
これは単なる実験であり、なぜ人生でそれほど必要ではないのかをすぐに予約しますが、それは可能です。



  1. Perl用の既製のバインディングを使用して変更する
  2. Perlタグタイプをスクリプトタグ処理に追加します:<script type = "Per">
  3. PerlでのHTMLの解析
  4. パーサーは、Perlタイプのスクリプトタグを検出すると、現在のインタープリターでこのコードを実行します




Perlスクリプトは次のようになりました。

use utf8; use strict; use warnings; use HTML::MyHTML::Fun; my $html = q~ <div> <span>text</span> </div> <script type="Perl"> # $MyHTML_TREE global var my $nodes = $MyHTML_TREE->get_elements_by_tag_name("span"); foreach my $node (@$nodes) { $node->delete($MyHTML_TREE); } </script> <span>footer</span> ~; # parse HTML my $myhtml = HTML::MyHTML->new(MyHTML_OPTIONS_DEFAULT, 1); my $tree = $myhtml->new_tree(); $myhtml->parse($tree, MyHTML_ENCODING_UTF_8, $html);
      
      





処理結果:



 <html> <head> <body> <div> <script type="Perl"> <-text>: ... <span> <-text>: footer
      
      







作業速度



待つのが好きな人はいません。特に私は。 重要な開発ポイントの1つは、HTML / CSS / Renderの特定の部分の高速処理を保証することです。 たとえば、一般的なhtmlページの平均処理時間は0.001秒、つまり1ミリ秒、つまり1秒あたり1000ページです。 ブートストラップCSSファイルとそのセレクターの解析には1.5msかかります。 現時点では、最速の本格的なHTMLおよびCSSパーサーがあります。 そして、これは制限ではありません。



最小限のリソース消費



作業の速度ですべてが多かれ少なかれ明確であれば、リソースの消費ですべてがはるかに複雑になります。 仕様は通常、すべてをメモリに保存するように「助言/要求」します。 より正確には、そうではなく、すべての推論は、すべてがすでに手元にあり、すべてが作成されているかのように進みます。



これは何に表れていますか?



たとえば、 CSS構文仕様を見てください。 彼女は、文字/文字のシーケンスごとにトークンを作成し、それらをグループに分類し、トークンのグループを作成する必要があると言っています。 率直に言って、トークン化の一般的な規則(デリムトークン)に含まれていない各シンボル、および「;」、「:」、「(」、「)」、「、」などのトークンを作成する必要があります、ルールの完全なリストはここで見ることができます



コンマまたはセミコロンごとにトークンを作成するのはかなり無駄な作業であることに同意します。 同時に、文字のトークン化のルールには次のような条件があることに注意する価値があります:現在の文字があること、次のHがXと等しいことを確認する、そうでなければYを作成する



後で、すべてのトークンが作成されたら、それらを分解する必要があります。 つまり、作成されたトークンのシーケンスからグループを選択します。 そして、CSSモジュールを使用するのはこれらのグループであり、 それだけでは不十分です。



ここからが楽しみです。 仕様に完全に準拠する必要がありますが、くしゃみごとにトークンを作成しないようにしてください。 多くの仕様を読み、「余分な」トークンを作成してメモリを節約しない方法について考えた結果、次の条件が形成されました。



1)CSS解析はチャンク、つまりストリーム解析をサポートする必要があります。 この仕様は必須ではありませんが、今後の開発には重要です。



データストリームがいつ終了するのかわからないのは、この条件のためです。 つまり、いつでも現在のキャラクターと前のキャラクターのみがいることが保証されていますが、次のキャラクターが何なのかわからないため、「キャラクターAが来たら、開き括弧があるかどうかを調べる」という条件で見ることはできません。



2)すべてのトークンを作成するのではなく、1つだけを作成します。将来的には常に書き換えられます。 どの時点でも、現在のトークンは1つだけです。 したがって、前のトークンも次のトークンも表示できません。それらは存在しません。 仕様には、「トークンXが来た場合、次の3つのトークンを参照し、それらがHでなければYである」などの多くの条件があるため、最初はこれが問題のように見えました。



上記のすべてがMyCSSに実装されています。 すでに、MyCSSはセレクターと一部のCSSプロパティを正常に解析し、最小限のメモリを消費しています。 したがって、メモリの「断片」を絶えず使用しないと、速度が大幅に向上します。



そして、上記のすべてに加えて、MyCSSパーサーは、そのためのモジュールのさらなる開発において明快さ、柔軟性、および容易さを保持しています。



ところで、MyHTMLでは、すべてがまったく逆に実装されています。 トークンの作成に重点が置かれ、トークンをさらに使用します。 これは、HTMLレンダラーを作成する場合など、「銀の弾丸」を使用できないことを明確に示しています。 どこでも個別のアプローチが必要です。 もちろん、仕様と仕様に必要なものを完全に理解しないと、これらすべてを作成することはできません。



現在のプロジェクト構造



現在、プロジェクトの次の部分が実装されています。



  1. MyHTML-HTMLパーサー
  2. MyCSS-CSSパーサー(セレクター、値、名前空間、プロパティ)
  3. MyFONTは、.otfおよび.fftファイルのパーサーです。 グリフのメトリックの取得:幅、高さ、ベースライン、x-heightなど。 ここで、ブラウザのように文字サイズについて話していることに注意してください。 例を参照してください


セレクターについて



セレクターについての別の記事を書く意味はありませんが、自慢したいです。 セレクターを使用して、ツリー内のノードを見つけることができます。



 div > :nth-child(2n+1):not(:has(a))
      
      





またはコンマ付きのリスト



 .header, :nth-child(2n+2 of div:not([id])) >> :not(:has(> [class ~= "bukabyaka" i]))
      
      





彼らは非常に高速に動作します。 上記の最初の例では、典型的なHabr記事のセレクターが0.00015秒、つまり0.15msで満たされ、247個の要素が見つかります。 現時点では、CSSの解析、セレクターの解析と作成、およびツリーの検索が含まれます。 事前にセレクターを作成して繰り返し使用すると、ランタイムが短縮されます。



現時点では、クアッドバージョンの仕様からのすべてのセレクター( セレクター4 )がサポートされていますが、次の例外があります。



  1. すべての擬似要素
  2. :dir ,: lang ,: scope、 "Time-dimensional Pseudo-classes" ,:ドロップ
  3. :n番目の列、:n番目の最後の列


1つ目と2つ目は、エンジンの開発に合わせて開発/追加されます。 サードパーティには届きませんでしたが、もちろん、近い将来にも実装されます。



今後のプロジェクト



それ(未来)は非常に明るいと見られています。 私は勤務時間中にプロジェクトに従事しています。 もちろん、私の雇用主は、プロジェクトにすべての作業時間を費やすことができました。



さて、レンダーツリー、レイヤーの作成を開始しました。 つまり、近い将来、幅、高さ、フォントサイズ、境界線の色など、計算されたhtmlノードメトリックを取得できるようになります。



たくさんのアイデアがありますが、私にはさらに「ガス」があります! ご清聴ありがとうございました!



PS:プロジェクトの実施を支援/参加したい人がいれば、 郵便局に安全に手紙を書くことができます。



参照:



» 控えめ

» 控えめな例

» MyHTMLの例

» MyCSSの例

»PerlのMyHTMLバインディング



All Articles