Using animated emoticons in IM is a very interesting way, but it's not easy to choose the right way to do it.
In general, in addition to implementing a rich text control yourself, there are currently 3 main solutions:
1, use the browser to do the container.
2. Use the RichText provided by QT to make containers.
3, use RichEdit to do containers.
Using the browser to do container benefits is simple to use, the efficiency should also be good (no test, just feel), the disadvantage is also obvious: memory consumption is too high, dependent on the browser kernel. Based on IE kernel does not need to take a large installation package, but IE kernel problems, there are problems difficult to solve; WebKit kernel Although open source, but the size of big pet.
The RichText to use QT requires that the program is based on QT development, such as yy voice. QT is still too big for normal client programs, and the RichText in Qt can be slightly thinner than the RichEdit in Windows.
Here we focus on the third approach, which is also widely used in major IM: animating emoticons based on the way RichEdit is inserted into an OLE object.
At present, the realization of QQ in the animation expression refresh efficiency should be the highest, you can see QQ from the historical version has been insisted on using RichEdit to display the chat content.
The advantages of using RichEdit are many, compared with the browser, such as small size, memory footprint, efficiency can be very high after the appropriate optimization (QQ in the animation should be the most important), and QT RichText than the need to rely on QT (this is limited to the Windows platform), Feature-rich, and MS is also constantly rolling out new versions.
Although the use of RichEdit in QQ display animation expression performance is good, but not just any client developers simply implement an OLE object can be achieved. What kind of performance can be achieved depends on the final optimization of the skill.
Said so much, dry out ...
We know that RichEdit is a container for an OLE object. By implementing a new OLE object yourself, you can implement a self-painted image in RichEdit and, of course, include emoticons.
Animations are moved to refresh these OLE objects.
To refresh an OLE object, you first need to know the location of the OLE object.
There are two ways to get the object position in my opinion:
1, each time to RichEdit to find their own location (such as this blog on the previous article provides a similar method).
2. Caches the object's drawing position in the OLE object's OnDraw function.
When the number of expressions displayed in the container is relatively small, such as <100, then the first method is simple and effective, but when the display of a lot of objects (such as a full screen of small animation, >1000), although the use of two points to query coordinates, CPU consumption is not simple.
The second method is straightforward, because the object is inserted to display, a display container will call the OLE OnDraw method to draw the OLE object, where the parameters have a display location, just at this point to cache the location, do not need to query every time. But the problem also comes, this method only know who wants to show, do not know who does not show, then those who do not need to display the expression of the timer how to deal with it?
The answer to this question is a message sent by RichEdit on refresh: En_update. The message will be send by RichEdit to the application before RichEdit each time it is drawn. With this message, we can erase the hidden expression timer when the window is refreshed.
Our choice has already been made, that is, the direct caching of the expression coordinates.
With coordinates, how to refresh the expression regularly?
There are two ways of refreshing an object:
1, through the InvalidateRect to refresh the position of the RichEdit expression.
2. Draw a new expression frame directly in the RichEdit in the display position.
If you display only a small amount of emoticons at the same time, there is no problem with which method. Here to solve the problem of a large number of small expressions refresh (such as >1000), this time the dirty rectangle even become meaningless, basically is the entire window of the refresh.
Since the whole window is refreshed, will it be different to use invalidaterect and draw yourself?
Before yesterday I had not believed in such a brutal realization: RichEdit is very inefficient when refreshing a full screen of small animations, so low that you can't stand it (single-core CPUs can account for 100%). Looked for a long time have not understood where the bottleneck.
After continuous troubleshooting, the final location to the RichEdit rendering problem: When the OLE objects are many, RichEdit on a 1920*1020 screen to refresh the small expression animation once to use about 200ms (CPU I5, 2.3G). By compiling a copy of the RichEdit source used on the wince on the web and running it, using Intel's VTune analysis performance bottleneck, the RichEdit is a string, and each RichEdit object is represented by 0xFFFE in this string. To draw this OLE object, RichEdit needs to go to an OLE list to query which OLE object points to the index of the current 0xFFFE, although the query uses a two-point method to query the OLE object's pointer, which is still very inefficient when the number of objects is large (assuming that 1024 objects are displayed , show an average query 10 times, then you need to 1024*10 the query).
Locating the bottleneck the answer is obvious, it is not appropriate to update the OLE object by drawing the RichEdit directly, and the rest is to draw the expression yourself.
The expression needs to be related to the choice of expression, background, and other things do not need to update the details of the tailoring of the problem, only need to do appropriate processing.
The following is a soui to insert a large number of small expressions and insert a large number of small expressions in QQ CPU occupancy comparison:
1920x1080: Soui occupies 3, QQ occupies 19%. (No machines around, no)
1366*768:soui occupies 0, QQ occupies 8% (see).
Soui. DEMO
Qq
Implementation of a method to quickly refresh embedded animation in RichEdit