biohazard

Обновление групчатов

Я сделал это. Сделал постоянные групчаты в tox-е.
Суть проблемы всем известна - групчаты в токсе умирают сразу после дисконнекта. Отвалилась связь? Заходи в групчат по новой. Перезапустил клиент - заходи в групчат по новой. Чтобы хоть как-то снизить градус нелепости происходящего, были придуманы групботы. Групбот - это такой друг (в терминах tox-а - friend), которы online 24/7 и который без вопросов соглашается на приглашение в друзья от любого, кто это приглашение ему пошлет. Этот групбот сидит в неком групчате (или сразу в нескольких) и таким образом оберегает групчат от исчезновения. За одно этот групбот понимает простые команды, типа invite или info. По команде invite, групбот приглашает вас в свою группу, в которой сидит сам. Есть и продвинуая версия групбота, российская Kalina, которая приглашает вас сразу, как только вы появляетесь в онлайне. Если кому интересно, можете добавить Калину себе в друзья и сразу попадете в чат, в котором обитает и ваш покорный слуга. Адрес Калины: kalina@toxme.io

А теперь пойдет злобный текст.
Как оказалось, такое свойство групчатов tox не потому что невозможно сделать иначе (я слышал фразы типа: "ну это же p2p, там все не так просто"), а потому что irungentoo, тот самый чувак, который и сотворил весь tox (за что ему, конечно, спасибо) забил на разработку. При чем забил, толком не доведя tox до ума. И, как показали дальнейшие события, это был единственный человек, который хоть что-то мог сделать. Все остальные из команды Tox Foundation, просто какие-то импотенты (Ребята, если вам кто-то переведет этот текст, можете меня возненавидеть. Вы реально нихера не умеете. А лучше не рефлексуйте, а идите и работайте). Кстати, существует реализация т.н. "новых" групчатов (тут). Но эту реализацию делали какие-то студенты по программе GSoC, и никто из Tox Foundation не знает как она работает. А она и не работает :) Поэтому воз и ныне там.

Вобщем, решил я что-то с этим сделать. Покопавшись в коде групчатов примерно с месяц, я сумел полностью их постичь, применив свой любимый метод - переписать нахрен. В процессе переписывания появлялись различные проблемы, которые я решал и смотрел, как они решены в оригинальном коде, тем самым постигая непонятные и, на первый взгляд, сомнительные куски оригинального кода.

В результате на свет появилось обновление к текущим групчатам, выраженное вот в этом PR-е. Как вы можете видеть, PR не принят. Я думаю, он не будет принят никогда. А всё потому что ребятки заигрались в крутую команду разработки, сами при этом нихрена не умеючи. Вобщем, они хотят двух вещей, на которые сами не способны: 1. Понять, как это всё работает. 2. Тесты. Я, тесты, понятное дело, писать не буду, т.к. хватит и того, что Isotoxin с этим обновлением вышел и работает. С первым пунктом, похоже вообще беда.

А между тем у обновы следующие свойства:

  • практически полная совместимость с текущим протоколом

  • исправление некоторых багов (например, некоторые клиенты иногда перестают видеть свои же собственные сообщения)

  • минимальное изменение в API

  • восстановление групчата даже если ваш друг (через которого и происходит восстановление) имеет старую версию групчатов


Что не сделано и, скорее всего, никогда не будет сделано, т.к. я, вероятно, буду писать новую реализацию групчатов.

  • восстановление через не-друзей (это возможно, но в рамках существующего протокола - сомнительное удовольствие)

  • публичные чаты. Это вообще за гранью. Не в текущем протоколе, однозначно.

  • синхронизация сообщений

  • упразднение разделения на типы (текстовый, аудио) групчатов. Сейчас это разделение имеет смысл, т.к. аудио групчат может выбивать пиров с плохим соединением. Это нужно править кардинально.


