Интеграция HTML движка в нативное Windows приложение – выбор и архитектура

в 7:29, , рубрики: , Blink, chromium, Google Chrome, GTK+, qtwebkit, webkit, wincairo, Анализ и проектирование систем, Блог компании 1С, разработка под windows

Как мы перевели работу с HTML в 1С:Предприятии с Internet Explorer на WebKit

Возможность отображать HTML в формах 1С появилась в платформе 1С:Предприятие еще в версии 8.0 (выпущена в 2003 г.). Для работы с HTML в платформе использовался движок браузера Internet Explorer (1С:Предприятие на тот момент работало только под Windows). Движок браузера использовался платформой для утилитарных целей. Например, писать с нуля полноценный элемент для редактирования текста а-ля Word – с возможностью различных цветовых и шрифтовых решений, вставки картинок и т.д. – весьма непростая задача. А если задействовать для этих целей HTML и использовать в качестве средства отображения движок интернет-браузера, то задача сильно упрощается. Также при помощи движка был реализован ряд других механизмов (например, отображение справочной информации) и элементов (например, Планировщик).

Ну а возможность для разработчиков прикладных решений отображать с помощью HTML нестандартный, по меркам мира учетных систем, дизайн позволяла иногда привносить разнообразные приятные изюминки в интерфейс бизнес-приложений.

Время шло, платформа стала поддерживать сначала Linux, а потом и macOS. Для работы с HTML в этих ОС Internet Explorer не подходил по понятным причинам; в Linux нами был задействован WebKitGTK+, а в macOs — библиотека на основе Cocoa. Таким образом, единство кодовой базы для разных ОС (которое мы стараемся поддерживать для клиентского кода на уровне 95%) в этой области было нарушено. Ну и движок IE к этому времени стал источником ряда проблем.
image

Проблемы:

  • У движка IE закрытый исходный код – значит:
    • Невозможна гибкая настройка движка под нужды платформы
    • Невозможны отладка и понимание процессов, происходящих внутри
    • Невозможно устранение багов и ошибок путем обновления версии движка
  • Движок не подходит для реализации современных задач веб-программирования
  • Проблемы производительности на слабых машинах

Итак, напрашивался перевод работы с HTML в версии 1С:Предприятия для Windows с движка IE на что-то другое. Что же выбрать?

Для начала мы сформулировали требования к движку:

  • Поддержка современных технологий веб-программирования
  • Открытый исходный код для возможности гибкой настройки движка и понимания логики его работы
  • Высокая производительность на слабых компьютерах
  • Желательно, чтобы движок требовал для работы небольшое количество сторонних библиотек

Выбор движка

Из чего выбирать? Начали мы, естественно, с WebKit, с которым уже работали в версиях платформы для Linux и macOS.

WebKit был разработан в Apple в начале 2000-х на основе движков с открытым исходным кодом KHTML и KJS. На основе WebKit был создан браузер Safari, позже – Chrome (еще позже Chrome перешел с WebKit на Blink, который опять-таки создан на основе кода WebCore из WebKit).

Исходный код WebKit – открытый, под лицензией LGPL. WebKit написан под macOS, под Windows есть несколько портов:

WebKit AppleWin

Это порт, который разработчики WebKit предлагают собирать под Windows по умолчанию. Был сделан сотрудниками Apple в середине-конце нулевых. Использует графическую библиотеку CoreGraphics, которая является упрощенной версией библиотеки под macOS, портированной на Windows. Для выполнения JavaScript порт использует библиотеку JavaScriptCore c тем же API, что используется в реализации платформы под Linux. Это делает его основным кандидатом для использования.

WebKit WinCairo

Ещё одна реализация движка WebKit под Windows, теперь уже независимая от разработчиков самого движка. Qt – популярная кроссплатформенная библиотека с собственной графической библиотекой QtGui. Этот порт также использует библиотеку JavaScriptCore для обработки JavaScript, однако у него есть минусы:

  • Сильная зависимость от основных компонент Qt, которые в случае использования в стороннем программном обеспечении нужно будет поставлять вместе с ним
  • Отличающийся набор интерфейсов для работы с компонентами для отрисовки HTML по сравнению с WebKitGTK и собственная логика работы с ними.

