Возможность отображать HTML в формах 1С появилась в платформе 1С:Предприятие в 2003 г. версии 8.0. Для работы с HTML в платформе использовался движок браузера Internet Explorer (1С:Предприятие на тот момент работало только под Windows). Движок браузера использовался платформой для утилитарных целей. Например, писать с нуля полноценный элемент для редактирования текста а-ля Word – с возможностью различных цветовых и шрифтовых решений, вставки картинок и т.д. – весьма непростая задача. А если задействовать для этих целей HTML и использовать в качестве средства отображения движок интернет-браузера, то задача сильно упрощается. Также при помощи движка был реализован ряд других механизмов (например, отображение справочной информации) и элементов (например, Планировщик).
Ну а возможность для разработчиков прикладных решений отображать с помощью HTML нестандартный, по меркам мира учетных систем, дизайн позволяла иногда привносить разнообразные приятные изюминки в интерфейс бизнес-приложений.
Время шло, платформа стала поддерживать сначала Linux, а потом и macOS. Для работы с HTML в этих ОС Internet Explorer не подходил по понятным причинам; в Linux нами был задействован WebKitGTK+, а в macOs — библиотека на основе Cocoa. Таким образом, единство кодовой базы для разных ОС (которое мы стараемся поддерживать для клиентского кода на уровне 95%) в этой области было нарушено. Ну и движок IE к этому времени стал источником ряда проблем.
Проблемы:
- У движка 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
Этот порт использует для графики библиотеку Cairo. Этот порт Apple какое-то время активно развивала как аналог основному порту AppleWin. Преимущество этого порта в том, что он менее зависим от macOS-специфичных библиотек, которые необходимы для работы CoreGraphics. Помимо этого порт использует ту же библиотеку для графики (Cairo), что и движок WebKitGTK+, который используется нами в Linux-реализации платформы, а это хорошо для стандартизации поведения нашего кода.
QtWebKit
Ещё одна реализация движка 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.
Упрощенная модель работы движка: три традиционных механизма форматирования веб-страницы — HTML, JavaScript и CSS — подаются на вход движку, а он из них формирует и отображает страницу:
Сам движок состоит из нескольких компонент:
- WTF (Web Template Framework, а не то, что вы, возможно, подумали): здесь находятся собственные реализации структур данных для функционирования движка, а также осуществляется работа с потоками
- JavaScriptCore: компонента, как ясно из названия, для работы с языком JavaScript
- WebCore: здесь написана вся работа с DOM, стилями, парсингом HTML и XML. Здесь делается вся основная «магия» движка
- Platform: выполняет технические действия для взаимодействия с сетью, помещение данных в БД, декодирование изображений, работа с медиа
- WebKit и WebKit2 API – связывание всех компонент и предоставление доступа к ним
Взаимосвязь компонент WebKit и ОС-специфичных особенностей — на рисунке ниже. Как видно, есть довольно много специфичных моментов, которые нужно реализовывать для каждой ОС отдельно. Хотя JavaScriptCore позволяет использовать себя в каждом порте без отдельных реализаций.
Как формируется веб-страница
Из сети приходит ответ на запрос к серверу с данными для загрузки. Загрузчик передает данные в парсер, который, взаимодействуя с компонентой для JavaScript, формирует DOM и таблицу стилей. Далее сформированные данные передаются в дерево рендеринга и отображаются графическим контекстом.
Сама страница состоит также из отдельных компонент. В компоненте WebCore реализован класс Page, который позволяет получить доступ ко всей странице. У Page есть главная рамка – MainFrame, в рамке всегда есть документ. В главной рамке может быть любое количество других рамок, также с документами внутри. Для каждой рамки отдельно формируются некоторые события, а также специфичные графический и JavaScript контексты.
Упрощенно HTML-парсер работает так. Из набора полученных от сервера байт декодер формирует набор символов для разбора. Символы преобразуются в лексемы или токены, которые обычно представляют собой элементарные части кода с мета-информацией о том, что это за текст, является ли он частью синтаксиса языка или контентом. Затем из токенов формируются узлы для построения DOM-дерева. Строитель дерева из набора узлов формирует полноценную объектную модель документа веб-страницы.
Окончательный выбор
- 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 цветной таблицы выглядит так:
Оригинал:
В Chrome:
Оба этих фактора не учли и разработчики WebKit. Открытость кода движка позволила нам доработать механизм вставки, и теперь вставленный в ПолеHTMLДокумента фрагмент таблицы близок к оригинальному:
Генерация курсивных шрифтов
Если в 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 и более поздних.
Что делать? Варианты были такие:
- Оставить в WinXP реализацию с движком Internet Explorer, а в старших версиях Windows использовать WebKit
- Взять для разработки более раннюю версию движка WebKit, работоспособную в WinXP, и использовать эту версию во всех ОС
- Использовать в WinXP подходящую версию WebKit, а в старших версиях Windows использовать свежий движок
- Портировать актуальную версию движка на 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С:Предприятия, обеспечивающие автоматическую поддержку прав доступа, управления функциональностью, адаптации к форм-фактору устройства, поддержку пользовательских настроек и работу многих других механизмов, без которых полноценная работа бизнес-приложения становится практически невозможной.
Комментарии (31)
Elanor
09.10.2018 11:01Примечание: Если у кого-нибудь в конфигурации использовался, например, разбор html-страницы c помощью объектной модели IE, то при переходе на новую версию платформы, такую конфигурацию надо будет доработать (перевести на модель WebKit).
Возможно, таких конфигураций немного, но всё же…
9thlevel
09.10.2018 12:02В форматированном документе, если работать с ним через веб-клиент, есть очень неприятная вещь — он теряет часть содержимого. Воспроизвести можно примерно следующим образом:
1) Добавить на управляемую форму (скажем, справочника) группу страниц.
2) Разнести элементы формы по разным страницам. При этом форматированный документ оставить на второй странице.
3) В режиме «Предприятие» в веб-клиенте наполнить форматированный документ.
4) Мышью переключиться на другую страницу и нажать CTRL+S.
5) После записи объекта перейти на вкладку с форматированным документом. Текст или его часть будет отсутствовать.
Опытным путем пришли к решению, что изменения содержимого поля форматированного документа помещаются в реквизит формы при смене фокуса на другой элемент. А в приведенном выше примере этого не происходит, соответственно, обновления данных в реквизите тоже.
Пока проблему решили принудительной установкой фокуса на другой элемент формы при смене страницы.
P.S. Платформа 8.3.11. Если не получится воспроизвести, могу скинуть видео.
iliabvf
09.10.2018 12:35Спасибо, хорошие новости.
Скажите а когда можно будет реализовать событие ПриНажатии в HTML поле в мобильном приложении?Neikist
09.10.2018 12:44Тоже с ним проблемы? Оно вроде как есть, но у нас не работало. Хотя надо бы на последних версиях проверить, может починили.
iliabvf
09.10.2018 13:12Да мы перешли на последнюю ознакомительную мобильную 8.3.13, но проблема не решена.
PeterG Автор
11.10.2018 10:03Насколько помню, в мобильной платформе событие ПриНажатии происходит только если нажатие приводит к переходу на другую страницу. У вас нажатие приводит к переходу на другую страницу?
iliabvf
11.10.2018 12:10Спасибо попробуем!
Пока что мы сильно не пользовались полем HTML в мобильной версии, т.к. при клике не срабатывало ПриНажатии.
unxed
09.10.2018 20:28А можно, пожалуйста, исправленный код поддержки вставки пулл-реквестом в вебкит и, по возможности, блинк? Спасибо!
PeterG Автор
10.10.2018 09:33Как дойдут у разработчиков руки — вольем. Но обычно разработчики у нас сильно загружены :(
paluke
10.10.2018 10:07А исходники этой доработанной версии WebKit где-то доступны?
PeterG Автор
10.10.2018 12:18Пока нет.
К выпуску версии 8.3.14 (ориентировочно — конец 2018 г.) планируем выложить исходники WebKit с нашими доработками здесь: github.com/1C-Company-third-party
istepan
10.10.2018 06:47Есть еще пятый вариант: Gecko
PeterG Автор
10.10.2018 15:39Совершенно верно. Я даже его на картинке нарисовал :)
Но Gecko у нас отвалился на ранней стадии рассмотрения, причину уже и не вспомню.
А у вас есть пример удачного использования Gecko? Кроме Firefox.
Будет здорово, если поделитесь.
savostin
10.10.2018 10:42А простые смертные (те, которые не могут себе позволить штат разработчиков, которые поставят ActivePerl, Php, Python, и кучу всего, разберутся как каждый компонент настроить, разберутся с такими советами, как отключение антивирусов, не обновлять WinCairo (!), «You may have to build twice before it works.» и т.д.) могут где-то получить замечательный WinCairo, чтоб вот как «этот уродский IE» взять и подключить к проекту одной строкой/dll'кой?
Sterpa
10.10.2018 17:08Расскажите пожалуйста, PeterG, чуть подробнее про решение НЕ в пользу
Chromium(Blink)
Первый и единственный не WebKit-подобный движок, который рассматривался как кандидат для решения задачи. Был отвергнут из-за больших различий в логике работы компонент для отрисовки HTML по сравнению с WebKitGTK+ и другой библиотеки для работы с JavaScript (V8).
Вроде бы считается, что движок V8 является одним из самых производительных для Javascript, а связка V8 + libuv позволяет реализовывать полноценный обмен с вешним миром, NODE.JS тому пример.
Что имеется в виду под «различиями в отрисовки HTML», которые оказались критичны для 1С, но с другой стороны создают конкурентное преимущество для Хрома?
И почему вы его называете не WebKit-подобным, хотя он основан на WebCore из WebKit?PeterG Автор
11.10.2018 10:05Главная причина отказа от Chromium в пользу WebKit была в том, что у WebKit для исполнения JavaScript используется библиотека JavaScriptCore, на основе которой у нас уже была реализована работа с DOM для Linux. Эту реализацию мы использовали в готовом виде для Windows и macOS, т.к. API у этой библиотеки для всех ОС одинаковый.
В случае с Blink, хотя за основу и была взята библиотека WebCore, далее движок развивался независимо. Поэтому WebKit выглядит предпочтительнее в смысле унификации поведения нашего клиента в разных ОС.
Blooderst
С какой версии 1С этот новый движек доступен?
PeterG Автор
8.3.14.
Спасибо за вопрос по делу, сейчас добавлю в статью.