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

Возможность отображать 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 к этому времени стал источником ряда проблем.
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


Этот порт использует для графики библиотеку 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.

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С:Предприятия, обеспечивающие автоматическую поддержку прав доступа, управления функциональностью, адаптации к форм-фактору устройства, поддержку пользовательских настроек и работу многих других механизмов, без которых полноценная работа бизнес-приложения становится практически невозможной.

Комментарии (31)


  1. Blooderst
    09.10.2018 10:43

    С какой версии 1С этот новый движек доступен?


    1. PeterG Автор
      09.10.2018 10:49

      8.3.14.
      Спасибо за вопрос по делу, сейчас добавлю в статью.


  1. PeterG Автор
    09.10.2018 10:49

    Del


  1. fotov
    09.10.2018 10:51

    Когда планируется поддержка таблиц в форматированном документе?


  1. Elanor
    09.10.2018 11:01

    Примечание: Если у кого-нибудь в конфигурации использовался, например, разбор html-страницы c помощью объектной модели IE, то при переходе на новую версию платформы, такую конфигурацию надо будет доработать (перевести на модель WebKit).
    Возможно, таких конфигураций немного, но всё же…


  1. vanxant
    09.10.2018 11:24

    Один вопрос — вы все эти патчи при себе держите или хоть что-то в апстрим отправляете? Те же баги со вставкой под виндой или курсивом думаю у многих встречаются.


    1. PeterG Автор
      09.10.2018 11:50

      Пока держим при себе.
      Согласен, влить было бы хорошо, но пока руки не доходят.


  1. 9thlevel
    09.10.2018 11:52

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


    1. Taraflex
      10.10.2018 02:46

      del


  1. 9thlevel
    09.10.2018 12:02

    В форматированном документе, если работать с ним через веб-клиент, есть очень неприятная вещь — он теряет часть содержимого. Воспроизвести можно примерно следующим образом:

    1) Добавить на управляемую форму (скажем, справочника) группу страниц.
    2) Разнести элементы формы по разным страницам. При этом форматированный документ оставить на второй странице.
    3) В режиме «Предприятие» в веб-клиенте наполнить форматированный документ.
    4) Мышью переключиться на другую страницу и нажать CTRL+S.
    5) После записи объекта перейти на вкладку с форматированным документом. Текст или его часть будет отсутствовать.

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

    Пока проблему решили принудительной установкой фокуса на другой элемент формы при смене страницы.

    P.S. Платформа 8.3.11. Если не получится воспроизвести, могу скинуть видео.


    1. PeterG Автор
      09.10.2018 12:11

      Спасибо!
      Если не получится воспроизвести — запрошу у вас видео.


  1. iliabvf
    09.10.2018 12:35

    Спасибо, хорошие новости.
    Скажите а когда можно будет реализовать событие ПриНажатии в HTML поле в мобильном приложении?


    1. Neikist
      09.10.2018 12:44

      Тоже с ним проблемы? Оно вроде как есть, но у нас не работало. Хотя надо бы на последних версиях проверить, может починили.


      1. iliabvf
        09.10.2018 13:12

        Да мы перешли на последнюю ознакомительную мобильную 8.3.13, но проблема не решена.


        1. PeterG Автор
          11.10.2018 10:03

          Насколько помню, в мобильной платформе событие ПриНажатии происходит только если нажатие приводит к переходу на другую страницу. У вас нажатие приводит к переходу на другую страницу?


          1. iliabvf
            11.10.2018 12:10

            Спасибо попробуем!

            Пока что мы сильно не пользовались полем HTML в мобильной версии, т.к. при клике не срабатывало ПриНажатии.


            1. PeterG Автор
              12.10.2018 11:43

              Если что — пишите. Не работает — постараемся починить.


              1. iliabvf
                12.10.2018 11:46

                Уже попробовали, действительно работает.
                Спасибо, действительно чувствуется ускорение в решении проблем, что не может не радовать.


  1. unxed
    09.10.2018 20:28

    А можно, пожалуйста, исправленный код поддержки вставки пулл-реквестом в вебкит и, по возможности, блинк? Спасибо!


    1. PeterG Автор
      10.10.2018 09:33

      Как дойдут у разработчиков руки — вольем. Но обычно разработчики у нас сильно загружены :(


      1. paluke
        10.10.2018 10:07

        А исходники этой доработанной версии WebKit где-то доступны?


        1. PeterG Автор
          10.10.2018 12:18

          Пока нет.
          К выпуску версии 8.3.14 (ориентировочно — конец 2018 г.) планируем выложить исходники WebKit с нашими доработками здесь: github.com/1C-Company-third-party


  1. fishca
    09.10.2018 23:42

    с версии 8.3.14 (релиз — конец 2018 г.)

    Ничего не перепутали? Конец 2018 года это же релиз 8.3.13 или же все таки к концу года и 8.3.14 ждать еще?


    1. vkar
      10.10.2018 05:15

      8.3.13 уже опубликована


  1. istepan
    10.10.2018 06:47

    Есть еще пятый вариант: Gecko


    1. ziv2012
      10.10.2018 15:37

      Где можно найти инструкцию по использованию Gecko?


    1. PeterG Автор
      10.10.2018 15:39

      Совершенно верно. Я даже его на картинке нарисовал :)
      Но Gecko у нас отвалился на ранней стадии рассмотрения, причину уже и не вспомню.
      А у вас есть пример удачного использования Gecko? Кроме Firefox.
      Будет здорово, если поделитесь.


  1. savostin
    10.10.2018 10:42

    А простые смертные (те, которые не могут себе позволить штат разработчиков, которые поставят ActivePerl, Php, Python, и кучу всего, разберутся как каждый компонент настроить, разберутся с такими советами, как отключение антивирусов, не обновлять WinCairo (!), «You may have to build twice before it works.» и т.д.) могут где-то получить замечательный WinCairo, чтоб вот как «этот уродский IE» взять и подключить к проекту одной строкой/dll'кой?


    1. PeterG Автор
      10.10.2018 15:44

      Даже не знаю. Нам пришлось пройти длинным путем.


  1. 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?


    1. PeterG Автор
      11.10.2018 10:05

      Главная причина отказа от Chromium в пользу WebKit была в том, что у WebKit для исполнения JavaScript используется библиотека JavaScriptCore, на основе которой у нас уже была реализована работа с DOM для Linux. Эту реализацию мы использовали в готовом виде для Windows и macOS, т.к. API у этой библиотеки для всех ОС одинаковый.
      В случае с Blink, хотя за основу и была взята библиотека WebCore, далее движок развивался независимо. Поэтому WebKit выглядит предпочтительнее в смысле унификации поведения нашего клиента в разных ОС.