WebKitGtk+ for Windows

Мы уже использовали WebKitGtk+ в Linux-версии платформы. Но вариант задействовать его в Windows был исключен из-за сложности сборки, плохой документированности этого процесса и отсутствия постоянной поддержки этого направления развития от разработчиков WebKitGTK+.

Chromium(Blink)

Первый и единственный не WebKit-подобный движок, который рассматривался как кандидат для решения задачи. Был отвергнут из-за больших различий в логике работы компонент для отрисовки HTML по сравнению с WebKitGTK+ и другой библиотеки для работы с JavaScript (V8).

Что выбрать?

После исследований в финал вышли AppleWin и WinCairo.
Чтобы сделать окончательный выбор, мы изучили, как работает WebKit.

Структура движка WebKit

Обычно разные порты WebKit отличаются двумя вещами. Первая – это непосредственно реализация для конкретной ОС с задействованием ОС-специфичных компонент. Вторая – это графическая библиотека. На рисунке ниже описаны различия в этом смысле между портами WebKit. Для Windows разработчиками WebKit были написаны порты на адаптированной CoreGraphics и библиотеке Cairo.

image

Упрощенная модель работы движка: три традиционных механизма форматирования веб-страницы — HTML, JavaScript и CSS — подаются на вход движку, а он из них формирует и отображает страницу:

image

Сам движок состоит из нескольких компонент:

  • WTF (Web Template Framework, а не то, что вы, возможно, подумали): здесь находятся собственные реализации структур данных для функционирования движка, а также осуществляется работа с потоками
  • JavaScriptCore: компонента, как ясно из названия, для работы с языком JavaScript
  • WebCore: здесь написана вся работа с DOM, стилями, парсингом HTML и XML. Здесь делается вся основная «магия» движка
  • Platform: выполняет технические действия для взаимодействия с сетью, помещение данных в БД, декодирование изображений, работа с медиа
  • WebKit и WebKit2 API – связывание всех компонент и предоставление доступа к ним

image
Взаимосвязь компонент WebKit и ОС-специфичных особенностей — на рисунке ниже. Как видно, есть довольно много специфичных моментов, которые нужно реализовывать для каждой ОС отдельно. Хотя JavaScriptCore позволяет использовать себя в каждом порте без отдельных реализаций.

image

Как формируется веб-страница

Из сети приходит ответ на запрос к серверу с данными для загрузки. Загрузчик передает данные в парсер, который, взаимодействуя с компонентой для JavaScript, формирует DOM и таблицу стилей. Далее сформированные данные передаются в дерево рендеринга и отображаются графическим контекстом.
image
Сама страница состоит также из отдельных компонент. В компоненте WebCore реализован класс Page, который позволяет получить доступ ко всей странице. У Page есть главная рамка – MainFrame, в рамке всегда есть документ. В главной рамке может быть любое количество других рамок, также с документами внутри. Для каждой рамки отдельно формируются некоторые события, а также специфичные графический и JavaScript контексты.

image

Упрощенно HTML-парсер работает так. Из набора полученных от сервера байт декодер формирует набор символов для разбора. Символы преобразуются в лексемы или токены, которые обычно представляют собой элементарные части кода с мета-информацией о том, что это за текст, является ли он частью синтаксиса языка или контентом. Затем из токенов формируются узлы для построения DOM-дерева. Строитель дерева из набора узлов формирует полноценную объектную модель документа веб-страницы.

image

Окончательный выбор

  • AppleWin
    • Плюсы:
      • Реализован на графической библиотеке, которая работает в macOS – главной целевой платформе для разработчиков WebKit
    • Минусы:
      • Отсутствие реализации механизма печати
      • Большое количество зависимостей
  • WinCairo
    • Плюсы:
      • Та же графическая библиотека (Cairo), что и в используемом Linux-порте платформы 1С
    • Минусы:
      • Существенных для наших задач не обнаружено

Победил WinCairo. Для разработки взята последняя доступная на тот момент версия WebKit – 605.1.11.

Реализация

