HTML engine integration into native Windows application - choice and architecture
How we translated work with HTML in 1C: Enterprise from Internet Explorer to WebKit The
ability to display HTML in 1C forms appeared in the 1C: Enterprise platform in 2003, version 8.0. To work with HTML, the platform used the browser engine Internet Explorer (1C: Enterprise at that time worked only under Windows). The browser engine was used by the platform for utilitarian purposes. For example, to write from scratch a full-fledged element for editing text a la Word - with the possibility of various color and font solutions, insert pictures, etc. - a very difficult task. And if you use HTML for these purposes and use the Internet browser engine as a display tool, the task is greatly simplified. Also, a number of other mechanisms were implemented using the engine (for example, mappingreference information ) and items (e.g. Scheduler ).
Well, the ability for application developers to display using HTML custom design by the standards of the world of accounting systems sometimes made it possible to bring a variety of pleasant highlights to the interface of business applications.
As time passed, the platform began to support Linux first, and then macOS. Internet Explorer was not suitable for working with HTML in these OSs for obvious reasons; on Linux, we used WebKitGTK + , and on macOs, a Cocoa- based library . Thus, the unity of the code base for different operating systems (which we try to maintain for the client code at the level of 95%) was violated in this area. Well, the IE engine by this time has become the source of a number of problems.
Problems:
So, the translation of working with HTML in version 1C: Enterprise for Windows from the IE engine to something else was obvious. What to choose?
To begin with, we formulated the requirements for the engine:
What to choose from? We started, of course, with WebKit , with which we already worked in versions of the platform for Linux and macOS.
WebKit was developed at Apple in the early 2000s based on the open source engines KHTML and KJS . Based on WebKit, the Safari browser was created, later - Chrome (even later Chrome switched from WebKit to Blink , which again is based on WebCore code from WebKit).
The source code for WebKit is open source and licensed under the LGPL . WebKit is written for macOS, there are several ports for Windows:
This is the port that WebKit developers suggest building under Windows by default. It was made by Apple employees in the mid-to-late 2000s. It uses the CoreGraphics graphics library , which is a simplified version of the library for macOS, ported to Windows. To execute JavaScript, the port uses the JavaScriptCore library with the same API that is used in the implementation of the platform for Linux. This makes it a prime candidate for use.
This port uses the Cairo library for graphics . For some time, Apple has been actively developing this port as an analogue to the main AppleWin port. The advantage of this port is that it is less dependent on the macOS-specific libraries that CoreGraphics requires. In addition, the port uses the same library for graphics ( Cairo ) as the WebKitGTK + engine, which we use in the Linux implementation of the platform, which is good for standardizing the behavior of our code.
Another implementation of the WebKit engine for Windows, now independent of the developers of the engine itself. Qt is a popular cross-platform library with its own QtGui graphics library. This port also uses the JavaScriptCore library to handle JavaScript, however it does have disadvantages:
We have already used WebKitGtk + in the Linux version of the platform. But the option to use it in Windows was ruled out due to the complexity of the assembly, poor documentation of this process and the lack of constant support for this development area from the developers of WebKitGTK +.
The first and only non-WebKit-like engine, which was considered as a candidate for solving the problem. It was rejected due to large differences in the logic of the components for rendering HTML compared to WebKitGTK + and another library for working with JavaScript ( V8 ).
After research, AppleWin and WinCairo reached the finals.
To make the final choice, we studied how WebKit works.
Typically, different WebKit ports differ in two ways. The first is directly the implementation for a particular OS using OS-specific components. The second is a graphics library. The figure below describes the differences in this sense between WebKit ports. For Windows, WebKit developers wrote ports on the adapted CoreGraphics and Cairo library.
A simplified model of the engine: three traditional mechanisms for formatting a web page - HTML, JavaScript and CSS - are fed to the engine, and it forms and displays the page from them:
The engine itself consists of several components:
The relationship between WebKit components and OS-specific features is shown in the figure below. As you can see, there are quite a few specific points that need to be implemented for each OS separately. Although JavaScriptCore allows you to use yourself in each port without separate implementations.
From the network, a response comes to a request to the server with data to download. The loader passes the data to the parser, which, interacting with the component for JavaScript, forms the DOM and style sheet. Next, the generated data is transferred to the rendering tree and displayed in a graphical context.
The page itself also consists of individual components. The WebCore component implements the Page class, which allows access to the entire page. Page has a main frame - MainFrame, a frame always has a document. The main frame can have any number of other frames, also with documents inside. For each frame, some events are formed separately, as well as specific graphic and JavaScript contexts.
Simplified HTML parser works like this. From the set of bytes received from the server, the decoder generates a set of characters for parsing. Symbols are converted to tokens or tokens, which are usually elementary pieces of code with meta-information about what kind of text it is, whether it is part of the language syntax or content. Then nodes are formed from tokens to build a DOM tree. A tree builder from a set of nodes forms a complete object model for a web page document.
Defeated WinCairo. For development, the latest version of WebKit available at that time was taken - 605.1.11.
Although the engine is pretty well covered by unit tests (about 30,000 for all components of the engine, written by the authors of the engine), there are errors and shortcomings in implementations for “non-core” OSs (that is, for everything that is not macOS). These implementation gaps were gradually discovered as the engine was developed and tested as part of the 1C: Enterprise platform.
When dragging text into the window, it was found that if the text being dragged contains non-ASCII characters, then hieroglyphs are inserted into the final document. The error appeared only in the Windows implementation of the engine, because it worked with an OS-specific mechanism for dragging and dropping elements. It turns out that the text was not decoded from UNICODE to UTF-16 before being passed to the insert event handler.
In most text editors (including Microsoft Word), this combination inserts a line break. The standard behavior of WebKit is to insert a new paragraph (as if simply pressing Enter). We changed the engine, making the behavior more familiar to users.
WebKit provides an API for implementing its own mechanism for canceling and repeating user actions. Its scheme is as follows: when the user performs a certain action discrete from the point of view of the engine (for example, switching to a new paragraph, formatting in italics, pasting), WebKit informs the developer about this using the API so that he can register this action.
In the process of testing the implemented mechanism, an unpleasant thing was found out: the engine does not report changes in the structure of the tables. Commands for adding and removing cells and changing the colSpan attribute were added, which became part of composite actions, such as, for example, adding / removing a column or a table row. Such composite commands are registered in the same undo & redo stack, and together with the commands from the engine ensure the correct operation of the mechanism.
Those who worked with the Windows and Excel clipboard may know that, firstly, when copying from Excel to HTML, the clipboard format in the copied fragment contains only the tags of the cells and rows, but not the tag of the table itself, and secondly, styles from an Excel document are not transferred to cells. Because of this, inserting, for example, a color table into an editable element in Chrome looks like this:
Original:
In Chrome:
WebKit developers did not take both of these factors into account. The openness of the engine code allowed us to refine the insertion mechanism, and now the fragment of the table inserted into the HTML field of the Document is close to the original:
If Windows does not have an italic version of a non-standard font, most text editors can generate such a font using its regular version. However, WebKit did not know this and a couple of times led the developers astray: how is it that in the HTML code of the document we put the text in the tag , but despite this the text remained straight. The reason is that the WebKit engine selects the right font in the WinCairo port we use - if there is no italic version, the engine uses the regular version. This behavior has been replaced by the use of the italic font generated by the Cairo graphics library.
Errors in the behavior of the engine when working with graphic elements were found. When loading some images in PNG format, image distortion was observed, and sometimes its absence at all. It was not possible to find out the reason for this behavior, since an error occurs when decoding images in the bowels of the libpng library.
Empirically, it was found that when linking the libpng library in a dynamic way instead of a static one, the problem is fixed. By the way, in the current version of the engine, linking is done in this way. It was decided to do the same.
Another problem was the engine when loading animations in GIF format. The error was periodically reproduced when loading the page with such animations and led to the crash of the program. The error was caused by the lack of synchronization when working with the buffer into which the next frame of the animation is placed. The problem was resolved using internal WebKit synchronization tools.
In the assembly with Internet Explorer, in Windows version 8 and later, the spellcheck could be enabled for the HTML editable field. To do this, it was enough to attribute "spellcheck" equal to "true". WebKit had different solutions for different ports: on Linux it is the Enchant library , on macOS it has its own mechanism familiar to all users of Apple products. But for Windows there is no implementation, but an API is provided for its own solution. We used the Windows Spell Checking API , available starting with Windows 8, and implemented a mechanism similar to the build with Internet Explorer. By the way, now in a formatted document in native 1C: Enterprise clients this functionality also works. Prior to version 8.3.14, it was disabled due to poor Internet Explorer performance.
Some of our clients still work on Windows XP, and are not going to upgrade the OS in the near future. Sad for us as developers, but true. So - we need to support them. And here we had an unpleasant surprise: WebKit developers for about a year have not supported the engine in WinXP. An attempt to build a version of the engine with a set of build tools for WinXP was unsuccessful - WebKit developers use libraries that are available only with versions of Windows Vista and later.
What to do? The options were as follows:
The question was not simple. The first option allowed you to use the latest version of the WebKit engine, but would force you to return the old implementation with Internet Explorer. In such a solution, it would be difficult to ensure error-free operation of the program, and the code itself would be very complicated. The second option provided the same behavior on all Windows OSs, however, it would not leave us the opportunity for development - updating the engine to fix errors and getting new features from the developers of the engine in later versions. The third option allowed using the current version of the engine in older versions of Windows, but greatly complicated the installation logic and ensuring the same version behavior in all OSs. The fourth option looked preferable to all the others, but it was impossible to predict the complexity and in general the possibility of such a solution.
Nevertheless, we decided to take a chance and implement the fourth option, the most correct from an architectural point of view (using a single engine source code on all versions of Windows). The ported version of WebKit works differently in WinXP and newer versions of Windows:
So, now in our 1C: Enterprise platform starting from version 8.3.14 (release - end of 2018) HTML will be supported at the highest level - HTML5, OpenGL, etc. Both the quantity and quality of the raisins that can be brought into decisions on our platform are limited only by the developer's imagination. And yet, of course, the client’s operating system - on WinXP, many tasty HTML5 buns will not work, for obvious reasons.
Now on Windows applications on the 1C: Enterprise platform will be able to show this:
But, using the "goodies" of HTML in application solutions, do not forget common sense. Using HTML is appropriate and recommended for specialized tasks (displaying help, techniques, product descriptions, ...), but not for implementing business logic tasks (input / output of structured information). To do this, you need to use the standard 1C: Enterprise interface mechanisms that provide automatic support for access rights, functionality management, adaptation to the device form factor, support for user settings, and the work of many other mechanisms, without which the full-fledged operation of a business application becomes almost impossible.
ability to display HTML in 1C forms appeared in the 1C: Enterprise platform in 2003, version 8.0. To work with HTML, the platform used the browser engine Internet Explorer (1C: Enterprise at that time worked only under Windows). The browser engine was used by the platform for utilitarian purposes. For example, to write from scratch a full-fledged element for editing text a la Word - with the possibility of various color and font solutions, insert pictures, etc. - a very difficult task. And if you use HTML for these purposes and use the Internet browser engine as a display tool, the task is greatly simplified. Also, a number of other mechanisms were implemented using the engine (for example, mappingreference information ) and items (e.g. Scheduler ).
Well, the ability for application developers to display using HTML custom design by the standards of the world of accounting systems sometimes made it possible to bring a variety of pleasant highlights to the interface of business applications.
As time passed, the platform began to support Linux first, and then macOS. Internet Explorer was not suitable for working with HTML in these OSs for obvious reasons; on Linux, we used WebKitGTK + , and on macOs, a Cocoa- based library . Thus, the unity of the code base for different operating systems (which we try to maintain for the client code at the level of 95%) was violated in this area. Well, the IE engine by this time has become the source of a number of problems.
Problems:
- The IE engine has closed source code - it means:
- Flexible adjustment of the engine to the needs of the platform is not possible
- Debugging and understanding of processes inside
- Cannot fix bugs and errors by updating engine version
- The engine is not suitable for the implementation of modern web programming tasks
- Performance Issues on Weak Machines
So, the translation of working with HTML in version 1C: Enterprise for Windows from the IE engine to something else was obvious. What to choose?
To begin with, we formulated the requirements for the engine:
- Support for modern web programming technologies
- Open source for flexible customization of the engine and understanding of its logic
- High performance on slower computers
- It is desirable that the engine require a small number of third-party libraries to work
Engine selection
What to choose from? We started, of course, with WebKit , with which we already worked in versions of the platform for Linux and macOS.
WebKit was developed at Apple in the early 2000s based on the open source engines KHTML and KJS . Based on WebKit, the Safari browser was created, later - Chrome (even later Chrome switched from WebKit to Blink , which again is based on WebCore code from WebKit).
The source code for WebKit is open source and licensed under the LGPL . WebKit is written for macOS, there are several ports for Windows:
WebKit AppleWin
This is the port that WebKit developers suggest building under Windows by default. It was made by Apple employees in the mid-to-late 2000s. It uses the CoreGraphics graphics library , which is a simplified version of the library for macOS, ported to Windows. To execute JavaScript, the port uses the JavaScriptCore library with the same API that is used in the implementation of the platform for Linux. This makes it a prime candidate for use.
WebKit WinCairo
This port uses the Cairo library for graphics . For some time, Apple has been actively developing this port as an analogue to the main AppleWin port. The advantage of this port is that it is less dependent on the macOS-specific libraries that CoreGraphics requires. In addition, the port uses the same library for graphics ( Cairo ) as the WebKitGTK + engine, which we use in the Linux implementation of the platform, which is good for standardizing the behavior of our code.
QtWebKit
Another implementation of the WebKit engine for Windows, now independent of the developers of the engine itself. Qt is a popular cross-platform library with its own QtGui graphics library. This port also uses the JavaScriptCore library to handle JavaScript, however it does have disadvantages:
- Strong dependence on the main components of Qt, which, if used in third-party software, will need to be delivered with it
- A different set of interfaces for working with components for rendering HTML compared to WebKitGTK and its own logic for working with them.
WebKitGtk + for Windows
We have already used WebKitGtk + in the Linux version of the platform. But the option to use it in Windows was ruled out due to the complexity of the assembly, poor documentation of this process and the lack of constant support for this development area from the developers of WebKitGTK +.
Chromium (Blink)
The first and only non-WebKit-like engine, which was considered as a candidate for solving the problem. It was rejected due to large differences in the logic of the components for rendering HTML compared to WebKitGTK + and another library for working with JavaScript ( V8 ).
What to choose?
After research, AppleWin and WinCairo reached the finals.
To make the final choice, we studied how WebKit works.
WebKit Engine Structure
Typically, different WebKit ports differ in two ways. The first is directly the implementation for a particular OS using OS-specific components. The second is a graphics library. The figure below describes the differences in this sense between WebKit ports. For Windows, WebKit developers wrote ports on the adapted CoreGraphics and Cairo library.
A simplified model of the engine: three traditional mechanisms for formatting a web page - HTML, JavaScript and CSS - are fed to the engine, and it forms and displays the page from them:
The engine itself consists of several components:
- WTF (Web Template Framework, not what you might have thought ): here you find your own implementations of data structures for the functioning of the engine, as well as work with streams
- JavaScriptCore: a component, as the name implies, for working with the JavaScript language
- WebCore: all work with DOM, styles, HTML and XML parsing is written here. All the main “magic” of the engine is done here.
- Platform: performs technical actions for interacting with the network, placing data in a database, decoding images, working with media
- WebKit and WebKit2 API - linking all components and providing access to them
The relationship between WebKit components and OS-specific features is shown in the figure below. As you can see, there are quite a few specific points that need to be implemented for each OS separately. Although JavaScriptCore allows you to use yourself in each port without separate implementations.
How a web page is formed
From the network, a response comes to a request to the server with data to download. The loader passes the data to the parser, which, interacting with the component for JavaScript, forms the DOM and style sheet. Next, the generated data is transferred to the rendering tree and displayed in a graphical context.
The page itself also consists of individual components. The WebCore component implements the Page class, which allows access to the entire page. Page has a main frame - MainFrame, a frame always has a document. The main frame can have any number of other frames, also with documents inside. For each frame, some events are formed separately, as well as specific graphic and JavaScript contexts.
Simplified HTML parser works like this. From the set of bytes received from the server, the decoder generates a set of characters for parsing. Symbols are converted to tokens or tokens, which are usually elementary pieces of code with meta-information about what kind of text it is, whether it is part of the language syntax or content. Then nodes are formed from tokens to build a DOM tree. A tree builder from a set of nodes forms a complete object model for a web page document.
Final choice
- Applewin
- Pros:
- Implemented on a graphics library that runs on macOS - the main target platform for WebKit developers
- Minuses:
- Lack of implementation of the printing mechanism
- A large number of dependencies
- Pros:
- Wincairo
- Pros:
- The same graphics library (Cairo), as used in the Linux port of the 1C platform
- Minuses:
- Essential for our tasks not found
- Pros:
Defeated WinCairo. For development, the latest version of WebKit available at that time was taken - 605.1.11.
Implementation
Although the engine is pretty well covered by unit tests (about 30,000 for all components of the engine, written by the authors of the engine), there are errors and shortcomings in implementations for “non-core” OSs (that is, for everything that is not macOS). These implementation gaps were gradually discovered as the engine was developed and tested as part of the 1C: Enterprise platform.
Download HTML via Drag & Drop
When dragging text into the window, it was found that if the text being dragged contains non-ASCII characters, then hieroglyphs are inserted into the final document. The error appeared only in the Windows implementation of the engine, because it worked with an OS-specific mechanism for dragging and dropping elements. It turns out that the text was not decoded from UNICODE to UTF-16 before being passed to the insert event handler.
Change Shift + Enter Keyboard Behavior
In most text editors (including Microsoft Word), this combination inserts a line break. The standard behavior of WebKit is to insert a new paragraph (as if simply pressing Enter). We changed the engine, making the behavior more familiar to users.
Organization of the Undo & Redo mechanism.
WebKit provides an API for implementing its own mechanism for canceling and repeating user actions. Its scheme is as follows: when the user performs a certain action discrete from the point of view of the engine (for example, switching to a new paragraph, formatting in italics, pasting), WebKit informs the developer about this using the API so that he can register this action.
In the process of testing the implemented mechanism, an unpleasant thing was found out: the engine does not report changes in the structure of the tables. Commands for adding and removing cells and changing the colSpan attribute were added, which became part of composite actions, such as, for example, adding / removing a column or a table row. Such composite commands are registered in the same undo & redo stack, and together with the commands from the engine ensure the correct operation of the mechanism.
Paste from Excel
Those who worked with the Windows and Excel clipboard may know that, firstly, when copying from Excel to HTML, the clipboard format in the copied fragment contains only the tags of the cells and rows, but not the tag of the table itself, and secondly, styles from an Excel document are not transferred to cells. Because of this, inserting, for example, a color table into an editable element in Chrome looks like this:
Original:
In Chrome:
WebKit developers did not take both of these factors into account. The openness of the engine code allowed us to refine the insertion mechanism, and now the fragment of the table inserted into the HTML field of the Document is close to the original:
Italic font generation
If Windows does not have an italic version of a non-standard font, most text editors can generate such a font using its regular version. However, WebKit did not know this and a couple of times led the developers astray: how is it that in the HTML code of the document we put the text in the tag , but despite this the text remained straight. The reason is that the WebKit engine selects the right font in the WinCairo port we use - if there is no italic version, the engine uses the regular version. This behavior has been replaced by the use of the italic font generated by the Cairo graphics library.
Errors in decoding images and animations
Errors in the behavior of the engine when working with graphic elements were found. When loading some images in PNG format, image distortion was observed, and sometimes its absence at all. It was not possible to find out the reason for this behavior, since an error occurs when decoding images in the bowels of the libpng library.
Empirically, it was found that when linking the libpng library in a dynamic way instead of a static one, the problem is fixed. By the way, in the current version of the engine, linking is done in this way. It was decided to do the same.
Another problem was the engine when loading animations in GIF format. The error was periodically reproduced when loading the page with such animations and led to the crash of the program. The error was caused by the lack of synchronization when working with the buffer into which the next frame of the animation is placed. The problem was resolved using internal WebKit synchronization tools.
Spelling support
In the assembly with Internet Explorer, in Windows version 8 and later, the spellcheck could be enabled for the HTML editable field. To do this, it was enough to attribute "spellcheck" equal to "true". WebKit had different solutions for different ports: on Linux it is the Enchant library , on macOS it has its own mechanism familiar to all users of Apple products. But for Windows there is no implementation, but an API is provided for its own solution. We used the Windows Spell Checking API , available starting with Windows 8, and implemented a mechanism similar to the build with Internet Explorer. By the way, now in a formatted document in native 1C: Enterprise clients this functionality also works. Prior to version 8.3.14, it was disabled due to poor Internet Explorer performance.
Windows XP support
Some of our clients still work on Windows XP, and are not going to upgrade the OS in the near future. Sad for us as developers, but true. So - we need to support them. And here we had an unpleasant surprise: WebKit developers for about a year have not supported the engine in WinXP. An attempt to build a version of the engine with a set of build tools for WinXP was unsuccessful - WebKit developers use libraries that are available only with versions of Windows Vista and later.
What to do? The options were as follows:
- Leave WinXP implementation with Internet Explorer engine, and use WebKit in older versions of Windows
- Take for development an earlier version of the WebKit engine, which works in WinXP, and use this version in all OS
- Use the appropriate version of WebKit in WinXP, and use the latest engine in older versions of Windows
- Port the current version of the engine to WinXP yourself and use it everywhere
The question was not simple. The first option allowed you to use the latest version of the WebKit engine, but would force you to return the old implementation with Internet Explorer. In such a solution, it would be difficult to ensure error-free operation of the program, and the code itself would be very complicated. The second option provided the same behavior on all Windows OSs, however, it would not leave us the opportunity for development - updating the engine to fix errors and getting new features from the developers of the engine in later versions. The third option allowed using the current version of the engine in older versions of Windows, but greatly complicated the installation logic and ensuring the same version behavior in all OSs. The fourth option looked preferable to all the others, but it was impossible to predict the complexity and in general the possibility of such a solution.
Nevertheless, we decided to take a chance and implement the fourth option, the most correct from an architectural point of view (using a single engine source code on all versions of Windows). The ported version of WebKit works differently in WinXP and newer versions of Windows:
- I had to abandon the tools of the new DirectX (d3d11) in favor of the old DirectX9 (d3d9) and adapt its header files to the younger version of the SDK.
- Functions from the new SDK, when executed on new versions of Windows, are called at the address (obtained through GetProcAddress ).
- For transferring data between streams in the engine, WinXP uses Thread local storage, in new versions - Fiber local storage.
Total
So, now in our 1C: Enterprise platform starting from version 8.3.14 (release - end of 2018) HTML will be supported at the highest level - HTML5, OpenGL, etc. Both the quantity and quality of the raisins that can be brought into decisions on our platform are limited only by the developer's imagination. And yet, of course, the client’s operating system - on WinXP, many tasty HTML5 buns will not work, for obvious reasons.
Now on Windows applications on the 1C: Enterprise platform will be able to show this:
But, using the "goodies" of HTML in application solutions, do not forget common sense. Using HTML is appropriate and recommended for specialized tasks (displaying help, techniques, product descriptions, ...), but not for implementing business logic tasks (input / output of structured information). To do this, you need to use the standard 1C: Enterprise interface mechanisms that provide automatic support for access rights, functionality management, adaptation to the device form factor, support for user settings, and the work of many other mechanisms, without which the full-fledged operation of a business application becomes almost impossible.