Что в итоге. В итоге Isotoxin умеет обновленные групчаты. Вы можете создать с друзьями групчат и он никуда от вас не денется. Вряд-ли вы увидите эту функциональность в других клиентах. Почему? Потому что ленивые жопы, вот почему. Ну или криворукие, если это вам ближе.
Хорошая новость в том, что я плотно засел за linux порт Isotoxin-а. Прямо очень плотно. Намереваюсь во что бы то ни стало, довести это дело до релиза. Плохая новость в том, что мне никто не помогает. С другой стороны, я делаю то что мне нравится, и это хорошая новость :) На этом пока всё.
biohazard

Автоскрываемая панель задач

Ох уж эта винда...
Вобщем, есть в винде возможность сделать таскбар автоскрываемым. Я с самого начала времен решил, что это фишка неудобная, и благополучно забыл о ней. Но, оказывается, есть люди, которые этой фишкой пользуются. Казалось бы, при чем тут Isotoxin? А дело тут вот в чем. Если вкратце, то имеет место баг: если Isotoxin раскрыть на весь экран, то скрытый таскбар не вызывается. Баг есть, надо лечить. Для начала, надо разобраться в сути вопроса.
Как оказалось, таскбар, будучи скрытым, торчит кромкой шириной в 2 пикселя из-за границы экрана поверх всех окон. Когда пользователь подводит туда мышкой, таскбар на это безобразие реагирует появлением. Ну и в чем тут засада? А засада тут в двух моментах:
1. Эти 2 торчащих пикселя не вычитаются из полного экрана, как это происходит, когда таскбар не скрыт.
2. Режим "поверх всех окон" сделан не с помощью стиля TOPMOST, а немного иначе (что, на самом деле правильно).

Что это означает: во первых, программа, запрашивая у системы размер максимальной рабочей области, не видит этих двух пикселей. Система о них не сообщает, фактически. Во вторых, это окно таскбара вообще не поверх всех окон. При раскрытии во весь экран, система просто подрезает максимальное окно на эти 2 пикселя.

Что получается. Поскольку Isotoxin отрабатывает манипуляции над своим окном самостоятельно, то при максимизации отрабатывает не ShowWindow(hwnd, SW_MAXIMIZE), как это обычно бывает, а просто окну выдается размер рабочей области текущего монитора. И, в согласии с особенностями реализации скрытого таскбара (пункты 1 и 2), оный оказывается под распахнутым на весь экран окном Isotoxin'а. Всё. Сообщения от системы о движении мыши таскбару не доходят и он не появляется.

Если честно, то я не знаю как правильно решить эту проблему. Можно было бы сделать окна Isotoxin'а более стандартными, т.е. делегировать все функции по ресайзу системе. Но делать это я не буду. Не хочется переписывать архитектуру движка интерфейса. Так что фикс немного хинтовый. Просто Isotoxin теперь самостоятельно определяет факт нахождения курсора над областью таскбара и сам сообщает ему, что неплохо бы и появиться. Вот такой вот грязный хак.

UPD:
Все же у этого хака есть недостаток: таскбар остается активным, пока явно не будет активировано другое окно.
Все таки немного изменил решение. Просто теперь размеры полного экрана учитывают торчащие 2 пикселя таскбара. Это пришлось сделать вручную, т.к. системные функции получения размера экрана не видят этих 2-х пикселей.
biohazard

Jabber