Хотя движок довольно неплохо покрыт юнит-тестами (около 30 000 на все компоненты движка, написаны авторами движка), в реализациях для “непрофильных” ОС (т.е. для всего, что не macOS), существуют ошибки и недоработки. Эти пробелы реализации постепенно обнаруживались по мере разработки и тестирования работы движка в составе платформы 1С:Предприятие.

Загрузка HTML-кода через Drag&Drop

При перетаскивании текста в окно обнаружилось, что если перетаскиваемый текст содержит не-ASCII символы, то в финальный документ вставляются иероглифы. Ошибка проявлялась только в Windows-реализации движка, потому что она работала со ОС-специфичным механизмом перетаскивания элементов. Оказывается, текст не декодировался из UNICODE в UTF-16 перед передачей в обработчик события вставки.

Изменение поведения по комбинации клавиш Shift+Enter

В большинстве текстовых редакторов (включая Microsoft Word) эта комбинация вставляет перенос строки. Стандартное же поведение WebKit – вставка нового параграфа (как при простом нажатии на Enter). Мы изменили движок, сделав поведение более привычным для пользователей.

Организация механизма Undo&Redo.

WebKit предоставляет API для реализации собственного механизма отмены и повторения действия пользователя. Его схема такова: когда пользователь совершает некое дискретное с точки зрения движка действие (например, переход к новому параграфу, форматирование курсивом, вставка), то WebKit сообщает об этом разработчику средствами API, чтобы он мог зарегистрировать это действие.

В процессе тестирования реализованного механизма выяснилась неприятная вещь: движок не сообщает об изменениях в структуре таблиц. Были добавлены команды добавления и удаления ячеек и изменения атрибута colSpan, которые стали частями составных действий, таких как, например, добавление/удаление столбца или строки таблицы. Такие составные команды регистрируются в тот же стек undo&redo, и вместе с командами из движка обеспечивают корректную работу механизма.

Вставка из Excel

Те, кто работал с буфером обмена Windows и Excel, возможно, знают, что, во-первых, при копировании из Excel в HTML формат буфера обмена в копируемый фрагмент помещаются только теги ячеек и рядов, но не тег самой таблицы, во-вторых, в ячейки не передаются стили из Excel документа. Из-за этого, вставка, например, в редактируемый элемент в Chrome цветной таблицы выглядит так:

Оригинал:

image

В Chrome:

image

Оба этих фактора не учли и разработчики WebKit. Открытость кода движка позволила нам доработать механизм вставки, и теперь вставленный в ПолеHTMLДокумента фрагмент таблицы близок к оригинальному:

image

Генерация курсивных шрифтов

Если в Windows отсутствует italic-версия нестандартного шрифта, большинство текстовых редакторов умеет генерировать такой шрифт по его regular-версии. Однако WebKit такого не умел и пару раз ввёл разработчиков в заблуждение: как же так, в коде HTML документа мы помещаем текст в тег <i>, но несмотря на это текст оставался прямым. Причина в алгоритме подбора движком WebKit нужного шрифта в используемом нами порте WinCairo – в случае, если курсивной версии нет, движок использует regular-версию. Это поведение было заменено на использование генерируемого графической библиотекой Cairo курсивного шрифта.

Ошибки при декодировании изображений и анимации

Были обнаружены ошибки поведения движка при работе с графическими элементами. При загрузке некоторых картинок в формате PNG наблюдалось искажение изображения, а иногда и вовсе его отсутствие. Причину такого поведения выяснить не удалось, так как ошибка происходит при декодировании изображений в недрах библиотеки libpng.

Опытным путём было выяснено, что при линковке библиотеки libpng динамическим способом вместо статического, проблема устраняется. Кстати, в актуальной версии движка линковка выполнена именно этим способом. Было решено поступить так же.

Еще одной проблемой оказалась работа движка при загрузке анимаций в формате GIF. Ошибка периодически воспроизводилась при загрузке страницы с такими анимациями и приводила к аварийному завершению работы программы. Ошибка была вызвана отсутствием синхронизации при работе с буфером, в который помещается очередной кадр анимации. Проблема была устранена использованием внутренних средств синхронизации WebKit.

Поддержка правописания

