As we all know, the newly open source “Hongmeng 2.0” uses JavaScript as the framework language for IoT application development. This marks the second time that JavaScript has enjoyed news coverage since the launch of SpaceX. It’s a shame to have a good opportunity like this. Instead of picking holes in the code with a magnifying glass, this article is intended to lay out in plain English what the GUI it supports really is. As long as you have a general understanding of the basic computer, you should not have trouble reading this article.
We already know that with “Hongman 2.0,” developers simply write JavaScript business logic in the form of a Vue component and render it as a UI on embedded hardware such as a smartwatch. What are the core modules involved in this process? Which of these modules are self-developed, and which use off-the-shelf open source projects? Here it is divided into three levels of abstraction from top to bottom:
- The JS framework layer can be understood as a substantially simplified Vue JavaScript framework
- The JS engine and runtime layer can be understood as a greatly simplified WebKit-style runtime
- Graphics rendering layer, can be understood as a greatly simplified Skia – style graphics rendering library
These three abstract layers, as a whole, constitute a set of embedded hardware oriented GUI technology stack. Different from many shout “unknown sense sharp/unfathom” public opinion, personally think that at least for GUI part, domestic who have contacted the current mainstream Hybrid cross-end solution or JS run time development of the first-line developers, are easy to understand it from the source code. The following layer by layer to do some interpretation and analysis.
JS framework layer
From the top level perspective, all you need to do to render dynamic text with HongMeng 2.0 is write the following HML (XML-like) format code:
<! -- hello.hml -->
<text onclick="boil">{{hello}}</text>
Copy the code
Then write JavaScript like this in the sibling directory:
// hello.js
export default {
data: {
hello: 'PPT'
},
boil() {
this.hello = 'Nuclear weapons'; }}Copy the code
So just clicking on the text calls the Boil method, making powerpoint a nuclear weapon.
What’s going on behind the scenes? Those familiar with Vue 2.0 should immediately think of the following:
- We need a preprocessing mechanism for XML to transform it into a nested function structure in JS. By doing a simple eval at run time, you can use JS to generate a UI that conforms to the XML structure.
- You need an event mechanism to trigger
onclick
Event can perform the corresponding callback. - Data hijacking mechanism is required to make the right
this.hello
The corresponding callback can be performed when the value is assigned. - You need to be able to update UI object controls in a callback.
How do these things work? Here’s the simple answer:
- XML preprocessingRely on ready-made NPM open source packages to put XML in
onclick
Property to a property field of a JS object. - Event registration and firingAre implemented directly by C++. The JS object obtained in the previous step
onclick
Properties are checked and registered in C++, equivalent to all components being native. - Data hijacking mechanismImplementation in JS is based on
Object.defineProperty
ViewModel of (hundreds of rows of magnitude). - Updates to UI controls, which calls the native C++ method implementation in the JS callback automatically executed by the ViewModel. This section is completely implicit and not open
document.createElement
Standard API of.
Since a lot of the capabilities in common JS frameworks are built directly into C++, So the whole GUI technology stack implemented in pure JavaScript (see core/index.js, observer.js, and Subject.js in ace_lite_jsfwk repository) has one function and only one:
A ViewModel to watch.
As for the complexity and quality of the implementation of the pure JS framework part, objectively speaking, if it is a personal amateur work, it can be regarded as a good plus in the college recruitment interview.
JS engine and runtime layer
After understanding the JS framework layer, we can either say that “hongmou2.0” chose to deeply customize the highly simplified Vue into C++, or that it implements a supporting front-end framework closely around the highly simplified (and private) DOM. So to continue exploring the principles of this GUI, we have to go into the C++ part of it and understand the implementation of its JS engine and runtime layer.
What are the differences and connections between the JS engine and the runtime? JS engines generally only need to comply with the ECMA-262 specification, which does not define any platform apis with “side effects”. From setTimeout to document.getelementByid to console.log to fs.readFile, the capabilities to perform actual IO operations are provided by runtimes that glue the engine API to the platform API. The mechanics of the runtime itself are not very complicated, for example, in my personal article from JS Engine to JS Runtime, you can see how to build your own runtime with the QuickJS engine already available.
So how is the JS runtime built in “Hongmeng 2.0”? Here are some key points:
- JS engine selected JerryScript, which is an embedded JS engine developed by Samsung.
- Each form such as
<text>
和<div>
XML tag components that correspond to a C++ Component class bound to JerryScript, such asTextComponent
和DivComponent
And so on. - In addition to UI native objects, there are also a series of UI native objects in JS
@system
Prefixed built-in modules that provide platform capabilities such as Router/Audio/File that are available in JS (seeohos_module_config.h
).
A special mention here is the Router. It is quite different from the common Web platform routes such as Vue-router, and is designed for deep customization at runtime (see Router_module. CPP, js_router. CPP, and js_page_state_machine.cpp). In a nutshell, this “routing” is implemented like this:
- To switch the page
router.replace
Native methods, enter C++. - C++ based on the new page URI path (e.g
pages/detail
) load a new page JS, create a new page state machine instance, and switch it to Init state. - In the Init process of the new state machine, the JS engine is called to eval the JS code of the new page to obtain the ViewModel of the new page.
- Append route parameters to the ViewModel and destroy the old state machine and its JS objects.
So we can see that what we call “switching routes” here is actually closer to “refreshing the page” in a Web browser. So can we consider this JS runtime capability to be comparable to webKit-level browser kernels?
Still far from it. Compared to WebKit, it doesn’t support parsing HTML and CSS (both of which are parsed and converted into equally executed JS during development), nor does it have the challenges of dynamically loading, parsing, and executing resources continuously in the browser (small programs are nothing more than a few local static JS files). There is also, of course, a big gap in typography and rendering, which will be covered in the last section.
In addition, I believe many students will be curious about the JerryScript engine. This section ends with some personal information.
The JerryScript engine is a JS interpreter specifically implemented for embedded hardware. It only supports ES5.1 standard. In QuickJS Benchmark, you can see the performance comparison results:
As you can see, JerryScript is substantially weaker than QuickJS and Hermes in terms of performance on jIT-free engines. It’s even two orders of magnitude slower than V8 with JIT on. So this is a very specific engine for low end devices, and you may still need to use a more powerful engine if you need to support the base libraries (or even their corresponding buckets) that are required for medium to large front-end projects like React and Vue.
As for the use of JerryScript, the founder of RT-Thread @midnight Bear has the same experience in the heavy application of the same scenario. The smartwatch developed by them and a domestic first-line manufacturer has implemented the UI with JerryScript, and the product will be released soon. Some of the team’s feedback on the use of JerryScript is consistent with these comments, which can be summarized as follows:
- JerryScript performs better than QuickJS in terms of size and memory footprint.
- JerryScript is less stable than QuickJS and has some problems that are hard to get around.
- JerryScript is struggling with a slightly larger (1M +) JS code base.
So are QuickJS and Hermes of Facebook the next generation of jit-free JS engines? Not necessarily. As TypeScript continues to grow in popularity, will there be runtimes that run TypeScript directly? Microsoft’s Static TypeScript, developed here for MakeCode, has the potential to be the next generation of high-performance JS language-based environments. By limiting TypeScript’s statically strongly typed subset and building a toolchain for it, STS can approach V8’s performance levels without JIT, while using two orders of magnitude less memory than V8. This enables STS to be used not only for IO intensive applications such as ordinary apps, but also for more computation-intensive applications such as small games that require frame by frame updates on embedded hardware. This is a major breakthrough in engineering capabilities.
So, ** While “Hung Moon 2.0” still required skilled developers to scrape together an environment to get through Hello World, Microsoft has enabled millions of kids to write introductory games in TypeScript on the Web for educational handheld consoles. ** No naysayers here, just a reminder that we should also be aware of what’s going on at the forefront of the industry while cheering for domestic “milestones”, that’s all.
Graphic rendering layer
After understanding the JS runtime, the last question left is how the various Component objects in the JS runtime are drawn as pixels on a device such as a watch.
This brings us to another Graphic_Lite repository in “Hung Mon 2.0.” You can think of this as the GUI that actually performs the actual drawing. Native components, like TextComponent before, will correspond to some kind of graphics library here, View. It is implemented in C++ layer in a fairly classic way and provides two sets of API systems, “Canvas style instant mode GUI” and “DOM style reserved mode GUI” (for the difference and connection between the immediate mode and reserved mode GUI, see the personal IMGUI popular answer). In summary, the main points of the graphics subsystem are as follows:
- The graphics library provides
UIView
The C++ control base class, which has a series of shapesOnClick
/OnLongPress
/OnDrag
Virtual function of. Basically every native Component class available in JS corresponds to a subclass of UIView. - In addition to various custom views, it also opens up a series of shapes
DrawLine
/DrawCurve
/DrawText
Such as imperative drawing method. - The graphics library has a GPU-accelerated module called GFX, but it seems to be only symbolic for now
FillArea
Rectangular monochrome filling ability.
In terms of basic UI controls, it’s not hard to find some self-developed module features worth mentioning:
- Supports the simplified RecycleView long list.
- Simple Flex layouts are supported.
- Supports an internal dirty Invalidate update mechanism.
As for the key capabilities in 2D UI rendering, there are basically three categories: paths, bitmaps, and text. This graphic library in these aspects have been involved in the last brief introduction.
For bitmaps, the library relies on libpng and libjpeg for image decoding, and then draws using in-memory bitmap images.
Then for the path, the graphics library itself to achieve a variety of CPU pixel drawing methods, a typical example of this is the bezier curve drawing source:
void DrawCurve::DrawCubicBezier(const Point& start, const Point& control1, const Point& control2, const Point& end,
const Rect& mask, int16_t width, const ColorType& color, OpacityType opacity)
{
if (width == 0 || opacity == OPA_TRANSPARENT) {
return;
}
Point prePoint = start;
for (int16_t t = 1; t <= INTERPOLATION_RANGE; t++) {
Point point;
point.x = Interpolation::GetBezierInterpolation(t, start.x, control1.x, control2.x, end.x);
point.y = Interpolation::GetBezierInterpolation(t, start.y, control1.y, control2.y, end.y);
if (prePoint.x == point.x && prePoint.y == point.y) {
continue;
}
DrawLine::Draw(prePoint, point, mask, width, color, opacity); prePoint = point; }}Copy the code
Based on high school math, it’s not hard to see how this curve is plotted: Interpolating a sufficient number of points (INTERPOLATION_RANGE at 1000), interpolating the XY coordinates of the curve expression point by point, and modifying the framebuffer memory at the pixel position. This textbook implementation is the most classic, but if you want to compare it to Skia’s dark magic, let’s not overdo it.
Finally for the text drawing, will involve some font parsing, positioning, RTL and line folding and other aspects of processing. This part is actually a combination of some industry common open source base library to achieve. For example, for the word “prison”, you can find several open source dependencies for graphics libraries, each of which plays a different role:
harfbuzz
– To tell the caller where to place the “secure” glyph.freetype
– Decoded “solid” Glyph from font files such as Song font, boldface font and raster them into pixels.icu
– Handles many strange special cases in Unicode, which I am not familiar with, so I will skip.
At this point, we can figure out a very general rendering process:
- JS to perform
this.hello = 'PPT'
To trigger dependency tracing. - JS relies on tracing callbacks to trigger native functions that update the state of C++ ‘s Component.
- Component updates the state of its bound UIView subclass, triggering the graphics library update.
- The graphics library updates the pixel state in memory to complete the drawing.
This is my personal interpretation of the “Hongmeng 2.0” GUI technology stack. Time is limited to dig further, and (civilised) criticism is welcome.
conclusion
Special note: This section is about the current GUI framework of “Hongmeng 2.0”. Please do not misinterpret it.
For the highlights of “Hongmeng 2.0” in the GUI section, I can think of the following:
- There is practical (but completely different from the powerpoint presentation) code.
- Instead of a WebView shell, the layout and drawing is done by yourself.
- You don’t need more than an undergraduate degree in computer science to be able to read and understand.
As for the obvious (not just some ugly lines of code) missing or problems, here are a few:
- JS framework layer
- There is no basic inter-component communication (e.g. Props/emit) capability
- There is no basic custom component capability
- There is no state management capability other than underlying dependency tracking
- JS engine and runtime layer
- Standard support is too low to run a proxy-required next generation front-end framework such as Vue 3.0
- The performance level is weak, and it is difficult to support medium and large JS applications
- The lack of an open DOM-style object model API doesn’t help smooth the differences
- Graphic rendering layer
- No actual GPU acceleration is available
- No advanced rendering capabilities such as SVG and rich text
- Canvas low completion, lack of state stack and lots of apis
That seems like a lot, but would you blame a car for not having a jet engine? For different complexity scenarios, there are naturally different optimal architectural designs. For now, the design is well suited for embedded hardware and simple “small programs” scenarios. But if you look at it in terms of “distributed, full-scene, cross-platform” terms, the complexity of this architecture is nothing compared to that of modern Web browsers or the GUIs of iOS and Android. It will almost certainly require a lot of additional complex modules, a lot of architectural evolution, and a lot of redesign if you want to implement it on mobile.
Of course, car companies don’t say they build planes, right?
In short, this is indeed a plate of self-made mapo tofu, but not some people in the population of manchu dinner.
And finally, personal subjective comments:
First, the GUI technology stack reaches a mainstream level of what is available when assembling and borrowing from open source products. But in terms of performance and performance limits, its core modules are still an order of magnitude away from cutting-edge industry-university-research solutions such as Microsoft’s MakeCode.
Second, don’t think of it as Rocket Science with a lot of expert precision — not to belittle indigenous research, but to really want people to understand, “This is something I can actually get involved in!” The operating system and GUI are not so mysterious. There are many domestic mature open source products for learning, using and contributing (rT-Thread, which is easy to experience and also domestic, is also recommended here as an early start). After all, the only way to avoid being beaten by someone with ulterior motives is to really understand what’s going on with a particular product, right?
Finally, for all the front-end developers who are familiar with JavaScript, ** why are you laughing at Hongqian? Hongmeng is JavaScript in China’s wealth password ah! **JavaScript is adopted by hongmeng, which can greatly enhance the confidence of the road, theory, culture and technology stack in the front end. As long as the combination of stitching and self-research in this form, you can win a high reputation in the whole country at one stroke. This road is really fascinating. (Whisper)
We should unite together, vigorously promote and promote the nuclear deterrent status of JavaScript in the competition between great powers, and strive to rise to the height where people will respect you as long as you say you can write JavaScript. As long as you are a front-end programmer, you can cut in line to buy a ticket, you can offer a seat in a bus, you can visit a white prostitute in a room… Good times, come!
Want to be a pillar of the nation? Write JavaScript!
No more talking. I’m off to work!