Решил подтвердить слово "мультипротокольный" в словосочетании "мультипротокольный клиент", когда это словосочетание применяется к Isotoxin'у. Ну да, формально, там сейчас два протокола: Tox и Lan. Но Lan, несмотря на то, что это вполне рабочий протокол, является всего-лишь протоколом, созданным мной для отладочных целей, в том числе и для отладки мультипротокольной архитектуры Isotoxin'а. Просто, некий бонус, необязательный к использованию, хотя и потенциально полезный.
Вобщем, мне нужно срочно добавить поддержку еще одного протокола, желательно распространенного. Сначала я хотел добавить Telegram, но пока решил повременить. Почему? Ну у меня сложилось впечатление, что г-ну Дурову вовсе не интересны сторонние клиенты. Да, протокол открыт. Но! Но не существует официально поддерживаемой библиотеки, поддерживающей этот протокол. Неофициальные - да, такие есть. Но что будет, если в протокол внесут изменения, а разработчик неофициальной библиотеки отошел от дел? Вот именно. Ничего не будет... работать. Поэтому, единственная для меня возможность сделать поддержку телеграма - это использовать официальные исходники Telegram Desktop. Но это не так то просто. Там всё слишком завязано на Qt. Не то, чтобы я был против этой замечательной библиотеки, но тянуть в проект Qt ради кода, который всё что делает, так только соединяется с чем-то в сети, (т.е. никакого GUI), считаю слишком накладным.
Что еще у нас открытого и распространенного? Да собственно, только Jabber, он же XMPP. Решено, делаю поддержку Jabber'а.

После беглого ознакомления со спецификацией, я понял, что этого монстра с нуля мне не осилить. Во всяком случае, за вменяемое время. Поиск библиотек, реализующих хотя бы часть спецификаций (или расширений, в терминах XMPP, т.н. XEP-ов), привел меня к библиотеке gloox. Подкупило, что эта либа написана на C++ (голый C, конечно, хороший язык, но его ограничения вгоняют меня в тоску), а также неплохая документированность. К плюсам библиотеки также можно отнести ее расширяемость: если какой-то XEP не поддерживается непосредственно библиотекой, довольно просто написать необходимую обвязку самостоятельно.
На момент написания этого поста, работы по внедрению поддержки Jabber'а уже близки к завершению. Осталось прикрутить передачу файлов, поддержку групповых чатов и подгрузку offline сообщений сервера. Хотя, как сказать. Возможно на эти три фичи я потрачу времени больше, чем на то что уже сделал (т.е. всё остальное).

Ну и под конец поста немного критики.
Вы, возможно, помните времена бума Jabber'а лет 10 назад. Поддержка крупными компаниями, типа гугла. Светлое будущее, аська должна умереть, что такое скайп и т.п. радостные возгласы. Казалось бы, вот он идеальный протокол обмена мгновенными сообщениями. Как бы не так.
Jabber - это перегруженный фичами монстр, в котором одно и тоже может быть сделано 5-ю разными способами, при этом первый способ устарел, второй поддерживается всем клиентами, но половиной клиентов неправильно, третий способ поддерживается только двумя клиентами, четвертый - только двумя серверами, а пятый еще в разработке и меняется каждый день. Утрирую, конечно. Но, по моему скромному мнению, jabber разваливается под собственным весом. Одних только способов передачи файлов есть как минимум 3 способа. Издевательство какое-то.
Вот такой вот он, jabber, великий и неподъемный. Вот вам маленький такой списочек XEP'ов. По каждому XEP-у многостраничный документ. Да в гробу я видал этот ваш XMPP.
Шучу. Скоро будет.
biohazard

64 бит

При портировании на линукс во всей красе встала необходимость собирать весь код под 64 бита. Вариант 32 битной сборки под линукс, хоть и осуществимый, но нелепый, с точки зрения здравого смысла. Вобщем, 64 бита...
Решено, сначала сделаю 64-биную версию под Windows, а там продолжу портировать под линукс.
Какие проблемы? Ну, особых проблем с C/C++ кодом нет. Включи сборку под 64 бита и компилятор все сделает. При условии, что код специально не затачивался под 32 бита, типа какой-нибудь хитрой арифметики на указателях. Ну я таким не злоупотреблял, поэтому тут все ok. Пришлось, правда, немного поиграться с типами данных, чтобы убрать тонны новых предупреждений на тему "ой, а вот тут у вас size_t в int преобразуется, битики теряются".
Самое веселье началось с _asm вставками. Как известно, в 64-битном режиме _asm вставки теперь вне закона. Сначала я негодовал по этому поводу, но позже понял, что побудило microsoft пойти на такой шаг. Дело в том, что т.н. AMD64, т.е. 64-битная архитектура, которую изначально придумала AMD, а Intel несколько позднее лицензировала, т.е. та самая 64 битная архитектура, которая ныне присутствует в подавляющем большинстве desktop компьютеров, обратно совместима со старым добрым x86. Т.е. код на ассемблере под x86, совершенно валиден для AMD64. Если бы microsoft своим волевым решением не поставила _asm вставки вне закона, то компилятор бы не имел возможности отличить x86 ассемблер от AMD64. Понятно, к чему бы это привело. Да. Старый код с _asm вставками просто приводил бы к неработоспособности только что собранного исполняемого файла.
Впрочем, если бы microsoft ввели ключевое слово, типа _asm64, то было бы намного лучше, чем вообще ничего.