В сборке с Internet Explorer, в Windows версии 8 и новее у редактируемого поля HTML можно было включить проверку правописания. Для этого достаточно было атрибут «spellcheck» сделать равным «true». У WebKit для разных портов были свои решения: в Linux это библиотека Enchant, в macOS — собственный механизм, знакомый всем пользователям продукции Apple. А вот для Windows реализации нет, но предоставляется API для собственного решения. Мы использовали Windows Spell Checking API, доступный начиная с Windows 8, и реализовали механизм по аналогии со сборкой с Internet Explorer. Кстати, теперь в форматированном документе в нативных клиентах 1С:Предприятия тоже работает эта функциональность. До версии 8.3.14 она была отключена из-за низкой производительности Internet Explorer.

Поддержка Windows XP

Часть наших клиентов до сих пор работает на Windows XP, и в ближайшее время апгрейдить ОС не собирается. Печально для нас как разработчиков, но факт. А значит — нам надо их поддерживать. И тут нас ждал неприятный сюрприз: разработчики WebKit уже около года не поддерживали работу движка в WinXP. Попытка собрать версию движка с набором средств сборки для WinXP не привела к успеху — разработчики WebKit используют библиотеки, доступные только с версии Windows Vista и более поздних.

Что делать? Варианты были такие:

  1. Оставить в WinXP реализацию с движком Internet Explorer, а в старших версиях Windows использовать WebKit
  2. Взять для разработки более раннюю версию движка WebKit, работоспособную в WinXP, и использовать эту версию во всех ОС
  3. Использовать в WinXP подходящую версию WebKit, а в старших версиях Windows использовать свежий движок
  4. Портировать актуальную версию движка на WinXP самостоятельно и использовать её везде

Вопрос стоял непростой. Первый вариант позволял использовать самую свежую версию движка WebKit, но вынудил бы вернуть старую реализацию с Internet Explorer. В таком решении было бы тяжело обеспечивать безошибочную работу программы, а также сам код сильно бы усложнился. Второй вариант обеспечивал одинаковое поведение на всех ОС Windows, однако не оставлял бы нам возможности для развития – обновления движка для исправления ошибок и получения новых возможностей от разработчиков движка в более поздних версиях. Третий вариант позволял задействовать актуальную версию движка в старших версиях Windows, но сильно усложнял логику установки и обеспечение одинакового поведения версий во всех ОС. Четвёртый вариант выглядел предпочтительнее всех остальных, однако было невозможно спрогнозировать сложность и вообще возможность такого решения.

Решили все же рискнуть и реализовать четвертый вариант, самый правильный с архитектурной точки зрения (использование единого исходного кода движка на всех версиях Windows). Портированная версия WebKit по-разному работает в WinXP и более новых версиях Windows:

  • Пришлось отказаться от средств нового DirectX (d3d11) в пользу старого DirectX9 (d3d9) и адаптировать его заголовочные файлы к младшей версии SDK.
  • Функции из нового SDK при выполнении на новых версиях Windows вызываются по адресу (получаемому через GetProcAddress).
  • Для передачи в движке данных между потоками в WinXP используется Thread local storage, в новых версиях — Fiber local storage.

Итог

Итак, теперь у нас в платформе 1С:Предприятие начиная с версии 8.3.14 (релиз — конец 2018 г.) HTML будет поддерживаться по высшему разряду – HTML5, OpenGL и т.д. И количество, и качество изюминок, которые можно привнести в решения на нашей платформе, ограничиваются только фантазией разработчика. И еще, конечно, операционной системой клиента – на WinXP многие вкусные плюшки из HTML5 работать, по понятным причинам, не смогут.

Теперь на Windows приложения на платформе 1С:Предприятие смогут показывать вот такое:

Но, используя «вкусности» HTML в прикладных решениях, не стоит забывать и здравый смысл. Использование HTML целесообразно и рекомендуется для специализированных задач (отображения справки, методик, описаний товаров, …), но не для реализации задач бизнес-логики (ввода/вывода структурированной информации). Для этого нужно использовать штатные механизмы интерфейса 1С:Предприятия, обеспечивающие автоматическую поддержку прав доступа, управления функциональностью, адаптации к форм-фактору устройства, поддержку пользовательских настроек и работу многих других механизмов, без которых полноценная работа бизнес-приложения становится практически невозможной.

Автор: PeterG

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js