{"id":400279,"date":"2024-06-29T15:09:42","date_gmt":"2024-06-29T15:09:42","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=400279"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=400279","title":{"rendered":"<span>\u041f\u0438\u0448\u0435\u043c \u0444\u043e\u0440\u043a Chrome, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/be\/7c\/vj\/be7cvjcanhv2iu49hamo1hu7wza.png\" data-src=\"https:\/\/habrastorage.org\/webt\/be\/7c\/vj\/be7cvjcanhv2iu49hamo1hu7wza.png\"\/><\/div>\n<p>  \u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434 \u044f \u043f\u0438\u0441\u0430\u043b \u043e <a href=\"https:\/\/fathy.fr\/html2svg\">\u0444\u043e\u0440\u043a\u0435 Chrome, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0435\u043c HTML \u0432 SVG<\/a>, \u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0445\u043e\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435\u0435, \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0432 \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b.<\/p>\n<p>  \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e <a href=\"https:\/\/github.com\/fathyb\/carbonyl\">\u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440 Carbonyl<\/a>!<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h2>\u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430<\/h2>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/qr\/cn\/xr\/qrcnxrtgsnoukwryf7f5wt7tpze.png\" data-src=\"https:\/\/habrastorage.org\/webt\/qr\/cn\/xr\/qrcnxrtgsnoukwryf7f5wt7tpze.png\"\/><\/div>\n<p>  <i>\u0422\u0435\u0440\u043c\u0438\u043d\u0430\u043b DEC VT100<\/i><\/p>\n<p>  \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u044b: \u0432\u0430\u043c \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u043b\u0438\u0448\u044c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043c\u043e\u043d\u043e\u0448\u0438\u0440\u0438\u043d\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u0432 \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u043e\u0439 \u0441\u0435\u0442\u043a\u0435, \u0438 \u043d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0451. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 escape-\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c \u043a\u0443\u0440\u0441\u043e\u0440, \u043c\u0435\u043d\u044f\u0442\u044c \u0446\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u043b\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043c\u044b\u0448\u044c. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0441\u044c \u0441 \u0434\u043d\u0435\u0439 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u043e\u0432 \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 DEC VT100, \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0437\u044f\u0442\u044b \u0438\u0437 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 xterm.<\/p>\n<p>  \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u0430\u043a\u043e\u0433\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430, \u043c\u044b \u043c\u043e\u0436\u0435\u043c:<\/p>\n<ul>\n<li>\u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c \u043a\u0443\u0440\u0441\u043e\u0440<\/li>\n<li>\u0417\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c \u0441\u0438\u043c\u0432\u043e\u043b\u044b Unicode<\/li>\n<li>\u0417\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0439 \u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0446\u0432\u0435\u0442 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/li>\n<li>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c RGB-\u043f\u0430\u043b\u0438\u0442\u0440\u0443 6x6x6 \u0438\u043b\u0438 24-\u0431\u0438\u0442\u043d\u0443\u044e RGB-\u043f\u0430\u043b\u0438\u0442\u0440\u0443, \u0435\u0441\u043b\u0438 <code>COLORTERM<\/code> \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>truecolor<\/code><\/li>\n<\/ul>\n<p>  \u041e\u0434\u0438\u043d \u0438\u0437 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 Unicode, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u2014 \u044d\u0442\u043e \u043d\u0438\u0436\u043d\u0438\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u043d\u044b\u0439 \u0431\u043b\u043e\u043a <code>U+2584<\/code>: <code>\u2584<\/code>. \u0417\u043d\u0430\u044f, \u0447\u0442\u043e \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044f\u0447\u0435\u0439\u043a\u0438 \u0438\u043c\u0435\u044e\u0442 \u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d 1:2, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0438\u0434\u0435\u0430\u043b\u044c\u043d\u043e \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u043d\u044b\u0435 \u043f\u0438\u043a\u0441\u0435\u043b\u0438, \u0437\u0430\u0434\u0430\u0432 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0444\u043e\u043d\u043e\u0432\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u0446\u0432\u0435\u0442 \u0432\u0435\u0440\u0445\u043d\u0435\u0433\u043e \u043f\u0438\u043a\u0441\u0435\u043b\u044f, \u0430 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430 \u2014 \u0446\u0432\u0435\u0442 \u043d\u0438\u0436\u043d\u0435\u0433\u043e \u043f\u0438\u043a\u0441\u0435\u043b\u044f.<\/p>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u043c \u0432\u044b\u0432\u043e\u0434 <code>html2svg<\/code> \u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435 \u043d\u0430 Rust:<\/p>\n<pre><code class=\"rust\">fn move_cursor((x, y): (usize, usize)) {     println!(\"\\x1b[{};{}H\", y + 1, x + 1) }  fn set_foreground((r, g, b): (u8, u8, u8)) {     println!(\"\\x1b[38;2;{};{};{}m\", r, g, b) }  fn set_background((r, g, b): (u8, u8, u8)) {     println!(\"\\x1b[48;2;{};{};{}m\", r, g, b) }  fn print_pixels_pair(     top: (u8, u8, u8),     bottom: (u8, u8, u8),     cursor: (usize, usize) ) {     move_cursor(cursor);     set_background(top);     set_foreground(bottom);     println!(\"\u2584\"); }<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/t2\/bb\/ad\/t2bbad5aikgqu5ty68k5xowvak4.png\" alt=\"image\" data-src=\"https:\/\/habrastorage.org\/webt\/t2\/bb\/ad\/t2bbad5aikgqu5ty68k5xowvak4.png\"\/><\/div>\n<p>  \u041d\u0435\u043f\u043b\u043e\u0445\u043e. \u0414\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 C++ \u043d\u043e\u0432\u043e\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e Skia. \u041d\u0430\u0437\u043e\u0432\u0451\u043c \u0435\u0433\u043e <code>TextCaptureDevice<\/code>. \u041c\u044b \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u043c \u0435\u0433\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u0443\u044e \u043d\u0430 Rust \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>draw_text<\/code>. \u041a\u0430\u043a \u0438 \u0432 <code>html2svg<\/code>, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u044b\u0432\u0430\u0442\u044c ID \u0433\u043b\u0438\u0444\u043e\u0432 \u0432 \u0441\u0438\u043c\u0432\u043e\u043b\u044b Unicode.<\/p>\n<pre><code class=\"cpp\">class TextCaptureDevice: public SkClipStackDevice {   void onDrawGlyphRunList(SkCanvas*,                           const sktext::GlyphRunList&amp; glyphRunList,                           const SkPaint&amp;,                           const SkPaint&amp; paint) override {     \/\/ \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u0442\u0435\u043a\u0441\u0442\u0430     auto position = localToDevice().mapRect(glyphRunList.origin());      for (auto&amp; glyphRun : glyphRunList) {       auto runSize = glyphRun.runSize();       SkAutoSTArray&lt;64, SkUnichar> unichars(runSize);        \/\/ \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c ID \u0433\u043b\u0438\u0444\u043e\u0432 \u0432 \u0441\u0438\u043c\u0432\u043e\u043b\u044b Unicode       SkFontPriv::GlyphsToUnichars(glyphRun.font(),                                   glyphRun.glyphsIDs().data(),                                   runSize,                                   unichars.get());        \/\/ \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u043c \u044d\u0442\u043e\u0442 \u0442\u0435\u043a\u0441\u0442 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435       draw_text(unichars.data(), runSize, position, paint.getColor());     }   } }<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/go\/y2\/g6\/goy2g60kuvz6fs_2fm9hlroqb7w.png\" alt=\"image\" data-src=\"https:\/\/habrastorage.org\/webt\/go\/y2\/g6\/goy2g60kuvz6fs_2fm9hlroqb7w.png\"\/><\/div>\n<p>  \u0415\u0449\u0451 \u043b\u0443\u0447\u0448\u0435! \u041e\u0434\u043d\u0430\u043a\u043e \u0432 \u0446\u0435\u043d\u0442\u0440\u0435 \u0442\u0435\u043a\u0441\u0442 \u0438\u0441\u043a\u0430\u0436\u0451\u043d. \u041d\u0430\u0448 <code>TextCaptureDevice<\/code> \u043d\u0435 \u0443\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u043d\u0435 \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u0434 \u043d\u0438\u043c.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/0z\/qd\/uk\/0zqduk1ha0szkhw8k-xd6hmjime.png\" alt=\"image\" data-src=\"https:\/\/habrastorage.org\/webt\/0z\/qd\/uk\/0zqduk1ha0szkhw8k-xd6hmjime.png\"\/><\/div>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u0434 \u0432 \u043c\u0435\u0442\u043e\u0434\u044b <code>drawRect<\/code> \u0438 <code>drawRRect<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u0447\u0438\u0449\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442, \u0435\u0441\u043b\u0438 \u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0437\u0430\u043b\u0438\u0432\u043a\u0443 \u0441\u043f\u043b\u043e\u0448\u043d\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c:<\/p>\n<pre><code class=\"cpp\">void drawRRect(const SkRRect&amp; rect, const SkPaint&amp; paint) override {     drawRect(rect.rect(), paint); }  void drawRect(const SkRect&amp; rect, const SkPaint&amp; paint) override {     if (         paint.getStyle() == SkPaint::Style::kFill_Style &amp;&amp;         paint.getAlphaf() == 1.0     ) {         clear_text(localToDevice().mapRect(rect));     } }<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/2v\/x4\/gl\/2vx4gl2e7fxrbfgjbl8x1d6lnmi.png\" alt=\"image\" data-src=\"https:\/\/habrastorage.org\/webt\/2v\/x4\/gl\/2vx4gl2e7fxrbfgjbl8x1d6lnmi.png\"\/><\/div>\n<p>  \u0421\u0435\u0440\u044b\u0439 \u0444\u043e\u043d \u043f\u043e\u0434 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0439 \u0440\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0442\u043e\u0440 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442 \u0442\u0435\u043a\u0441\u0442 \u0432 \u043d\u0430\u0448\u0435 \u0431\u0438\u0442\u043e\u0432\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0443\u0434\u0430\u043b\u0438\u043c \u0435\u0433\u043e:<\/p>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:third_party\/skia\/src\/core\/SkBitmapDevice.cpp;l=521-527;drc=7a9783136c9dc4ff2b188aac722e75eabb7bf287\">chromium\/third_party\/skia\/src\/core\/SkBitmapDevice.cpp, \u0441\u0442\u0440\u043e\u043a\u0430 521<\/a><\/p>\n<pre><code class=\"cpp\">void SkBitmapDevice::onDrawGlyphRunList(SkCanvas* canvas,                                         const sktext::GlyphRunList&amp; glyphRunList,                                         const SkPaint&amp; initialPaint,                                         const SkPaint&amp; drawingPaint) { \/\/    SkASSERT(!glyphRunList.hasRSXForm()); \/\/    LOOP_TILER( drawGlyphRunList(canvas, &amp;fGlyphPainter, glyphRunList, drawingPaint), nullptr ) }<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/id\/wv\/m0\/idwvm0gnxepbfhosso6czbxwqka.png\" alt=\"image\" data-src=\"https:\/\/habrastorage.org\/webt\/id\/wv\/m0\/idwvm0gnxepbfhosso6czbxwqka.png\"\/><\/div>\n<p>  \u042d\u0442\u043e \u0431\u044b\u043b\u043e \u0441\u0430\u043c\u043e\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0435. \u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0432\u0432\u043e\u0434!<\/p>\n<h2>\u0412\u0432\u043e\u0434<\/h2>\n<p>  \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440\u0443 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0438 \u0441\u043e\u043e\u0431\u0449\u0430\u0442\u044c \u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u0445 \u043c\u044b\u0448\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u0432\u0432\u0435\u0441\u0442\u0438 <code>\\x1b[?1003h<\/code>, \u0442\u043e \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0447\u0430\u0442\u044c \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435:<\/p>\n<pre><code class=\"rust\">fn report_mouse_move((x, y): (usize, usize)) {     write!(get_stdin(), \"\\x1b[&lt;35;{};{}M\", y + 1, x + 1) } fn report_mouse_down((x, y): (usize, usize)) {     write!(get_stdin(), \"\\x1b[&lt;0;{};{}M\", y + 1, x + 1) } fn report_mouse_up((x, y): (usize, usize)) {     write!(get_stdin(), \"\\x1b[&lt;0;{};{}m\", y + 1, x + 1) }<\/code><\/pre>\n<p>  \u041e\u043d\u0438 \u0441\u0445\u043e\u0436\u0438 \u0441 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044f\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0441\u0442\u0438\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432\u044b\u0432\u043e\u0434\u0430. \u041f\u0440\u0435\u0444\u0438\u043a\u0441 <code>\\x1b[<\/code> \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f Control Sequence Introducer.<\/p>\n<pre><code class=\"cpp\">carbonyl::browser->BrowserMainThread()->PostTask(     FROM_HERE,     base::BindOnce(         &amp;HeadlessBrowserImpl::OnMouseDownInput,         x,         y     ) );<\/code><\/pre>\n<p>  \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0442\u044c \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u043d\u043e \u0435\u0441\u0442\u044c \u043e\u0434\u043d\u0430 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u044c: \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0440\u0435\u0442\u0438\u0442\u044c \u043f\u043e\u0442\u043e\u043a\u0443 \u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c stdin, \u043e\u0434\u043d\u0430\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u044b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u0437 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0442\u043e\u043a\u0430. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u043f\u043e\u0447\u0442\u0438 \u0432\u0435\u0437\u0434\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:base\/task\/task_runner.h;drc=63e1f9974bc57b0ca12d790b2a73e5ba7f5cec6e;l=60\"><code>TaskRunner<\/code><\/a>.<\/p>\n<p>  <a href=\"https:\/\/github.com\/fathyb\/carbonyl\/blob\/5d0807e35b893963953791a1878fbe08de81a3ce\/src\/input\/parser.rs#L69-L96\">carbonyl\/src\/input\/parser.rs, \u0441\u0442\u0440\u043e\u043a\u0430 69<\/a><\/p>\n<pre><code class=\"cpp\">for &amp;key in input {     sequence = match sequence {         Sequence::Char => match key {             0x1b => Sequence::Escape,             0x03 => emit!(Event::Exit),             key => emit!(Event::KeyPress { key }),         },         Sequence::Escape => match key {             b'[' => Sequence::Control,             b'P' => Sequence::DeviceControl(DeviceControl::new()),             0x1b =>                 emit!(Event::KeyPress { key: 0x1b }; continue),             key => {                 emit!(Event::KeyPress { key: 0x1b });                 emit!(Event::KeyPress { key })             }         },         Sequence::Control => match key {             b'&lt;' => Sequence::Mouse(Mouse::new()),             b'A' => emit!(Event::KeyPress { key: 0x26 }),             b'B' => emit!(Event::KeyPress { key: 0x28 }),             b'C' => emit!(Event::KeyPress { key: 0x27 }),             b'D' => emit!(Event::KeyPress { key: 0x25 }),             _ => Sequence::Char,         },         Sequence::Mouse(ref mut mouse) => parse!(mouse, key),         Sequence::DeviceControl(ref mut dcs) => parse!(dcs, key),     } }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/63fc46ce9f1c6be050bf583d\" data-style=\"\" id=\"63fc46ce9f1c6be050bf583d\" width=\"\"><\/div>\n<\/div>\n<p><i>Google \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u043c\u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Chrome<\/i><\/p>\n<h2>Pipe<\/h2>\n<p>  \u041d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u043e\u043b\u0435\u0435-\u043c\u0435\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u0446\u0435\u043d\u043e\u0439 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f CPU \u043d\u0430 400%, \u0438 \u044d\u0442\u043e \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u044f iTerm2, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 200%. \u0423 \u043d\u0430\u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c:<\/p>\n<ul>\n<li>\u0414\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0432 5 FPS \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432<\/li>\n<li>\u041c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u0430\u0434\u0440\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f<\/li>\n<li>\u041c\u044b \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0432\u0441\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0430 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435<\/li>\n<\/ul>\n<p>  \u0414\u043b\u044f \u043f\u043e\u0432\u044b\u0448\u0435\u043d\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u0430\u044f \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430. \u041e\u043d\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0435\u0442 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u044b \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b, \u0441\u043d\u0438\u0436\u0430\u044f \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0443\u0449\u0435\u0440\u0431, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u0439 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438. \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0441\u0440\u0435\u0434\u0435 \u043f\u0435\u0441\u043e\u0447\u043d\u0438\u0446\u044b \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u041e\u0421, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u0435. \u0421\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 GPU \u0442\u043e\u0436\u0435 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0439 \u0438 \u043e\u043d \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0430; \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0434\u043b\u044f \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 \u0432 GPU API \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435 WebGL. \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432, \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u043b\u044e\u0431\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/j3\/dy\/4s\/j3dy4so8a0-psafpwqjctxd0vie.png\" data-src=\"https:\/\/habrastorage.org\/webt\/j3\/dy\/4s\/j3dy4so8a0-psafpwqjctxd0vie.png\"\/><\/div>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:third_party\/blink\/public\/web\/web_local_frame.h;drc=e95ee489e7a4aee5408d8bb0e13bebc61adcca0d;l=786\"><code>CapturePaintPreview<\/code><\/a> \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0434\u043b\u044f <code>html2svg<\/code>, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0414\u043b\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0439 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 iframe \u0432\u043d\u0435 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0432\u044b\u0437\u043e\u0432\u044b IPC, \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u044f \u043c\u0430\u0440\u0448\u0440\u0443\u0442 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, GPU \u0438 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0430. \u041e\u043d \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u044b\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0437 GPU, \u0447\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0443 \u043d\u0430 \u043f\u043e\u043b\u043e\u0441\u0443 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u043d\u0438\u044f \u043f\u0430\u043c\u044f\u0442\u0438. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0443 \u0438 \u0434\u0430\u0436\u0435 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0430\u043f\u043f\u0430\u0440\u0430\u0442\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0430\u0441 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0431\u0443\u0434\u0443\u0442 \u0441\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0437\u0430\u0442\u0440\u0430\u0442\u043d\u044b\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u044b IPC.<\/p>\n<p>  \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0430\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f; \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0435 \u0432\u0435\u0440\u0438\u0442\u044c, \u043d\u043e \u0440\u0430\u043d\u044c\u0448\u0435 \u043e\u043d \u0434\u0430\u0436\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u043b\u0441\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0412\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0430 \u043e\u0434\u043d\u043e\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u043e\u0441\u0442\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 \u043d\u0438\u043c \u0431\u044b\u043b\u043e \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e, \u043e\u0434\u043d\u0430\u043a\u043e \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u043e\u0431\u0449\u0438\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0430\u043c\u044f\u0442\u0438 \u0441\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u043e\u0434 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432. \u0415\u0441\u043b\u0438 \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0437\u0430\u0441\u0443\u043d\u0443\u0442\u044c \u043d\u0430\u0448\u0438 \u043f\u0438\u043a\u0441\u0435\u043b\u0438 \u0432 \u043e\u0434\u043d\u0443 \u0438\u0437 \u044d\u0442\u0438\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u043f\u0430\u043c\u044f\u0442\u0438, \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f IPC.<\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/gz\/9d\/q6\/gz9dq6xp7bgyppfnfk_zju4bcui.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/gz\/9d\/q6\/gz9dq6xp7bgyppfnfk_zju4bcui.gif\"\/><\/div>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u044d\u0442\u0443 \u043e\u0431\u0449\u0443\u044e \u043f\u0430\u043c\u044f\u0442\u044c, \u043d\u0443\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:components\/viz\/host\/host_display_client.h;drc=c8b537923f4fdbdf492a1e475b0f2bff0340a32b;l=25\"><code>HostDisplayClient<\/code><\/a> \u0438 <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:components\/viz\/service\/display\/software_output_device.h;drc=12be03159fe22cd4ef291e9561762531c2589539;l=33\"><code>SoftwareOutputDevice<\/code><\/a> \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:services\/viz\/privileged\/mojom\/compositing\/layered_window_updater.mojom;drc=098756533733ea50b2dcb1c40d9a9e18d49febbe;l=13\"><code>LayeredWindowUpdater<\/code><\/a>, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u043c <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:services\/viz\/privileged\/mojom\/compositing\/layered_window_updater.mojom;drc=098756533733ea50b2dcb1c40d9a9e18d49febbe;l=21\"><code>OnAllocatedSharedMemory()<\/code><\/a>.<\/p>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:components\/viz\/host\/host_display_client.h;drc=c8b537923f4fdbdf492a1e475b0f2bff0340a32b;l=25\"><code>HostDisplayClient<\/code><\/a> \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c GPU \u0447\u0435\u0440\u0435\u0437 IPC. \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c \u0441\u043e \u0432\u0441\u0435\u043c \u044d\u0442\u0438\u043c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 GPU \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u0438\u0441\u043f\u043b\u0435\u044f, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:content\/browser\/compositor\/viz_process_transport_factory.cc;l=351;drc=c8b537923f4fdbdf492a1e475b0f2bff0340a32b?q=VizProcessTransportFactory::OnEstablishedGpuChannel&amp;amp;sq=&amp;amp;ss=chromium%2Fchromium%2Fsrc\"><code>VizProcessTransportFactory::OnEstablishedGpuChannel()<\/code><\/a> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:content\/browser\/compositor\/viz_process_transport_factory.cc;l=402-403;drc=c8b537923f4fdbdf492a1e475b0f2bff0340a32b\">chromium\/content\/browser\/compositor\/viz_process_transport_factory.cc, \u0441\u0442\u0440\u043e\u043a\u0430 402<\/a><\/p>\n<pre><code class=\"cpp\">compositor_data.display_client = \/\/      std::make_unique&lt;HostDisplayClient>(compositor);       std::make_unique&lt;carbonyl::HostDisplayClient>();<\/code><\/pre>\n<p>  <a href=\"https:\/\/github.com\/fathyb\/carbonyl\/blob\/5d0807e35b893963953791a1878fbe08de81a3ce\/src\/browser\/host_display_client.cc#L28-L44\">carbonyl\/src\/browser\/host_display_client.cc, \u0441\u0442\u0440\u043e\u043a\u0430 28<\/a><\/p>\n<pre><code class=\"cpp\">void LayeredWindowUpdater::OnAllocatedSharedMemory(     const gfx::Size&amp; pixel_size,     base::UnsafeSharedMemoryRegion region ) {     if (region.IsValid())         shm_mapping_ = region.Map(); }  void LayeredWindowUpdater::Draw(     const gfx::Rect&amp; damage_rect,     DrawCallback draw_callback ) {     carbonyl_draw_bitmap(         shm_mapping_.GetMemoryAs&lt;uint8_t>(),         shm_mapping_.size()     );      std::move(draw_callback).Run(); }<\/code><\/pre>\n<p>  \u041c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0441 \u0431\u0438\u0442\u043e\u0432\u044b\u043c\u0438 \u043a\u0430\u0440\u0442\u0430\u043c\u0438, \u043d\u043e \u043a\u0430\u043a \u043d\u0430\u043c \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435? \u042d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0430, \u043e\u0434\u043d\u0430\u043a\u043e \u043d\u0430\u0448 \u043a\u043e\u0434 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0441 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.<\/p>\n<h2>Mojo<\/h2>\n<p>  Mojo \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u043e\u0431\u043c\u0435\u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438. \u041e\u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 IDL \u0434\u043b\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0439 \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u0435\u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0440\u044b \u0444\u0430\u0439\u043b\u043e\u0432, \u043e\u0431\u0449\u0438\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0430\u043c\u044f\u0442\u0438, \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0435 \u0432\u044b\u0437\u043e\u0432\u044b), \u0438 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u043e\u043a C++, Java (Android) \u0438 JavaScript (DevTools). \u041e\u043d\u0430 \u0438\u043c\u0435\u0435\u0442 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430 \u0432 \u0440\u0430\u0431\u043e\u0442\u0435.<\/p>\n<p>  \u041c\u044b \u043d\u0430\u0447\u043d\u0451\u043c \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 <code>CarbonylRenderService<\/code>, \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0433\u043e \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430, \u0441 \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>DrawText<\/code>, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u044b\u043c \u0438\u0437 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0430.<\/p>\n<p>  <a href=\"https:\/\/github.com\/fathyb\/carbonyl\/blob\/5d0807e35b893963953791a1878fbe08de81a3ce\/src\/browser\/carbonyl.mojom#L1\">carbonyl\/src\/browser\/carbonyl.mojom<\/a><\/p>\n<pre><code class=\"cpp\">\/\/ \u041d\u0430\u0448\u0438 \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 C++ \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0438\u043c\u0451\u043d carbonyl::mojom module carbonyl.mojom;  \/\/ \u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u043f\u0440\u0438\u0432\u044f\u0437\u043a\u0438 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b import \"ui\/gfx\/geometry\/mojom\/geometry.mojom\"; import \"skia\/public\/mojom\/skcolor.mojom\";  \/\/ \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 struct TextData {     \/\/ \u0421\u0442\u0440\u043e\u043a\u0430 UTF-8 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c     string contents;     \/\/ \u0413\u0440\u0430\u043d\u0438\u0446\u044b, \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438     gfx.mojom.RectF bounds;     \/\/ \u0426\u0432\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u0430     skia.mojom.SkColor color; };  \/\/ \u042d\u0442\u043e\u0442 \u0441\u0435\u0440\u0432\u0438\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 interface CarbonylRenderService {     \/\/ \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0430     DrawText(array&lt;TextData> data); };<\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 <code>.mojom<\/code> \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b C++, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0430\u0442\u0435\u043b\u0438 Mojo, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430\u0448 \u0441\u0435\u0440\u0432\u0438\u0441, \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430\u043c\u0438; \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0451 \u0432 <code>BrowserInterfaceBroker<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u043e\u043c \u0447\u0435\u0440\u0435\u0437 <code>BrowserInterfaceBrokerProxy<\/code>:<\/p>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:content\/browser\/browser_interface_binders.cc;l=890;drc=c8b537923f4fdbdf492a1e475b0f2bff0340a32b\">chromium\/content\/browser\/browser_interface_binders.cc, \u0441\u0442\u0440\u043e\u043a\u0430 890<\/a><\/p>\n<pre><code class=\"cpp\">map->Add&lt;carbonyl::mojom::CarbonylRenderService>(     base::BindRepeating(&amp;RenderFrameHostImpl::GetCarbonylRenderService,                         base::Unretained(host)));<\/code><\/pre>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:content\/renderer\/render_frame_impl.cc;l=2206;drc=c8b537923f4fdbdf492a1e475b0f2bff0340a32b\">chromium\/content\/renderer\/render_frame_impl.cc, \u0441\u0442\u0440\u043e\u043a\u0430 2206<\/a><\/p>\n<pre><code class=\"cpp\">GetBrowserInterfaceBroker().GetInterface(   std::move(carbonyl_render_service_receiver_) );<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0431\u0435\u0437 \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0437\u0430\u0442\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u043c\u0430\u0440\u0448\u0440\u0443\u0442\u0430. \u0423 Blink \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>GetPaintRecord()<\/code>, \u043f\u043e\u043b\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043d\u043e \u043e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0435 \u0437\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u043c API, \u0430 \u044d\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430\u0448 \u043a\u043e\u0434 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u0440\u0435\u043d\u0434\u0435\u0440\u0435\u0440\u0435 \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430. \u0412 \u0438\u0434\u0435\u0430\u043b\u0435 \u043d\u0430\u043c \u0431\u044b \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0435\u0433\u043e \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u043e\u0432\u0449\u0438\u043a\u0443 (<code>cc<\/code>), \u043d\u043e \u044d\u0442\u043e \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0441\u043b\u043e\u0436\u043d\u0435\u0435. \u0411\u044b\u0441\u0442\u0440\u043e\u0435 \u0438 \u0433\u0440\u044f\u0437\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u044d\u0442\u043e \u043a \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u043c\u0443 <code>blink::WebViewImpl<\/code>:<\/p>\n<pre><code class=\"cpp\">auto* view = static_cast&lt;blink::WebViewImpl*>(GetWebFrame()->View());  view->MainFrameImpl()->GetFrame()->View()->GetPaintRecord().Playback(&amp;canvas); carbonyl_render_service_->DrawText(std::move(data));<\/code><\/pre>\n<p>  \u0421\u044e\u0440\u043f\u0440\u0438\u0437 \u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430: \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043d\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0437\u0430 \u0431\u0438\u0442\u043e\u0432\u043e\u0439 \u043a\u0430\u0440\u0442\u043e\u0439. \u0410, \u043f\u043e\u043d\u044f\u0442\u043d\u043e: \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u043d\u0433 \u0438 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043f\u043e\u0442\u043e\u043a\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u043e\u0432\u0449\u0438\u043a\u0430, \u0447\u0442\u043e \u043e\u0441\u0432\u043e\u0431\u043e\u0436\u0434\u0430\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043f\u043e\u0442\u043e\u043a \u0438 \u0443\u043f\u0440\u043e\u0449\u0430\u0435\u0442 \u0432\u0441\u0451. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u043a\u0440\u0430\u0441\u0442\u0438\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 <code>--disable-threaded-scrolling<\/code> <code>--disable-threaded-animation<\/code>.<\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/63fc622461f0ac6fb269f22f\" data-style=\"\" id=\"63fc622461f0ac6fb269f22f\" width=\"\"><\/div>\n<\/div>\n<p><i>\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u0438\u043d\u0433 \u0432\u043a\u043b\u044e\u0447\u0435\u043d<\/i><\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/63fc62249f1c6be050bf69af\" data-style=\"\" id=\"63fc62249f1c6be050bf69af\" width=\"\"><\/div>\n<\/div>\n<p><i>\u041f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u0438\u043d\u0433 \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d<\/i><\/p>\n<p>  \u0412\u0441\u0451 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043b\u0430\u0432\u043d\u043e, \u0438 \u0431\u0443\u0434\u0435\u0442 \u0435\u0449\u0451 \u043f\u043b\u0430\u0432\u043d\u0435\u0435, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u043f\u043e\u0447\u0438\u043d\u0438\u043c \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u0437\u0438\u0442\u0438\u043d\u0433! \u0418 \u043c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043d\u0430\u0448\u0443 \u0441\u0430\u043c\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443: \u043f\u0440\u0438 \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u043c\u044b \u043d\u0435 \u0442\u0440\u0430\u0442\u0438\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u044b CPU, \u0430 \u0441\u043a\u0440\u043e\u043b\u043b\u0438\u043d\u0433 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e 15%.<\/p>\n<h2>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446<\/h2>\n<p>  \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0438\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0448\u0440\u0438\u0444\u0442\u0430, \u043d\u043e Blink \u044d\u0442\u043e\u0433\u043e \u043d\u0435 \u0437\u043d\u0430\u0435\u0442. \u0418\u0437-\u0437\u0430 \u044d\u0442\u043e\u0433\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043a\u0430\u0436\u0430\u0442\u044c\u0441\u044f, \u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0431\u043b\u043e\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430 \u0438\u043b\u0438 \u0438\u043c\u0435\u0442\u044c \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u044f. \u041e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u0437\u0430\u043c\u0435\u0442\u043d\u043e \u044d\u0442\u043e \u043d\u0430 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u0430\u0445 \u0441 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u0438 \u0441\u0441\u044b\u043b\u043e\u043a, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0412\u0438\u043a\u0438\u043f\u0435\u0434\u0438\u0438.<\/p>\n<p>  \u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0433\u0440\u044f\u0437\u043d\u044b\u0439 (\u043d\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0439) \u0442\u0440\u044e\u043a \u2014 \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043c\u043e\u043d\u043e\u0448\u0438\u0440\u0438\u043d\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u043a\u043e\u0434 \u0432 <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:third_party\/blink\/renderer\/core\/css\/resolver\/style_resolver.cc;l=954;drc=a67b5c344bfa8645cb2f66685e010b425ac19ea1\"><code>StyleResolver::ResolveStyle<\/code><\/a>.<\/p>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:third_party\/blink\/renderer\/core\/css\/resolver\/style_resolver.cc;l=954;drc=a67b5c344bfa8645cb2f66685e010b425ac19ea1\">chromium\/third_party\/blink\/renderer\/core\/css\/resolver\/style_resolver.cc, \u0441\u0442\u0440\u043e\u043a\u0430 954<\/a><\/p>\n<pre><code class=\"cpp\">auto font = state.StyleBuilder().GetFontDescription();  font.SetStretch(ExtraExpandedWidthValue()); font.SetKerning(FontDescription::kNoneKerning); font.SetComputedSize(11.75 \/ 7.0); font.SetGenericFamily(FontDescription::kMonospaceFamily); font.SetIsAbsoluteSize(true); state.StyleBuilder().SetFontDescription(font); state.StyleBuilder().SetLineHeight(Length::Fixed(14.0 \/ 7.0));<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/rs\/-r\/xu\/rs-rxuxwwt-yckhenkrbidymloa.png\" data-src=\"https:\/\/habrastorage.org\/webt\/rs\/-r\/xu\/rs-rxuxwwt-yckhenkrbidymloa.png\"\/><\/div>\n<p>  <i>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b<\/i><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/be\/7c\/vj\/be7cvjcanhv2iu49hamo1hu7wza.png\" data-src=\"https:\/\/habrastorage.org\/webt\/be\/7c\/vj\/be7cvjcanhv2iu49hamo1hu7wza.png\"\/><\/div>\n<p>  <i>\u0418\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430<\/i><\/p>\n<h2>LoDPI<\/h2>\n<p>  \u0417\u0430\u0442\u0440\u0430\u0442\u043d\u044b\u043c \u044d\u0442\u0430\u043f\u043e\u043c \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043e\u043d\u0432\u0435\u0439\u0435\u0440\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0434\u0430\u0443\u043d\u0441\u043a\u0435\u0439\u043b\u0438\u043d\u0433: \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0443\u0444\u0435\u0440\u0430 \u043a\u0430\u0434\u0440\u043e\u0432 \u0441 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0430 \u043d\u0430 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0435. \u0422\u043e, \u0447\u0442\u043e \u043c\u044b \u0434\u0435\u043b\u0430\u0435\u043c, \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0443 HiDPI, \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e 2, \u0442\u043e \u0435\u0441\u0442\u044c 1 \u043f\u0438\u043a\u0441\u0435\u043b\u044c \u0432 \u0432\u0435\u0431\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u0435\u043d 4 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u043c \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435. \u041d\u0430\u0448\u0435 \u0441\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0440\u0430\u0432\u043d\u043e <code>1 \/ 7<\/code>, \u0442\u043e \u0435\u0441\u0442\u044c 49 \u043f\u0438\u043a\u0441\u0435\u043b\u0435\u0439 \u0432 \u0432\u0435\u0431\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u0432 1 \u0431\u043b\u043e\u043a \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430.<\/p>\n<p>  HiDPI \u0440\u0430\u0437\u0434\u0440\u0430\u0436\u0430\u0435\u0442 \u0442\u0435\u043c, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 4 \u0440\u0430\u0437\u0430 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a Carbonyl LoDPI\u00ae \u0443\u0441\u043a\u043e\u0440\u044f\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 49 \u0440\u0430\u0437. \u041d\u0430\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0441\u0443\u043d\u0443\u0442\u044c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043a\u043b\u0430\u0441\u0441 <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:ui\/display\/display.h;drc=8d3b4cc374e70dcfef858a355ac13e75d08c4f67;l=31\"><code>Display<\/code><\/a>.<\/p>\n<p>  <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:ui\/display\/display.cc;l=77-89;drc=63e1f9974bc57b0ca12d790b2a73e5ba7f5cec6e\">chromium\/ui\/display\/display.cc, \u0441\u0442\u0440\u043e\u043a\u0430 77<\/a><\/p>\n<pre><code class=\"cpp\">\/\/ static float Display::GetForcedDeviceScaleFactor() {     return 1.0 \/ 7.0; }  \/\/ static bool Display::HasForceDeviceScaleFactor() {     return true; }<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0426\u0432\u0435\u0442<\/h2>\n<p>  \u042f \u043f\u043e\u0438\u0441\u043a\u0430\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0446\u0432\u0435\u0442\u043e\u0432 RGB \u0432 <code>xterm-256<\/code>, \u043d\u043e \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0439 \u043c\u043d\u043e\u0439 \u043a\u043e\u0434 \u0431\u044b\u043b \u043e\u0448\u0438\u0431\u043e\u0447\u043d\u044b\u043c \u0438\u043b\u0438 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b \u043f\u043e\u0438\u0441\u043a \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0445 \u0441\u043e\u0441\u0435\u0434\u0435\u0439. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u0438\u043a\u0441\u0435\u043b\u044f, \u0442\u0430\u043a \u0447\u0442\u043e \u043e\u043d \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u044b\u043c.<\/p>\n<p>  \u0424\u043e\u0440\u043c\u0443\u043b\u0430 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0430 (\u0435\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0446\u0432\u0435\u0442\u043e\u0432 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0435 \u043e\u0442 0 \u0438 1): <code>16 + r * 5 * 36 + g * 5 * 6 + b * 5<\/code>.<\/p>\n<p>  \u041e\u0448\u0438\u0431\u043a\u0430 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0433\u043e \u043c\u043d\u043e\u0439 \u043a\u043e\u0434\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0430\u0441\u044c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438: \u0448\u0435\u0441\u0442\u044c \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0446\u0432\u0435\u0442\u0430 \u043d\u0435\u043b\u0438\u043d\u0435\u0439\u043d\u044b: 0, 95, 135, 175, 215, 255; \u043c\u0435\u0436\u0434\u0443 \u043f\u0435\u0440\u0432\u044b\u043c \u0438 \u0432\u0442\u043e\u0440\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 95, \u0430 \u043c\u0435\u0436\u0434\u0443 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 40.<\/p>\n<p>  \u041b\u043e\u0433\u0438\u0447\u043d\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0442\u0451\u043c\u043d\u044b\u0445 \u043e\u0442\u0442\u0435\u043d\u043a\u043e\u0432, \u0432\u0435\u0434\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u044f \u0446\u0432\u0435\u0442\u043e\u0432 \u0437\u0430\u043c\u0435\u0442\u043d\u0435\u0435 \u043d\u0430 \u0441\u0432\u0435\u0442\u043b\u044b\u0445 \u0446\u0432\u0435\u0442\u0430\u0445. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043e\u0442 0 \u0434\u043e 255 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 <code>max(0, color - 95 - 40) \/ 40<\/code>.<\/p>\n<pre><code class=\"rust\">pub fn to_xterm(&amp;self) -> u8 {     let r = (self.r as f32 - (95.0 - 40.0)).max(0.0) \/ 40.0;     let g = (self.g as f32 - (95.0 - 40.0)).max(0.0) \/ 40.0;     let b = (self.b as f32 - (95.0 - 40.0)).max(0.0) \/ 40.0;      (16.0 +         r.round() * 36.0 +         g.round() * 6.0 +         b.round()) as u8 }<\/code><\/pre>\n<p>  \u0421\u0430\u043c\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043c\u043e\u0436\u043d\u043e \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u044b\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c <code>(r, g, b)<\/code> \u0438 <code>(36, 6, 1)<\/code>. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432\u044b\u0447\u0438\u0442\u0430\u043d\u0438\u0435 \u0432 \u0432\u044b\u0437\u043e\u0432 <code>mul_add<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043c\u043e\u0447\u044c \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0443 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 FMA.<\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u0442\u0430\u043f \u2014 \u044d\u0442\u043e \u043e\u0442\u0442\u0435\u043d\u043a\u0438 \u0441\u0435\u0440\u043e\u0433\u043e: \u043d\u0430\u0448 \u043f\u0440\u043e\u0444\u0438\u043b\u044c xterm \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 256 \u0446\u0432\u0435\u0442\u043e\u0432, \u0432 \u043d\u0451\u043c 216 \u0446\u0432\u0435\u0442\u043e\u0432 \u0438\u0437 \u043a\u0443\u0431\u0430 RGB (<code>6 * 6 * 6<\/code>), 16 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u0446\u0432\u0435\u0442\u043e\u0432 \u0438 24 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0441\u0435\u0440\u043e\u0433\u043e \u043e\u0442 <code>rgb(8,8,8)<\/code> \u0434\u043e <code>rgb(238,238,238)<\/code>.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043b\u0438 \u0446\u0432\u0435\u0442 \u0432 \u043e\u0442\u0442\u0435\u043d\u043a\u0430\u0445 \u0441\u0435\u0440\u043e\u0433\u043e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0447\u0435\u0441\u0442\u044c \u0435\u0433\u043e \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043e \u0435\u0433\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043b\u0438 \u043e\u043d \u043d\u0438\u0436\u0435 \u043f\u043e\u0440\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0441\u043a\u0430\u0436\u0435\u043c, 8.<\/p>\n<p>  <a href=\"https:\/\/github.com\/fathyb\/carbonyl\/blob\/5d0807e35b893963953791a1878fbe08de81a3ce\/src\/output\/xterm.rs#L4-L24\">carbonyl\/src\/output\/xterm.rs, \u0441\u0442\u0440\u043e\u043a\u0430 4<\/a><\/p>\n<pre><code class=\"rust\">pub fn to_xterm(&amp;self) -> u8 {     if self.max_val() - self.min_val() &lt; 8 {         match self.r {             0..=4 => 16,             5..=8 => 232,             238..=246 => 255,             247..=255 => 231,             r => 232 + (r - 8) \/ 10,         }     } else {         let scale = 5.0 \/ 200.0;          (16.0             + self                 .cast::&lt;f32>()                 .mul_add(scale, scale * -55.0)                 .max(0.0)                 .round()                 .dot((36.0, 6.0, 1.0))) as u8     } }<\/code><\/pre>\n<p>  <\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/s3\/mw\/us\/s3mwus3spzbflmogizo3eea-8yu.png\" data-src=\"https:\/\/habrastorage.org\/webt\/s3\/mw\/us\/s3mwus3spzbflmogizo3eea-8yu.png\"\/><\/div>\n<p>  <i>\u041f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u0443\u0431 RGB<\/i><\/p>\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/vm\/d7\/w-\/vmd7w-1fqustdo7o9badbuso3q8.png\" data-src=\"https:\/\/habrastorage.org\/webt\/vm\/d7\/w-\/vmd7w-1fqustdo7o9badbuso3q8.png\"\/><\/div>\n<p>  <i>\u0421 \u043f\u0443\u0442\u0451\u043c \u043a\u043e\u0434\u0430 \u043e\u0442\u0442\u0435\u043d\u043a\u043e\u0432 \u0441\u0435\u0440\u043e\u0433\u043e<\/i><\/p>\n<p>  \u041d\u043e \u0443 \u043d\u0430\u0441 \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043e\u0434\u043d\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430: \u043a\u0430\u043a \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043b\u0438 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b true color \u0438\u043b\u0438 256 \u0446\u0432\u0435\u0442\u043e\u0432? \u0417\u0430\u0433\u0443\u0433\u043b\u0438\u0432, \u043c\u044b \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f <code>COLORTERM<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432 \u0441\u043b\u0443\u0447\u0430\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 true color \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>24bit<\/code> \u0438\u043b\u0438 <code>truecolor<\/code>. \u041d\u043e \u043e\u043d\u0430 \u043d\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 Docker \u0438\u043b\u0438 SSH, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0430\u0448\u0438\u043c\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c\u0438 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430\u043c\u0438.<\/p>\n<p>  \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u044e\u043a \u0441 DCS (Device Control Sequence) \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0444\u043e\u043d\u043e\u0432\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430. \u0415\u0441\u043b\u0438 \u043c\u044b \u0437\u0430\u0434\u0430\u0434\u0438\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 RGB \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 RGB, \u0437\u043d\u0430\u0447\u0438\u0442, \u043c\u043e\u0436\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c true color.<\/p>\n<p>  \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/p>\n<pre><code class=\"bash\">$ printf \"\\e[48;2;13;37;42m\\eP\\$qm\\e\\\\\"; cat<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li><code>\\e<\/code>: \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c escape-\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c<br \/> \n<ul>\n<li><code>[<\/code>: \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/li>\n<li><code>48<\/code>: \u0437\u0430\u0434\u0430\u0451\u043c \u0444\u043e\u043d<\/li>\n<li><code>2<\/code>: \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0446\u0432\u0435\u0442 RGB<\/li>\n<li><code>13<\/code>: R = 13<\/li>\n<li><code>37<\/code>: G = 37<\/li>\n<li><code>42<\/code>: B = 42<\/li>\n<li><code>m<\/code>: \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433<\/li>\n<\/ul>\n<p>  <\/li>\n<li><code>\\e<\/code>: \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c escape-\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\n<ul>\n<li><code>P<\/code>: \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c device control sequence<\/li>\n<li><code>$<\/code>: \u0432\u0445\u043e\u0434\u0438\u043c \u0432 \u0440\u0435\u0436\u0438\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f<\/li>\n<li><code>q<\/code>: \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440<\/li>\n<li><code>m<\/code>: \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>  \u0415\u0441\u043b\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f, \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0441 \u0442\u0451\u043c\u043d\u043e-\u0431\u0438\u0440\u044e\u0437\u043e\u0432\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c:<\/p>\n<pre><code class=\"plaintext\">^[P1$r0;48:2:1:13:37:42m^[\\<\/code><\/pre>\n<p>  \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e \u044d\u043c\u0443\u043b\u044f\u0442\u043e\u0440 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 stdin, \u0438 \u044d\u0442\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043f\u0430\u0440\u0441\u0438\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c true color.<\/p>\n<p>  <a href=\"https:\/\/github.com\/fathyb\/carbonyl\/blob\/5d0807e35b893963953791a1878fbe08de81a3ce\/src\/input\/dcs\/parser.rs#L27-L41\">carbonyl\/src\/input\/dcs\/parser.rs, \u0441\u0442\u0440\u043e\u043a\u0430 27<\/a><\/p>\n<pre><code class=\"rust\">self.sequence = match self.sequence {     \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\     Code => match key {         b'0' | b'1' => Type(key),         _ => control_flow!(break)?,     },     \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\     Type(code) => match key {         b'$' => Status(StatusParser::new(code)),         b'+' => Resource(ResourceParser::new(code)),         _ => control_flow!(break)?,     },     \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\     Status(ref mut status) => return status.parse(key),     Resource(ref mut resource) => return resource.parse(key), };<\/code><\/pre>\n<p>  <a href=\"https:\/\/github.com\/fathyb\/carbonyl\/blob\/5d0807e35b893963953791a1878fbe08de81a3ce\/src\/input\/dcs\/status.rs#L33-L79\">carbonyl\/src\/input\/dcs\/status.rs, \u0441\u0442\u0440\u043e\u043a\u0430 33<\/a><\/p>\n<pre><code class=\"rust\">self.sequence = match self.sequence {     \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\     Start => match key {         b'r' => Value,         _ => control_flow!(break)?,     },     \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\     Value => match key {         \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\         0x1b => self.terminate(),         \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\         b';' => self.push_value(),         \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\         char => self.push_char(char),     },     \/\/ ^[P1$r0;48:2:1:13:37:42m^[\\     Terminator => control_flow!(break self.parse_event(key))?, };<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a<\/h2>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 xterm \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043e\u043a\u043d\u0430 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<pre><code class=\"rust\">fn set_title(title: &amp;str) {     \/\/ \u0417\u0430\u0434\u0430\u0451\u043c \u0438\u043c\u0435\u043d\u0438 \u0437\u043d\u0430\u0447\u043a\u0430 \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443 \u043e\u043a\u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 string     println!(\"\\x1b]0;{}\\x07\", title);     \/\/ \u0417\u0430\u0434\u0430\u0451\u043c \u0438\u043c\u0435\u043d\u0438 \u0437\u043d\u0430\u0447\u043a\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 string     println!(\"\\x1b]1;{}\\x07\", title);     \/\/ \u0417\u0430\u0434\u0430\u0451\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443 \u043e\u043a\u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 string     println!(\"\\x1b]2;{}\\x07\", title); }<\/code><\/pre>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u044f \u043e\u0431 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430, \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/source.chromium.org\/chromium\/chromium\/src\/+\/main:content\/public\/browser\/web_contents_observer.h;drc=d868f781dd811d46a0a5ae88ccaf4b5afb0f0f3c;l=576\">WebContentsObserver::TitleWasSet()<\/a>:<\/p>\n<pre><code class=\"cpp\">void HeadlessWebContentsImpl::TitleWasSet(content::NavigationEntry* entry) {     carbonyl::Renderer::Main()->SetTitle(         base::UTF16ToUTF8(entry->GetTitleForDisplay())     ); }<\/code><\/pre>\n<p>  <\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/63fc62253afabae0666da944\" data-style=\"\" id=\"63fc62253afabae0666da944\" width=\"\"><\/div>\n<\/div>\n<p><i>\u041e\u0442\u043b\u0438\u0447\u043d\u043e<\/i><\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/726110\/\"> https:\/\/habr.com\/ru\/articles\/726110\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/be\/7c\/vj\/be7cvjcanhv2iu49hamo1hu7wza.png\" data-src=\"https:\/\/habrastorage.org\/webt\/be\/7c\/vj\/be7cvjcanhv2iu49hamo1hu7wza.png\"\/><\/div>\n<p>  \u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0441\u044f\u0446\u0435\u0432 \u043d\u0430\u0437\u0430\u0434 \u044f \u043f\u0438\u0441\u0430\u043b \u043e <a href=\"https:\/\/fathy.fr\/html2svg\">\u0444\u043e\u0440\u043a\u0435 Chrome, \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0435\u043c HTML \u0432 SVG<\/a>, \u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u0445\u043e\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435\u0447\u0442\u043e \u043f\u043e\u0445\u043e\u0436\u0435\u0435, \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0432 \u0435\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b.<\/p>\n<p>  \u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e <a href=\"https:\/\/github.com\/fathyb\/carbonyl\">\u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440 Carbonyl<\/a>!  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-400279","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/400279","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=400279"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/400279\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=400279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=400279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=400279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}