И знаете что? Мне пришло понимание того, что далеко не всякая 64-битная версия какой либо программы, такая же быстрая, как 32-битная. В общем и целом, сборка под 64 бита быстрее - сказывается наличие 8 дополнительных регистров, да и некоторые алгоритмы на 64 бита ложатся лучше. Но есть большое НО. Это старый 32-битный код на ассемблере. Если в программе такого кода много, то разработчик, скорее всего, не будет писать такие же быстрые функции на 64 битном ассемблере (во всяком случае, не сразу), а оставит реализацию на языке высокого уровня. В большинстве случаев, разницы в скорости никто не заметит, но есть случаи, когда разница есть, и она ощутима.
Я говорю об оптимизации работы с графикой на SSE. В коде Isotoxin'а многие тяжелые операции оптимизированы на ассемблере с SSE, и вот сейчас встал вопрос о переписывании этого кода так, чтобы он заработал на 64 битах. Это и оказалось самым сложным в портировании на 64 бита.
Вобщем, решил я попробовать SSE интринсики. Это отдельные SSE команды, которые выглядят как функции. Попробовал и остался доволен результатом. Очень доволен. Как оказалось, если готовую реализацию на ассемблере перевести в код на интринсиках как есть, то скорость работы такого кода иногда даже выше, чем оригинального asm кода! Чудо! Разработчики оптимизаторов - мое почтение!
biohazard

gcc vs msvc

Потихоньку портирую на линукс. Естественно, возникла необходимость собирать код с помощью gcc. Как оказалось, gcc невероятно параноидален в плане соблюдения стандарта. Нет, я не против привести свой код в соответствие, так сказать. Но, местами, откровенно бесит. Вот взять, к примеру, разбор шаблонов. Тут gcc пытается сразу разобрать шаблон по косточкам и убедиться, что там всё верно. Казалось бы, благая цель. Но не все так просто. msvc не пытается найти в шаблонах ошибки. Нет, он находит проблемы в синтаксисе, не без этого. Но вот, если я обращусь к переменной, которой не существует, msvc ничего не скажет. Почему? Ну потому что, когда я проинстанцирую шаблон, возможно эта переменная появится, и ругаться на этапе парсинга шаблона действительно не стОило. К чему это приводит? К тому, что там где msvc спокойно собирает код, gcc спотыкается, требуя подсказок. Вот пример кода, на котором gcc споткнется, а msvc проглотит не икнув:

template<typename T> struct foo {
    T bar;

    void do_something() {
        bar.func<int>( 123 );
    }
};

Видите? Я вызываю шаблонный метод func класса T. gcc не понимает, что я от него хочу. Исправлю код:

template<typename T> struct foo {
    T bar;

    void do_something() {
        bar.template func<int>( 123 );
    }
};

