How to use litehtml

Yuri Kobets edited this page Aug 30, 2018 · 6 revisions

How to use litehtml

To use litehtml you need some easy steps:

  1. Implement litehtml::document_container class.
  2. Prepare and load the master CSS.
  3. Call some functions from litehtml::document to parse, render and draw HTML text.

Implementing litehtml::document_container

The first step to integrate litehtml into your application is implementing abstract class litehtml::document_container. This class draw the HTML elements and perform some actions depended of the platform.

Load and draw HTML page

First you have to create litehtml::context object and load master CSS with litehtml::context::load_master_stylesheet function. Master CSS must contain the default styles for all HTML elements. See the master.css and example.

litehtml have 3 functions to render HTML document:

static litehtml::document::ptr createFromString(const tchar_t* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
static litehtml::document::ptr createFromUTF8(const char* str, litehtml::document_container* objPainter, litehtml::context* ctx, litehtml::css* user_styles = 0);
  • createFromString - creates litehtml::document from tchar_t string (null terminated)
  • createFromUTF8 - creates litehtml::document from utf-8 encoded string (null terminated)

On Linux the createFromString and createFromUTF8 are the same, because the tchar_t strings are assumed as utf-8 encoded string.

On Windows tchar_t strings are assumed as 2-bytes unicode (WCHAR) and you can use createFromUTF8 to load utf-8 encoded document.

If you prefer to use utf-8 on Windows for all strings, define LITEHTML_UTF8.

  • str - HTML code
  • objPainter - your implementation of litehtml::document_container
  • ctx - HTML context with master CSS
  • user_styles - optional user CSS (applied after all other styles)

createFromString returns the litehtml::document pointer. Call litehtml::document::render(max_width) to render HTML elements:

m_doc->render(max_width);

The parameter max_width usually the browser window width. Also render returns the optimal width for HTML text. You can use the returned value to render elements into the optimal width. This can be useful for tooltips.

Use height and width litehtml::document functions to find the width and height of the rendered document:

m_doc->height()
m_doc->width()

Now call draw function:

m_doc->draw(hdc, m_left, m_top, &clip);

draw accepts 4 parameters:

  • uint_ptr hdc - usually device context or something where to draw. For example HDC in windows. This parameter will be passed into all draw functions of litehtml::document_container.
  • int x, int y - position where to draw HTML.
  • const position* clip - clipping area. litehtml does not draw the elements that don't intersect the clipping rectangle. But note, you have to set your own clipping if you want to clip HTML content.

That's all! Your HTML page is painted!

Fit to the document

If you don't have the fixed size window to draw HTML, you need to get the HTML best width. It is very easy: document::render returns the best width for you.

So the example looks like this:

int best_width = m_doc->render(max_width);
if(best_width < max_width)
{
	m_doc->render(best_width);
}

First you render document with the maximum possible width and document::render returns the best width for HTML. If the best width is less then maximum width, you have to render your document with the returned best width. Now you can use document::width to get the actual document width.

You can use this technique to show HTML tooltips in your application or to create the HTML widgets.

Scrolling and Clipping

Scrolling of html document is released via x,y parameters of the document::draw function. For example, if you want to scroll document on 50px horizontally and 100px vertically:

m_doc->draw(hdc, -50, -100, litehtml::position(50, 100, window_width, window_height));

Note, the x and y parameters are screen relative. The clip parameter is always document relative. Also note, defining clip parameter in draw does not guarantee the valid clipping. Some elements can be drawn out off the clipping area. litehtml just checks if the element's bounding rectangle is intersected with clipping rectangle to draw elements. So you must implement your own clipping.

Handling the mouse

If you want to handle the mouse you have call some functions from litehtml::document:

bool litehtml::document::on_mouse_over( int x, int y, int client_x, int client_y, position::vector& redraw_boxes );
bool litehtml::document::on_mouse_leave( position::vector& redraw_boxes );
bool litehtml::document::on_lbutton_down( int x, int y, int client_x, int client_y, position::vector& redraw_boxes );
bool litehtml::document::on_lbutton_up( int x, int y, int client_x, int client_y, position::vector& redraw_boxes );

All functions returns the bool to indicate that you have to redraw the rectangles from redraw_boxes vector. Also note the x and y are relative to the HTML layout. So 0,0 is the top-left corner. The parameters client_x and client_y are the mouse position in the client area (draw area). These parameters are used to handle the elements with fixed position.

Processing anchor click

If you process the mouse, the clicking on anchor tag will calls the function document_container::on_anchor_click. This function gets the url of the anchor as parameter and pointer to litehtml::element. You can open the new document at this point.

NOTE: Don't delete the document inside document_container::on_anchor_click, this will cause the crash. The document_container::on_anchor_click is generated by document::on_lbutton_up, so it is safe to delete old document and show new one after document::on_lbutton_up is finished.

Processing named anchors

litehtml does not have the special handling of the named anchors. But it is easy to process the named anchors manually. You get the url with the anchor name into document_container::on_anchor_click. Just find the hash char (#) and extract the name. In the example below, the variable anchor_name contains the anchor name:

if(!anchor_name.empty())
{
	if(m_doc)
	{
		WCHAR selector[255];
		StringCchPrintf(selector, 255, L"#%s", anchor_name.c_str());
		element::ptr el = m_doc->root()->select_one(selector);
		if(!el)
		{
			StringCchPrintf(selector, 255, L"[name=%s]", anchor_name.c_str());
			el = m_doc->root()->select_one(selector);
		}
		if(el)
		{
			litehtml::position pos = el->get_placement();
			m_top = pos.y;
		}
	}
}

The function element::select_one returns the first element for the CSS selector. So select_one("#name") return the element with attribute id="name". el->get_placement() returns the absolute position of the element (document relative coordinates).

So, you have the position of the named anchor and now you can scroll your document into this position.

Images

litehtml does not cache the images. So if you want to increase the performance, you have to create your own images cache. Also you can implement the delayed images loading. Start image downloading in [#load_image load_image] function. If the image is not loaded return fake sizes and draw placeholder. When the image is loaded call litehtml::document::render, and redraw page.

Support for CSS media features

litehtml support CSS @media at-rule as well are media attribute in the <link> and <style> html tags. To make CSS media support you need:

  1. Implement document_container::get_media_features function and fill the media parameter with valid media features (like width, height etc.).
  2. Call document::media_changed function when any media feature is changed (for example user is changed the window size).
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.