"Другое дело" - говорит gcc и работает дальше.
Вот и сижу, подсовываю костылики бедненькому gcc, а то не справляется. Но это ладно. Добавить ключевое слово - не великА беда. Гораздо сложнее приходится в том случае, когда чего-то вообще нет в стандарте, но есть в msvc. Я может и был не прав, что использовал эти возможности, но ведь эти возможности не случайно появились в msvc. msvc создавался не ради стандарта, а как рабочий инструмент огромной корпорации, а, значит, старался упрощать жизнь программистам в некоторых областях. Так, msvc поддерживает частичную специализацию функций. Да, в стандарте этого нет. Да, в большинстве случаев, можно обойтись перегрузкой. Но есть ситуации, где перегрузка не спасает и приходится городить кучу вспомогательных шаблонов, просто чтобы уложиться в стандарт. А msvc позволяет сделать красиво и аккуратно. Еще, из-за отсутствия __if_exist, мне добавилось много работы по сопровождению старого кода. Там где __if_exist обеспечивал мне функциональность по умолчанию, теперь нужно сообщать компилятору об этой функциональности явно, что не добавляет коду легкости. Ну да ладно. Хорошо, хоть разработчики gcc перенимают иногда хорошие вещи у msvc (например #pragma once).
Вобщем, работа потихоньку движется.
biohazard

hunspell - кошмар перфекциониста

hunspell - это библиотека проверки орфографии. Используется во многих крупных проектах. Из известных: mozilla firefox, google chrome, open office. Можно сказать, основная библиотека для проверки орфографии. Существует много словарей.
Когда я выбирал библиотеку для проверки орфографии в Isotoxin'а, особо много не думал. Самое популярное, да в таких проектах - конечно надо брать.

Сейчас я расскажу, что предстало моим глазам. Если вкратце - я очень расстроен. Такого унылого кода я давно не видел. Понятно, всё работает. Работает - не трогай. Но, хочется взять и всё переписать.
1. Библиотека не умеет загружать словари из буфера в памяти. Это, товарищи, просто п#$ец. Я это ограничение обошел, но, как говорится, не повторяйте это дома.
2. Библиотека не позволяет проверять на одном словаре сразу несколько слов, используя разные потоки. Можете себе представить, на дворе век многоядерных машин, а кто-то до сих пор пишет код, который не дружит с параллельностью. А проверка одного слова, кстати, не очень то быстрая.
3. Библиотека написана изначально но C, а позже ее частично переписали на C++. Вобщем самые худшие техники обоих языков переплелись воедино. Взгляните на этот код:

std::string tword(appnd);
tword.append(word + strip.size());
return mystrdup(tword.c_str());

Что мы тут видим? Создается std::string строка на стеке, к ней добавляется подстрока (word - это указатель на строку), а затем создается копия строки, которая возвращается. Я не знаю, видите ли вы тут п#$дец настолько отчетливо, насколько его вижу я... Просто поверьте - это говнокод. Особая, ядреная квинтэссенция говнокода, которую только можно написать на обоих языках.

У меня уже третью неделю чешутся руки переписать весь hunspell на c++ по человечески. Останавливают меня только два момента - это моя лень и необходимость последующего вливания обновлений вручную из оригинального репозитория.
biohazard

Попытка улучшить качество видео

Выпустил версию 0.3.424. В ней, среди прочего, реализовал свой собственный способ передачи видео. Как я уже писал, ядро передает все видеоданные в режиме lossy, т.е. с потерями. Я сделал передачу видео без потери. Алгоритм очень простой: кадр ставится в очередь на отправку, и пока весь кадр не будет передан другой стороне, все вновь поступающие кадры с камеры просто отбрасываются. Таким образом я получаю гарантированно целую картинку, но, возможно, с низким fps. Сначала отбрасывал неключевые кадры, т.е. новый кадр отправлялся на сжатие, и если кодек выдавал неключевой кадр, то этот кадр мог быть отброшен, если поступил новый кадр, а ключевой еще не был передан. Однако такая стратегия сразу приводила к порче картинки. То ли vp8 кодек очень чувствителен к потери неключевых кадров, то ли я чего-то в нем не докрутил, но выкидывать из очереди неключевые кадры без ущерба для качества нельзя. Тогда я просто стал выкидывать кадры до отправки их в кодек, а то что успело сжаться, отправлялось безусловно.
Результаты:
Во первых качество передачи видео заметно возросло. Картинка больше не рассыпается на цифровой шум при малейшей возможности. В локальной сети передача full-hd идет без проблем. Победа? Не совсем. Во всей красе всплыл баг toxcore, который частенько проявлял себя при передаче больших файлов: разрыв соединения. Увы, это болячка ядра все еще не исправлена. Видимо, скоро мне придется заняться этой проблемой. Другой момент - низкий fps хорош при передачи изображения с рабочего стола, а вот с камеры - это плохо. С камеры надо снижать битрейт, чтобы fps оставался высоким. Займусь этим вскоре.
Новый способ передачи видео работает только при соединениях Isotoxin-Isotoxin, что очевидно. В продвинутых настройках видеозвонков можно выключить это поведение и видео будет предаваться как и раньше, встроенными средствами toxcore. Там же, в расширенных настройках можно включить кодек vp9. Честно сказать, смысла в этом никакого. По качеству разницы почти не видно, зато vp9 оооочень медленно сжимает. Буквально мой 4-х ядерный i5 загружается на 80%, при том что vp8 на том же видеопотоке едва грузит на 3%. Не исключаю, что я что-то опять напутал в настройках кодека. Займусь этим позже.
Кстати, vp9 еще достаточно сырой кодек, несмотря на то, что гугл уже пилит vp10. Я словил неприятность в виде подвисания декодера. Ну то есть, в какой-то момент декодер vp9 просто натурально зависает. Немного покопавшись, я нашел причину. В процессе работы vp9 использует все доступные буфера кадров, коих он выделяет что-то порядка десятка (точнее смотреть лень) и в этот момент, из за бага в коде, указатель позиции чтения кадра остается в нулевом значении и кодек снова и снова пытается обработать один и тот же кадр и тем самым виснет. В своей сборке кодека я исправил этот баг. Хотел было сделать pull request с исправлением в основной репозиторий кодека, но, как оказалось, зеркало на гитхабе пул реквесты не принимает, а разбираться с тем, как сделать пул реквест в основной репозиторий, мне просто не хочется.
Вобщем, еще есть над чем работать в плане передачи видео. До скайпа пока не дотягиваем, увы.
biohazard

Dark Theme

Закончил эпопею с цветами.
В самом начале GUI движок делал очень просто: все что было на экране, тупо собиралось из кусочков png картинки. Вот, например, такая png-шка была где-то в самом начале разработки:
back@183.png
В общем-то любые графические запросы это покрывало, но имело огромный недостаток: каждый элемент интерфейса надо было рисовать. А это огромные затраты времени для меня, не-художника и не дизайнера. С этим надо было что-то делать. Первый шаг - области со сплошным цветом стало возможно заливать программно. Жить стало немного легче. Я просто указывал в файле интерфейса, что вот эта область должна быть красной, и мне не нужно было рисовать красный прямоугольник в моей картинке интерфейса.
Через некоторое время я понял, что задолбался рисовать круглые кнопки. Если с прямоугольными проблем не было - они формировались программно из вон тех голубеньких прямоугольников (чуть леве и выше центра, см. картинку), то с круглыми - просто беда. Каждую такую надо было нарисовать в 4-х экземплярах. В один прекрасный момент я написал программную генерацию круглых кнопок с тенью. Жить стало еще легче. Теперь мне было достаточно нарисовать ч/б иконку к кнопке, а всё остальное генерировалось программно.
Так я и жил, пока не задался целью создать тёмную тему интерфейса. Самый просто вариант - это сделать клон светлой темы и в фотошопе подправить цвета на картинке-исходнике запчастей для GUI движка. Ну еще немного подправить цвета для программных заливок и кнопок. Думаю, я бы сделал это в течении дня. Но к чему бы привело такое решение? А к тому, что мне пришлось бы по полной поддерживать уже две темы. Понадобилась новая кнопка - будь любезен нарисовать к ней иконку в двух экземплярах, пропиши настройки генерации в двух местах. В общем - удвоение работы на ровном месте. Так не пойдет.
Я решил, что вынесу все используемые в интерфейсе цвета в отдельный файл и научу движок интерфейса для одной и той же темы интерфейса подключать разные наборы цветов. Занявшись этим, я довольно быстро уперся в серьезную проблему, а именно: в интерфейсе оказалось полно элементов, которые уже нарисованы и для них практически невозможно поменять программно цвет. Например, квадратик чекбокса. В светлой теме он черный. В темной теме, он, очевидно, должен быть светлым. Но как изменить его цвет в картинке, если он там нарисован с тенью и с цветовыми градиентами? Экспериментируя с фильтрами, я так и не добился приемлемого результата. В итоге решил, что настала пора переводить весь интерфейс на svg. Собственно, предыдущие посты именно про это. Теперь практически весь интерфейс генерируется программно из svg конструкций. Движок по прежнему умеет работать с растровой графикой, но теперь ее осталось совсем мало. Зато теперь можно изменять цвета всех элементов интерфейса, совершенно не напрягаясь, что и сделало возможным появление темной темы.

PS. Для gif-смайлов колобков потребовалось сделать специальный фильтр, который делает их нормально выглядящими на темном фоне.
biohazard

librsvg

Библиотека librsvg слегка глючновата. Скопипастил с неё парсер пути и обнаружил, что на некоторых путях получается фейл. Косяк нашелся. Как оказалось, rsvg неправильно брал базовые координаты точки для команды m. Нужно брать координаты последней M, а не просто последней точки. Например вот этот путь rsvg парсит неверно: "M 14.790242,6.1529815 C 10.409578,6.1526455 6.8582656,9.7039577 6.8586016,14.084621 l 0,36.617188 c -3.36e-4,4.380664 3.5509764,7.931978 7.9316404,7.931638 l 24.136719,0 c 4.38067,3.4e-4 7.931981,-3.550974 7.931641,-7.931638 l 0,-29.548828 -15,-14.9999995 z m 1.871095,4.1015625 12.535155,0 0,8.955077 c 0,1.73127 1.629334,3.824219 3.626954,3.824219 l 9.751953,0 0,26.138672 c 2.7e-4,3.576247 -1.701104,5.410431 -5.277344,5.410156 l -20.304688,0 c -3.576247,2.75e-4 -5.875274,-2.033128 -5.875,-5.609375 l 0,-33.775391 c -2.74e-4,-3.576246 1.966722,-4.943632 5.54297,-4.943358 z"

Я уже писал про неэффективность librsvg. Но тогда это был вывод на основе беглого взгляда на код. Сейчас, когда я неплохо разобрался во внутренностях этой либы, могу подтвердить свои догадки. Почти весь код библиотеки написан, хотя и аккуратно, но совершенно без оглядки на производительность. Такое впечатление, что авторы вообще не знают, что код может работать медленно. Особо меня впечатлил код фильтра feBlend. Решение о том, какую функцию обработки пикселя использовать, принимается... нет, не на каждый пиксель. Хуже! на каждую компоненту пикселя! Черт. Да как так-то? Я уж молчу про malloc/free на каждый чих. Если вы используете librsvg для рендеринга хотя бы несколько раз в секунду, настоятельно рекомендую вам найти замену. Справедливости ради, на C писать эффективно такие сложные вещи, как librsvg, практически невозможно. Упорство некоторых программеров, изо всех сил игнорирующих C++, достойно лучшего применения.

Но, несмотря на баги, неэффективность и практическую невозможность собрать librsvg под виндой, так, чтобы exe'шник не подрос сразу на несколько мегабайт из за безумных зависимостей, я все равно благодарен создателям, т.к. без этой библиотеки постигнуть тонкости обработки и рендеринга svg файлов было бы в разы сложнее.
biohazard

Пост отчаяния или как собрать librsvg под Visual Studio

Работы ведутся. У меня даже родилась гениальная идея... тьфу. Так о чем это я?
А! Вобщем захотелось мне засунуть поддержку svg фомата в Isotoxin. Зачем? Ну так захотелось. Удобно рендерить запчасти интерфейса. Сейчас приходится каждую закорючку рисовать, но это слабо совместимо со сменой цветов. Т.е. идея такая: у темы есть набор раскрасок, которые можно быстренько менять. Но ведь цвета некоторых иконок прибиты в картинке темы гвоздями! Как быть? Ну, я не придумал ничего лучше, чем научить Isotoxin генерить UI элементы из svg.
Что там у нас умеет рендерить svg? librsvg, конечно. Все остальное по разным причинам не подходит. Ну так значит librsvg. Традиционно, я захотел собрать это под Visual Studio. Когда я пытался провернуть этот фокус с libvpx (я писал об этом тут), основная проблема была в генерации кода. Ох как любят программисты под линуксом всякую кодогенерацию. Ох любят! Но, как оказалось, кодогенерация - это просто детский сад по сравнению с настоящим, матерым linux-way в библиотеке librsvg. Блять! Извините за мат, но это пи%&ец, товарищи! ЗАВИСИМОСТИ! Сука, ну зачем так делать? Эта сраная библиотека тянет за собой чуть ли не весь GNOME. Вот уж счастье привалило!
Итак, чтобы собрать librsvg, нужно к ней собрать:
1. glib. Ради функций работы со строками. Этот адов монстр требуется целиком ради сраных строчек. А еще ради костылей, которые имитируют, блять, работу с объектами! С объектами! На C, блять!
2. libxml. Ну ладно, нам надо парсить xml. Но, почему не что-нибудь легкое, типа RapidXML. Почему опять нужен этот монстр? 35 мегабайт исходников! На%уя?! Это какая-то машина для парсинга всего, что изобрело человечество за последние 20 лет.
3. cairo. Каиро хорошая. Выглядит очень неплохой библиотекой. Умеет делать графику. Собственно, именно каиро будет заниматься рендерингом. А librsvg только преобразует команды svg в инструкции для каиро.
4. gtk-pixbuf. Накуя? В каиро всё есть! Накуя? 19Mb, блять, исходников, чтобы просто работать с буфером пикселей. Гениально!
5. pango. Шта? Это что еще за хрень? Какой-то костыль для каиро, для рендеринга текста? Не понял чет этот момент. Ну да ладно, еще разберусь.

Вот это я называю говнокодом. Тупо не паримся и ради мелкой фигни в коде подтягиваем самые большие и навороченные библиотеки, какие только найдем. Linux-way, мать его.
Но я не сдаюсь. Я буду, наверное, первым человеком на Земле, кто соберет это без этих адовых зависимостей. Или свихнусь.

UPD: Я слишком стар для этого дерьма. Проще написать аналог с нуля (тем более мне не нужна всеядность), чем ворошить это. rsvg слишком неотделим от GNOME.

UPD2: Пишу svg renderer lib с нуля. Это проще, чем казалось. Рутинные куски кода выдираются прямо из librsvg и подгоняются под C++. Кстати, из за своей C природы, librsvg жутко неэффективен, по сравнению с C++. Кто бы там что не говорил, но C++ позволяет писать значительно более эффективый код. ЗЫ: Каиро - офигенная библиотека.

UPD3: Написал поддержку svg. Не всё, конечно, но основные вещи, типа нарисовать сложную фигуру (тег path) и применить GaussianBlur фильтр, чтобы организовать тень, уже можно. Это полностью покрывает все потребности UI движка в деле генерации изображений UI элементов. В общем-то я даже рад, что librsvg собрать не удалось. Зато я много узнал о том, как svg устроен изнутри :)