forked from qt-creator/qt-creator
QLitehtml: Make container_qpainter usable without litehtml internals
We use it elsewhere to "paint" html to a printer (for generating a PDF). It is much easier if we don't need to pull litehtml internals into that. Change-Id: I447fa5442f02a6b5e84524f82089513f0c569939 Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
@@ -35,7 +35,7 @@ add_qtc_library(qlitehtml
|
||||
PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
SOURCES
|
||||
container_qpainter.cpp container_qpainter.h
|
||||
container_qpainter.cpp container_qpainter.h container_qpainter_p.h
|
||||
qlitehtml_global.h
|
||||
qlitehtmlwidget.cpp qlitehtmlwidget.h
|
||||
)
|
||||
|
@@ -24,6 +24,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "container_qpainter.h"
|
||||
#include "container_qpainter_p.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QCursor>
|
||||
@@ -440,16 +441,18 @@ QRect Selection::boundingRect() const
|
||||
return rect;
|
||||
}
|
||||
|
||||
DocumentContainer::DocumentContainer() = default;
|
||||
DocumentContainer::DocumentContainer()
|
||||
: d(new DocumentContainerPrivate)
|
||||
{}
|
||||
|
||||
DocumentContainer::~DocumentContainer() = default;
|
||||
|
||||
litehtml::uint_ptr DocumentContainer::create_font(const litehtml::tchar_t *faceName,
|
||||
int size,
|
||||
int weight,
|
||||
litehtml::font_style italic,
|
||||
unsigned int decoration,
|
||||
litehtml::font_metrics *fm)
|
||||
litehtml::uint_ptr DocumentContainerPrivate::create_font(const litehtml::tchar_t *faceName,
|
||||
int size,
|
||||
int weight,
|
||||
litehtml::font_style italic,
|
||||
unsigned int decoration,
|
||||
litehtml::font_metrics *fm)
|
||||
{
|
||||
const QStringList splitNames = QString::fromUtf8(faceName).split(',', Qt::SkipEmptyParts);
|
||||
QStringList familyNames;
|
||||
@@ -515,23 +518,23 @@ litehtml::uint_ptr DocumentContainer::create_font(const litehtml::tchar_t *faceN
|
||||
return reinterpret_cast<litehtml::uint_ptr>(font);
|
||||
}
|
||||
|
||||
void DocumentContainer::delete_font(litehtml::uint_ptr hFont)
|
||||
void DocumentContainerPrivate::delete_font(litehtml::uint_ptr hFont)
|
||||
{
|
||||
auto font = reinterpret_cast<Font *>(hFont);
|
||||
delete font;
|
||||
}
|
||||
|
||||
int DocumentContainer::text_width(const litehtml::tchar_t *text, litehtml::uint_ptr hFont)
|
||||
int DocumentContainerPrivate::text_width(const litehtml::tchar_t *text, litehtml::uint_ptr hFont)
|
||||
{
|
||||
const QFontMetrics fm(toQFont(hFont));
|
||||
return fm.horizontalAdvance(QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
void DocumentContainer::draw_text(litehtml::uint_ptr hdc,
|
||||
const litehtml::tchar_t *text,
|
||||
litehtml::uint_ptr hFont,
|
||||
litehtml::web_color color,
|
||||
const litehtml::position &pos)
|
||||
void DocumentContainerPrivate::draw_text(litehtml::uint_ptr hdc,
|
||||
const litehtml::tchar_t *text,
|
||||
litehtml::uint_ptr hFont,
|
||||
litehtml::web_color color,
|
||||
const litehtml::position &pos)
|
||||
{
|
||||
auto painter = toQPainter(hdc);
|
||||
painter->setFont(toQFont(hFont));
|
||||
@@ -539,23 +542,24 @@ void DocumentContainer::draw_text(litehtml::uint_ptr hdc,
|
||||
painter->drawText(toQRect(pos), 0, QString::fromUtf8(text));
|
||||
}
|
||||
|
||||
int DocumentContainer::pt_to_px(int pt)
|
||||
int DocumentContainerPrivate::pt_to_px(int pt)
|
||||
{
|
||||
// magic factor of 11/12 to account for differences to webengine/webkit
|
||||
return m_paintDevice->physicalDpiY() * pt * 11 / m_paintDevice->logicalDpiY() / 12;
|
||||
}
|
||||
|
||||
int DocumentContainer::get_default_font_size() const
|
||||
int DocumentContainerPrivate::get_default_font_size() const
|
||||
{
|
||||
return m_defaultFont.pointSize();
|
||||
}
|
||||
|
||||
const litehtml::tchar_t *DocumentContainer::get_default_font_name() const
|
||||
const litehtml::tchar_t *DocumentContainerPrivate::get_default_font_name() const
|
||||
{
|
||||
return m_defaultFontFamilyName.constData();
|
||||
}
|
||||
|
||||
void DocumentContainer::draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker &marker)
|
||||
void DocumentContainerPrivate::draw_list_marker(litehtml::uint_ptr hdc,
|
||||
const litehtml::list_marker &marker)
|
||||
{
|
||||
auto painter = toQPainter(hdc);
|
||||
if (marker.image.empty()) {
|
||||
@@ -586,9 +590,9 @@ void DocumentContainer::draw_list_marker(litehtml::uint_ptr hdc, const litehtml:
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentContainer::load_image(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
bool redraw_on_ready)
|
||||
void DocumentContainerPrivate::load_image(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
bool redraw_on_ready)
|
||||
{
|
||||
const auto qtSrc = QString::fromUtf8(src);
|
||||
const auto qtBaseUrl = QString::fromUtf8(baseurl);
|
||||
@@ -604,9 +608,9 @@ void DocumentContainer::load_image(const litehtml::tchar_t *src,
|
||||
m_pixmaps.insert(url, pixmap);
|
||||
}
|
||||
|
||||
void DocumentContainer::get_image_size(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
litehtml::size &sz)
|
||||
void DocumentContainerPrivate::get_image_size(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
litehtml::size &sz)
|
||||
{
|
||||
const auto qtSrc = QString::fromUtf8(src);
|
||||
const auto qtBaseUrl = QString::fromUtf8(baseurl);
|
||||
@@ -619,7 +623,7 @@ void DocumentContainer::get_image_size(const litehtml::tchar_t *src,
|
||||
sz.height = pm.height();
|
||||
}
|
||||
|
||||
void DocumentContainer::drawSelection(QPainter *painter, const QRect &clip) const
|
||||
void DocumentContainerPrivate::drawSelection(QPainter *painter, const QRect &clip) const
|
||||
{
|
||||
painter->save();
|
||||
painter->setClipRect(clip, Qt::IntersectClip);
|
||||
@@ -639,7 +643,7 @@ static QString tagName(const litehtml::element::ptr &e)
|
||||
return current ? QString::fromUtf8(current->get_tagName()) : QString();
|
||||
}
|
||||
|
||||
void DocumentContainer::buildIndex()
|
||||
void DocumentContainerPrivate::buildIndex()
|
||||
{
|
||||
m_index.elementToIndex.clear();
|
||||
m_index.indexToElement.clear();
|
||||
@@ -666,7 +670,8 @@ void DocumentContainer::buildIndex()
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentContainer::draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint &bg)
|
||||
void DocumentContainerPrivate::draw_background(litehtml::uint_ptr hdc,
|
||||
const litehtml::background_paint &bg)
|
||||
{
|
||||
auto painter = toQPainter(hdc);
|
||||
if (bg.is_root) {
|
||||
@@ -749,10 +754,10 @@ void DocumentContainer::draw_background(litehtml::uint_ptr hdc, const litehtml::
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void DocumentContainer::draw_borders(litehtml::uint_ptr hdc,
|
||||
const litehtml::borders &borders,
|
||||
const litehtml::position &draw_pos,
|
||||
bool root)
|
||||
void DocumentContainerPrivate::draw_borders(litehtml::uint_ptr hdc,
|
||||
const litehtml::borders &borders,
|
||||
const litehtml::position &draw_pos,
|
||||
bool root)
|
||||
{
|
||||
Q_UNUSED(root)
|
||||
// TODO: special border styles
|
||||
@@ -815,18 +820,18 @@ void DocumentContainer::draw_borders(litehtml::uint_ptr hdc,
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentContainer::set_caption(const litehtml::tchar_t *caption)
|
||||
void DocumentContainerPrivate::set_caption(const litehtml::tchar_t *caption)
|
||||
{
|
||||
m_caption = QString::fromUtf8(caption);
|
||||
}
|
||||
|
||||
void DocumentContainer::set_base_url(const litehtml::tchar_t *base_url)
|
||||
void DocumentContainerPrivate::set_base_url(const litehtml::tchar_t *base_url)
|
||||
{
|
||||
m_baseUrl = QString::fromUtf8(base_url);
|
||||
}
|
||||
|
||||
void DocumentContainer::link(const std::shared_ptr<litehtml::document> &doc,
|
||||
const litehtml::element::ptr &el)
|
||||
void DocumentContainerPrivate::link(const std::shared_ptr<litehtml::document> &doc,
|
||||
const litehtml::element::ptr &el)
|
||||
{
|
||||
// TODO
|
||||
qDebug(log) << "link";
|
||||
@@ -834,20 +839,20 @@ void DocumentContainer::link(const std::shared_ptr<litehtml::document> &doc,
|
||||
Q_UNUSED(el)
|
||||
}
|
||||
|
||||
void DocumentContainer::on_anchor_click(const litehtml::tchar_t *url,
|
||||
const litehtml::element::ptr &el)
|
||||
void DocumentContainerPrivate::on_anchor_click(const litehtml::tchar_t *url,
|
||||
const litehtml::element::ptr &el)
|
||||
{
|
||||
Q_UNUSED(el)
|
||||
if (!m_blockLinks)
|
||||
m_linkCallback(resolveUrl(QString::fromUtf8(url), m_baseUrl));
|
||||
}
|
||||
|
||||
void DocumentContainer::set_cursor(const litehtml::tchar_t *cursor)
|
||||
void DocumentContainerPrivate::set_cursor(const litehtml::tchar_t *cursor)
|
||||
{
|
||||
m_cursorCallback(toQCursor(QString::fromUtf8(cursor)));
|
||||
}
|
||||
|
||||
void DocumentContainer::transform_text(litehtml::tstring &text, litehtml::text_transform tt)
|
||||
void DocumentContainerPrivate::transform_text(litehtml::tstring &text, litehtml::text_transform tt)
|
||||
{
|
||||
// TODO
|
||||
qDebug(log) << "transform_text";
|
||||
@@ -855,9 +860,9 @@ void DocumentContainer::transform_text(litehtml::tstring &text, litehtml::text_t
|
||||
Q_UNUSED(tt)
|
||||
}
|
||||
|
||||
void DocumentContainer::import_css(litehtml::tstring &text,
|
||||
const litehtml::tstring &url,
|
||||
litehtml::tstring &baseurl)
|
||||
void DocumentContainerPrivate::import_css(litehtml::tstring &text,
|
||||
const litehtml::tstring &url,
|
||||
litehtml::tstring &baseurl)
|
||||
{
|
||||
const QUrl actualUrl = resolveUrl(QString::fromStdString(url), QString::fromStdString(baseurl));
|
||||
const QString urlString = actualUrl.toString(QUrl::None);
|
||||
@@ -866,10 +871,10 @@ void DocumentContainer::import_css(litehtml::tstring &text,
|
||||
text = QString::fromUtf8(m_dataCallback(actualUrl)).toStdString();
|
||||
}
|
||||
|
||||
void DocumentContainer::set_clip(const litehtml::position &pos,
|
||||
const litehtml::border_radiuses &bdr_radius,
|
||||
bool valid_x,
|
||||
bool valid_y)
|
||||
void DocumentContainerPrivate::set_clip(const litehtml::position &pos,
|
||||
const litehtml::border_radiuses &bdr_radius,
|
||||
bool valid_x,
|
||||
bool valid_y)
|
||||
{
|
||||
// TODO
|
||||
qDebug(log) << "set_clip";
|
||||
@@ -879,18 +884,18 @@ void DocumentContainer::set_clip(const litehtml::position &pos,
|
||||
Q_UNUSED(valid_y)
|
||||
}
|
||||
|
||||
void DocumentContainer::del_clip()
|
||||
void DocumentContainerPrivate::del_clip()
|
||||
{
|
||||
// TODO
|
||||
qDebug(log) << "del_clip";
|
||||
}
|
||||
|
||||
void DocumentContainer::get_client_rect(litehtml::position &client) const
|
||||
void DocumentContainerPrivate::get_client_rect(litehtml::position &client) const
|
||||
{
|
||||
client = {m_clientRect.x(), m_clientRect.y(), m_clientRect.width(), m_clientRect.height()};
|
||||
}
|
||||
|
||||
std::shared_ptr<litehtml::element> DocumentContainer::create_element(
|
||||
std::shared_ptr<litehtml::element> DocumentContainerPrivate::create_element(
|
||||
const litehtml::tchar_t *tag_name,
|
||||
const litehtml::string_map &attributes,
|
||||
const std::shared_ptr<litehtml::document> &doc)
|
||||
@@ -902,14 +907,14 @@ std::shared_ptr<litehtml::element> DocumentContainer::create_element(
|
||||
return {};
|
||||
}
|
||||
|
||||
void DocumentContainer::get_media_features(litehtml::media_features &media) const
|
||||
void DocumentContainerPrivate::get_media_features(litehtml::media_features &media) const
|
||||
{
|
||||
media.type = litehtml::media_type_screen;
|
||||
// TODO
|
||||
qDebug(log) << "get_media_features";
|
||||
}
|
||||
|
||||
void DocumentContainer::get_language(litehtml::tstring &language, litehtml::tstring &culture) const
|
||||
void DocumentContainerPrivate::get_language(litehtml::tstring &language, litehtml::tstring &culture) const
|
||||
{
|
||||
// TODO
|
||||
qDebug(log) << "get_language";
|
||||
@@ -919,67 +924,91 @@ void DocumentContainer::get_language(litehtml::tstring &language, litehtml::tstr
|
||||
|
||||
void DocumentContainer::setPaintDevice(QPaintDevice *paintDevice)
|
||||
{
|
||||
m_paintDevice = paintDevice;
|
||||
d->m_paintDevice = paintDevice;
|
||||
}
|
||||
|
||||
void DocumentContainer::setScrollPosition(const QPoint &pos)
|
||||
{
|
||||
m_scrollPosition = pos;
|
||||
d->m_scrollPosition = pos;
|
||||
}
|
||||
|
||||
void DocumentContainer::setDocument(const QByteArray &data, litehtml::context *context)
|
||||
void DocumentContainer::setDocument(const QByteArray &data, DocumentContainerContext *context)
|
||||
{
|
||||
m_pixmaps.clear();
|
||||
m_selection = {};
|
||||
m_document = litehtml::document::createFromUTF8(data.constData(), this, context);
|
||||
buildIndex();
|
||||
d->m_pixmaps.clear();
|
||||
d->m_selection = {};
|
||||
d->m_document = litehtml::document::createFromUTF8(data.constData(), d.get(), &context->d->context);
|
||||
d->buildIndex();
|
||||
}
|
||||
|
||||
litehtml::document::ptr DocumentContainer::document() const
|
||||
bool DocumentContainer::hasDocument() const
|
||||
{
|
||||
return m_document;
|
||||
return d->m_document.get();
|
||||
}
|
||||
|
||||
void DocumentContainer::setBaseUrl(const QString &url)
|
||||
{
|
||||
d->set_base_url(url.toUtf8().constData());
|
||||
}
|
||||
|
||||
void DocumentContainer::render(int width, int height)
|
||||
{
|
||||
m_clientRect = {0, 0, width, height};
|
||||
if (!m_document)
|
||||
d->m_clientRect = {0, 0, width, height};
|
||||
if (!d->m_document)
|
||||
return;
|
||||
m_document->render(width);
|
||||
m_selection.update();
|
||||
d->m_document->render(width);
|
||||
d->m_selection.update();
|
||||
}
|
||||
|
||||
void DocumentContainer::draw(QPainter *painter, const QRect &clip)
|
||||
{
|
||||
drawSelection(painter, clip);
|
||||
const QPoint pos = -m_scrollPosition;
|
||||
d->drawSelection(painter, clip);
|
||||
const QPoint pos = -d->m_scrollPosition;
|
||||
const litehtml::position clipRect = {clip.x(), clip.y(), clip.width(), clip.height()};
|
||||
document()->draw(reinterpret_cast<litehtml::uint_ptr>(painter), pos.x(), pos.y(), &clipRect);
|
||||
d->m_document->draw(reinterpret_cast<litehtml::uint_ptr>(painter), pos.x(), pos.y(), &clipRect);
|
||||
}
|
||||
|
||||
int DocumentContainer::documentWidth() const
|
||||
{
|
||||
return d->m_document->width();
|
||||
}
|
||||
|
||||
int DocumentContainer::documentHeight() const
|
||||
{
|
||||
return d->m_document->height();
|
||||
}
|
||||
|
||||
int DocumentContainer::anchorY(const QString &anchorName) const
|
||||
{
|
||||
litehtml::element::ptr element = d->m_document->root()->select_one(
|
||||
QString("#%1").arg(anchorName).toStdString());
|
||||
if (!element) {
|
||||
element = d->m_document->root()->select_one(QString("[name=%1]").arg(anchorName).toStdString());
|
||||
}
|
||||
if (element)
|
||||
return element->get_placement().y;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QVector<QRect> DocumentContainer::mousePressEvent(const QPoint &documentPos,
|
||||
const QPoint &viewportPos,
|
||||
Qt::MouseButton button)
|
||||
{
|
||||
if (!m_document || button != Qt::LeftButton)
|
||||
if (!d->m_document || button != Qt::LeftButton)
|
||||
return {};
|
||||
QVector<QRect> redrawRects;
|
||||
// selection
|
||||
if (m_selection.isValid())
|
||||
redrawRects.append(m_selection.boundingRect());
|
||||
m_selection = {};
|
||||
m_selection.selectionStartDocumentPos = documentPos;
|
||||
m_selection.startElem = deepest_child_at_point(m_document,
|
||||
documentPos,
|
||||
viewportPos,
|
||||
m_selection.mode);
|
||||
if (d->m_selection.isValid())
|
||||
redrawRects.append(d->m_selection.boundingRect());
|
||||
d->m_selection = {};
|
||||
d->m_selection.selectionStartDocumentPos = documentPos;
|
||||
d->m_selection.startElem = deepest_child_at_point(d->m_document,
|
||||
documentPos,
|
||||
viewportPos,
|
||||
d->m_selection.mode);
|
||||
// post to litehtml
|
||||
litehtml::position::vector redrawBoxes;
|
||||
if (m_document->on_lbutton_down(documentPos.x(),
|
||||
documentPos.y(),
|
||||
viewportPos.x(),
|
||||
viewportPos.y(),
|
||||
redrawBoxes)) {
|
||||
if (d->m_document->on_lbutton_down(
|
||||
documentPos.x(), documentPos.y(), viewportPos.x(), viewportPos.y(), redrawBoxes)) {
|
||||
for (const litehtml::position &box : redrawBoxes)
|
||||
redrawRects.append(toQRect(box));
|
||||
}
|
||||
@@ -989,34 +1018,30 @@ QVector<QRect> DocumentContainer::mousePressEvent(const QPoint &documentPos,
|
||||
QVector<QRect> DocumentContainer::mouseMoveEvent(const QPoint &documentPos,
|
||||
const QPoint &viewportPos)
|
||||
{
|
||||
if (!m_document)
|
||||
if (!d->m_document)
|
||||
return {};
|
||||
QVector<QRect> redrawRects;
|
||||
// selection
|
||||
if (m_selection.isSelecting
|
||||
|| (!m_selection.selectionStartDocumentPos.isNull()
|
||||
&& (m_selection.selectionStartDocumentPos - documentPos).manhattanLength()
|
||||
>= kDragDistance
|
||||
&& m_selection.startElem.element)) {
|
||||
const Selection::Element element = deepest_child_at_point(m_document,
|
||||
if (d->m_selection.isSelecting
|
||||
|| (!d->m_selection.selectionStartDocumentPos.isNull()
|
||||
&& (d->m_selection.selectionStartDocumentPos - documentPos).manhattanLength() >= kDragDistance
|
||||
&& d->m_selection.startElem.element)) {
|
||||
const Selection::Element element = deepest_child_at_point(d->m_document,
|
||||
documentPos,
|
||||
viewportPos,
|
||||
m_selection.mode);
|
||||
d->m_selection.mode);
|
||||
if (element.element) {
|
||||
redrawRects.append(
|
||||
m_selection.boundingRect() /*.adjusted(-1, -1, +1, +1)*/); // redraw old selection area
|
||||
m_selection.endElem = element;
|
||||
m_selection.update();
|
||||
redrawRects.append(m_selection.boundingRect());
|
||||
d->m_selection.boundingRect() /*.adjusted(-1, -1, +1, +1)*/); // redraw old selection area
|
||||
d->m_selection.endElem = element;
|
||||
d->m_selection.update();
|
||||
redrawRects.append(d->m_selection.boundingRect());
|
||||
}
|
||||
m_selection.isSelecting = true;
|
||||
d->m_selection.isSelecting = true;
|
||||
}
|
||||
litehtml::position::vector redrawBoxes;
|
||||
if (m_document->on_mouse_over(documentPos.x(),
|
||||
documentPos.y(),
|
||||
viewportPos.x(),
|
||||
viewportPos.y(),
|
||||
redrawBoxes)) {
|
||||
if (d->m_document->on_mouse_over(
|
||||
documentPos.x(), documentPos.y(), viewportPos.x(), viewportPos.y(), redrawBoxes)) {
|
||||
for (const litehtml::position &box : redrawBoxes)
|
||||
redrawRects.append(toQRect(box));
|
||||
}
|
||||
@@ -1027,26 +1052,23 @@ QVector<QRect> DocumentContainer::mouseReleaseEvent(const QPoint &documentPos,
|
||||
const QPoint &viewportPos,
|
||||
Qt::MouseButton button)
|
||||
{
|
||||
if (!m_document || button != Qt::LeftButton)
|
||||
if (!d->m_document || button != Qt::LeftButton)
|
||||
return {};
|
||||
QVector<QRect> redrawRects;
|
||||
// selection
|
||||
m_selection.isSelecting = false;
|
||||
m_selection.selectionStartDocumentPos = {};
|
||||
if (m_selection.isValid())
|
||||
m_blockLinks = true;
|
||||
d->m_selection.isSelecting = false;
|
||||
d->m_selection.selectionStartDocumentPos = {};
|
||||
if (d->m_selection.isValid())
|
||||
d->m_blockLinks = true;
|
||||
else
|
||||
m_selection = {};
|
||||
d->m_selection = {};
|
||||
litehtml::position::vector redrawBoxes;
|
||||
if (m_document->on_lbutton_up(documentPos.x(),
|
||||
documentPos.y(),
|
||||
viewportPos.x(),
|
||||
viewportPos.y(),
|
||||
redrawBoxes)) {
|
||||
if (d->m_document->on_lbutton_up(
|
||||
documentPos.x(), documentPos.y(), viewportPos.x(), viewportPos.y(), redrawBoxes)) {
|
||||
for (const litehtml::position &box : redrawBoxes)
|
||||
redrawRects.append(toQRect(box));
|
||||
}
|
||||
m_blockLinks = false;
|
||||
d->m_blockLinks = false;
|
||||
return redrawRects;
|
||||
}
|
||||
|
||||
@@ -1054,36 +1076,36 @@ QVector<QRect> DocumentContainer::mouseDoubleClickEvent(const QPoint &documentPo
|
||||
const QPoint &viewportPos,
|
||||
Qt::MouseButton button)
|
||||
{
|
||||
if (!m_document || button != Qt::LeftButton)
|
||||
if (!d->m_document || button != Qt::LeftButton)
|
||||
return {};
|
||||
QVector<QRect> redrawRects;
|
||||
m_selection = {};
|
||||
m_selection.mode = Selection::Mode::Word;
|
||||
const Selection::Element element = deepest_child_at_point(m_document,
|
||||
d->m_selection = {};
|
||||
d->m_selection.mode = Selection::Mode::Word;
|
||||
const Selection::Element element = deepest_child_at_point(d->m_document,
|
||||
documentPos,
|
||||
viewportPos,
|
||||
m_selection.mode);
|
||||
d->m_selection.mode);
|
||||
if (element.element) {
|
||||
m_selection.startElem = element;
|
||||
m_selection.endElem = m_selection.startElem;
|
||||
m_selection.isSelecting = true;
|
||||
m_selection.update();
|
||||
if (m_selection.isValid())
|
||||
redrawRects.append(m_selection.boundingRect());
|
||||
d->m_selection.startElem = element;
|
||||
d->m_selection.endElem = d->m_selection.startElem;
|
||||
d->m_selection.isSelecting = true;
|
||||
d->m_selection.update();
|
||||
if (d->m_selection.isValid())
|
||||
redrawRects.append(d->m_selection.boundingRect());
|
||||
} else {
|
||||
if (m_selection.isValid())
|
||||
redrawRects.append(m_selection.boundingRect());
|
||||
m_selection = {};
|
||||
if (d->m_selection.isValid())
|
||||
redrawRects.append(d->m_selection.boundingRect());
|
||||
d->m_selection = {};
|
||||
}
|
||||
return redrawRects;
|
||||
}
|
||||
|
||||
QVector<QRect> DocumentContainer::leaveEvent()
|
||||
{
|
||||
if (!m_document)
|
||||
if (!d->m_document)
|
||||
return {};
|
||||
litehtml::position::vector redrawBoxes;
|
||||
if (m_document->on_mouse_leave(redrawBoxes)) {
|
||||
if (d->m_document->on_mouse_leave(redrawBoxes)) {
|
||||
QVector<QRect> redrawRects;
|
||||
for (const litehtml::position &box : redrawBoxes)
|
||||
redrawRects.append(toQRect(box));
|
||||
@@ -1094,26 +1116,24 @@ QVector<QRect> DocumentContainer::leaveEvent()
|
||||
|
||||
QUrl DocumentContainer::linkAt(const QPoint &documentPos, const QPoint &viewportPos)
|
||||
{
|
||||
if (!m_document)
|
||||
if (!d->m_document)
|
||||
return {};
|
||||
const litehtml::element::ptr element = m_document->root()->get_element_by_point(documentPos.x(),
|
||||
documentPos.y(),
|
||||
viewportPos.x(),
|
||||
viewportPos.y());
|
||||
const litehtml::element::ptr element = d->m_document->root()->get_element_by_point(
|
||||
documentPos.x(), documentPos.y(), viewportPos.x(), viewportPos.y());
|
||||
const char *href = element->get_attr("href");
|
||||
if (href)
|
||||
return resolveUrl(QString::fromUtf8(href), m_baseUrl);
|
||||
return d->resolveUrl(QString::fromUtf8(href), d->m_baseUrl);
|
||||
return {};
|
||||
}
|
||||
|
||||
QString DocumentContainer::caption() const
|
||||
{
|
||||
return m_caption;
|
||||
return d->m_caption;
|
||||
}
|
||||
|
||||
QString DocumentContainer::selectedText() const
|
||||
{
|
||||
return m_selection.text;
|
||||
return d->m_selection.text;
|
||||
}
|
||||
|
||||
void DocumentContainer::findText(const QString &text,
|
||||
@@ -1130,16 +1150,16 @@ void DocumentContainer::findText(const QString &text,
|
||||
oldSelection->clear();
|
||||
if (newSelection)
|
||||
newSelection->clear();
|
||||
if (!m_document)
|
||||
if (!d->m_document)
|
||||
return;
|
||||
const bool backward = flags & QTextDocument::FindBackward;
|
||||
int startIndex = backward ? -1 : 0;
|
||||
if (m_selection.startElem.element && m_selection.endElem.element) { // selection
|
||||
if (d->m_selection.startElem.element && d->m_selection.endElem.element) { // selection
|
||||
// poor-man's incremental search starts at beginning of selection,
|
||||
// non-incremental at end (forward search) or beginning (backward search)
|
||||
Selection::Element start;
|
||||
Selection::Element end;
|
||||
std::tie(start, end) = getStartAndEnd(m_selection.startElem, m_selection.endElem);
|
||||
std::tie(start, end) = getStartAndEnd(d->m_selection.startElem, d->m_selection.endElem);
|
||||
Selection::Element searchStart;
|
||||
if (incremental || backward) {
|
||||
if (start.index < 0) // fully selected
|
||||
@@ -1152,8 +1172,8 @@ void DocumentContainer::findText(const QString &text,
|
||||
else
|
||||
searchStart = end;
|
||||
}
|
||||
const auto findInIndex = m_index.elementToIndex.find(searchStart.element);
|
||||
if (findInIndex == std::end(m_index.elementToIndex)) {
|
||||
const auto findInIndex = d->m_index.elementToIndex.find(searchStart.element);
|
||||
if (findInIndex == std::end(d->m_index.elementToIndex)) {
|
||||
qWarning() << "internal error: cannot find litehmtl element in index";
|
||||
return;
|
||||
}
|
||||
@@ -1179,30 +1199,30 @@ void DocumentContainer::findText(const QString &text,
|
||||
: QRegularExpression::CaseInsensitiveOption;
|
||||
const QRegularExpression expression(term, patternOptions);
|
||||
|
||||
int foundIndex = backward ? m_index.text.lastIndexOf(expression, startIndex)
|
||||
: m_index.text.indexOf(expression, startIndex);
|
||||
int foundIndex = backward ? d->m_index.text.lastIndexOf(expression, startIndex)
|
||||
: d->m_index.text.indexOf(expression, startIndex);
|
||||
if (foundIndex < 0) { // wrap
|
||||
foundIndex = backward ? m_index.text.lastIndexOf(expression)
|
||||
: m_index.text.indexOf(expression);
|
||||
foundIndex = backward ? d->m_index.text.lastIndexOf(expression)
|
||||
: d->m_index.text.indexOf(expression);
|
||||
if (wrapped && foundIndex >= 0)
|
||||
*wrapped = true;
|
||||
}
|
||||
if (foundIndex >= 0) {
|
||||
const Index::Entry startEntry = m_index.findElement(foundIndex);
|
||||
const Index::Entry endEntry = m_index.findElement(foundIndex + text.size());
|
||||
const Index::Entry startEntry = d->m_index.findElement(foundIndex);
|
||||
const Index::Entry endEntry = d->m_index.findElement(foundIndex + text.size());
|
||||
if (!startEntry.second || !endEntry.second) {
|
||||
qWarning() << "internal error: search ended up with nullptr elements";
|
||||
return;
|
||||
}
|
||||
if (oldSelection)
|
||||
*oldSelection = m_selection.selection;
|
||||
m_selection = {};
|
||||
m_selection.startElem = fillXPos({startEntry.second, foundIndex - startEntry.first, -1});
|
||||
m_selection.endElem = fillXPos(
|
||||
*oldSelection = d->m_selection.selection;
|
||||
d->m_selection = {};
|
||||
d->m_selection.startElem = fillXPos({startEntry.second, foundIndex - startEntry.first, -1});
|
||||
d->m_selection.endElem = fillXPos(
|
||||
{endEntry.second, int(foundIndex + text.size() - endEntry.first), -1});
|
||||
m_selection.update();
|
||||
d->m_selection.update();
|
||||
if (newSelection)
|
||||
*newSelection = m_selection.selection;
|
||||
*newSelection = d->m_selection.selection;
|
||||
if (success)
|
||||
*success = true;
|
||||
return;
|
||||
@@ -1212,36 +1232,68 @@ void DocumentContainer::findText(const QString &text,
|
||||
|
||||
void DocumentContainer::setDefaultFont(const QFont &font)
|
||||
{
|
||||
m_defaultFont = font;
|
||||
m_defaultFontFamilyName = m_defaultFont.family().toUtf8();
|
||||
d->m_defaultFont = font;
|
||||
d->m_defaultFontFamilyName = d->m_defaultFont.family().toUtf8();
|
||||
}
|
||||
|
||||
QFont DocumentContainer::defaultFont() const
|
||||
{
|
||||
return m_defaultFont;
|
||||
return d->m_defaultFont;
|
||||
}
|
||||
|
||||
void DocumentContainer::setDataCallback(const DocumentContainer::DataCallback &callback)
|
||||
{
|
||||
m_dataCallback = callback;
|
||||
d->m_dataCallback = callback;
|
||||
}
|
||||
|
||||
void DocumentContainer::setCursorCallback(const DocumentContainer::CursorCallback &callback)
|
||||
{
|
||||
m_cursorCallback = callback;
|
||||
d->m_cursorCallback = callback;
|
||||
}
|
||||
|
||||
void DocumentContainer::setLinkCallback(const DocumentContainer::LinkCallback &callback)
|
||||
{
|
||||
m_linkCallback = callback;
|
||||
d->m_linkCallback = callback;
|
||||
}
|
||||
|
||||
void DocumentContainer::setPaletteCallback(const DocumentContainer::PaletteCallback &callback)
|
||||
{
|
||||
m_paletteCallback = callback;
|
||||
d->m_paletteCallback = callback;
|
||||
}
|
||||
|
||||
QPixmap DocumentContainer::getPixmap(const QString &imageUrl, const QString &baseUrl)
|
||||
static litehtml::element::ptr elementForY(int y, const litehtml::document::ptr &document)
|
||||
{
|
||||
if (!document)
|
||||
return {};
|
||||
|
||||
const std::function<litehtml::element::ptr(int, litehtml::element::ptr)> recursion =
|
||||
[&recursion](int y, const litehtml::element::ptr &element) {
|
||||
litehtml::element::ptr result;
|
||||
const int subY = y - element->get_position().y;
|
||||
if (subY <= 0)
|
||||
return element;
|
||||
for (int i = 0; i < int(element->get_children_count()); ++i) {
|
||||
const litehtml::element::ptr child = element->get_child(i);
|
||||
result = recursion(subY, child);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return recursion(y, document->root());
|
||||
}
|
||||
|
||||
int DocumentContainer::withFixedElementPosition(int y, const std::function<void()> &action)
|
||||
{
|
||||
const litehtml::element::ptr element = elementForY(y, d->m_document);
|
||||
action();
|
||||
if (element)
|
||||
return element->get_placement().y;
|
||||
return -1;
|
||||
}
|
||||
|
||||
QPixmap DocumentContainerPrivate::getPixmap(const QString &imageUrl, const QString &baseUrl)
|
||||
{
|
||||
const QString actualBaseurl = baseUrl.isEmpty() ? m_baseUrl : baseUrl;
|
||||
const QUrl url = resolveUrl(imageUrl, baseUrl);
|
||||
@@ -1252,25 +1304,25 @@ QPixmap DocumentContainer::getPixmap(const QString &imageUrl, const QString &bas
|
||||
return m_pixmaps.value(url);
|
||||
}
|
||||
|
||||
QString DocumentContainer::serifFont() const
|
||||
QString DocumentContainerPrivate::serifFont() const
|
||||
{
|
||||
// TODO make configurable
|
||||
return {"Times New Roman"};
|
||||
}
|
||||
|
||||
QString DocumentContainer::sansSerifFont() const
|
||||
QString DocumentContainerPrivate::sansSerifFont() const
|
||||
{
|
||||
// TODO make configurable
|
||||
return {"Arial"};
|
||||
}
|
||||
|
||||
QString DocumentContainer::monospaceFont() const
|
||||
QString DocumentContainerPrivate::monospaceFont() const
|
||||
{
|
||||
// TODO make configurable
|
||||
return {"Courier"};
|
||||
}
|
||||
|
||||
QUrl DocumentContainer::resolveUrl(const QString &url, const QString &baseUrl) const
|
||||
QUrl DocumentContainerPrivate::resolveUrl(const QString &url, const QString &baseUrl) const
|
||||
{
|
||||
const QUrl qurl(url);
|
||||
if (qurl.isRelative() && !qurl.path(QUrl::FullyEncoded).isEmpty()) {
|
||||
@@ -1294,3 +1346,14 @@ Index::Entry Index::findElement(int index) const
|
||||
return {-1, {}};
|
||||
return *(upper - 1);
|
||||
}
|
||||
|
||||
DocumentContainerContext::DocumentContainerContext()
|
||||
: d(new DocumentContainerContextPrivate)
|
||||
{}
|
||||
|
||||
DocumentContainerContext::~DocumentContainerContext() = default;
|
||||
|
||||
void DocumentContainerContext::setMasterStyleSheet(const QString &css)
|
||||
{
|
||||
d->context.load_master_stylesheet(css.toUtf8().constData());
|
||||
}
|
||||
|
@@ -25,125 +25,56 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <litehtml.h>
|
||||
#include "qlitehtml_global.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QHash>
|
||||
#include <QByteArray>
|
||||
#include <QPaintDevice>
|
||||
#include <QPalette>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QString>
|
||||
#include <QTextDocument>
|
||||
#include <QUrl>
|
||||
#include <QVector>
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
class Selection
|
||||
class DocumentContainerPrivate;
|
||||
class DocumentContainerContextPrivate;
|
||||
|
||||
class QLITEHTML_EXPORT DocumentContainerContext
|
||||
{
|
||||
public:
|
||||
struct Element
|
||||
{
|
||||
litehtml::element::ptr element;
|
||||
int index = -1;
|
||||
int x = -1;
|
||||
};
|
||||
DocumentContainerContext();
|
||||
~DocumentContainerContext();
|
||||
|
||||
enum class Mode { Free, Word };
|
||||
void setMasterStyleSheet(const QString &css);
|
||||
|
||||
bool isValid() const;
|
||||
private:
|
||||
std::unique_ptr<DocumentContainerContextPrivate> d;
|
||||
|
||||
void update();
|
||||
QRect boundingRect() const;
|
||||
|
||||
Element startElem;
|
||||
Element endElem;
|
||||
QVector<QRect> selection;
|
||||
QString text;
|
||||
|
||||
QPoint selectionStartDocumentPos;
|
||||
Mode mode = Mode::Free;
|
||||
bool isSelecting = false;
|
||||
friend class DocumentContainer;
|
||||
friend class DocumentContainerPrivate;
|
||||
};
|
||||
|
||||
struct Index
|
||||
{
|
||||
QString text;
|
||||
// only contains leaf elements
|
||||
std::unordered_map<litehtml::element::ptr, int> elementToIndex;
|
||||
|
||||
using Entry = std::pair<int, litehtml::element::ptr>;
|
||||
std::vector<Entry> indexToElement;
|
||||
|
||||
Entry findElement(int index) const;
|
||||
};
|
||||
|
||||
class DocumentContainer : public litehtml::document_container
|
||||
class QLITEHTML_EXPORT DocumentContainer
|
||||
{
|
||||
public:
|
||||
DocumentContainer();
|
||||
virtual ~DocumentContainer();
|
||||
|
||||
public: // document_container API
|
||||
litehtml::uint_ptr create_font(const litehtml::tchar_t *faceName,
|
||||
int size,
|
||||
int weight,
|
||||
litehtml::font_style italic,
|
||||
unsigned int decoration,
|
||||
litehtml::font_metrics *fm) override;
|
||||
void delete_font(litehtml::uint_ptr hFont) override;
|
||||
int text_width(const litehtml::tchar_t *text, litehtml::uint_ptr hFont) override;
|
||||
void draw_text(litehtml::uint_ptr hdc,
|
||||
const litehtml::tchar_t *text,
|
||||
litehtml::uint_ptr hFont,
|
||||
litehtml::web_color color,
|
||||
const litehtml::position &pos) override;
|
||||
int pt_to_px(int pt) override;
|
||||
int get_default_font_size() const override;
|
||||
const litehtml::tchar_t *get_default_font_name() const override;
|
||||
void draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker &marker) override;
|
||||
void load_image(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
bool redraw_on_ready) override;
|
||||
void get_image_size(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
litehtml::size &sz) override;
|
||||
void draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint &bg) override;
|
||||
void draw_borders(litehtml::uint_ptr hdc,
|
||||
const litehtml::borders &borders,
|
||||
const litehtml::position &draw_pos,
|
||||
bool root) override;
|
||||
void set_caption(const litehtml::tchar_t *caption) override;
|
||||
void set_base_url(const litehtml::tchar_t *base_url) override;
|
||||
void link(const std::shared_ptr<litehtml::document> &doc,
|
||||
const litehtml::element::ptr &el) override;
|
||||
void on_anchor_click(const litehtml::tchar_t *url, const litehtml::element::ptr &el) override;
|
||||
void set_cursor(const litehtml::tchar_t *cursor) override;
|
||||
void transform_text(litehtml::tstring &text, litehtml::text_transform tt) override;
|
||||
void import_css(litehtml::tstring &text,
|
||||
const litehtml::tstring &url,
|
||||
litehtml::tstring &baseurl) override;
|
||||
void set_clip(const litehtml::position &pos,
|
||||
const litehtml::border_radiuses &bdr_radius,
|
||||
bool valid_x,
|
||||
bool valid_y) override;
|
||||
void del_clip() override;
|
||||
void get_client_rect(litehtml::position &client) const override;
|
||||
std::shared_ptr<litehtml::element> create_element(
|
||||
const litehtml::tchar_t *tag_name,
|
||||
const litehtml::string_map &attributes,
|
||||
const std::shared_ptr<litehtml::document> &doc) override;
|
||||
void get_media_features(litehtml::media_features &media) const override;
|
||||
void get_language(litehtml::tstring &language, litehtml::tstring &culture) const override;
|
||||
|
||||
public: // outside API
|
||||
void setPaintDevice(QPaintDevice *paintDevice);
|
||||
void setDocument(const QByteArray &data, litehtml::context *context);
|
||||
litehtml::document::ptr document() const;
|
||||
void setDocument(const QByteArray &data, DocumentContainerContext *context);
|
||||
bool hasDocument() const;
|
||||
void setBaseUrl(const QString &url);
|
||||
void setScrollPosition(const QPoint &pos);
|
||||
void render(int width, int height);
|
||||
void draw(QPainter *painter, const QRect &clip);
|
||||
int documentWidth() const;
|
||||
int documentHeight() const;
|
||||
int anchorY(const QString &anchorName) const;
|
||||
|
||||
// these return areas to redraw in document space
|
||||
QVector<QRect> mousePressEvent(const QPoint &documentPos,
|
||||
@@ -186,29 +117,8 @@ public: // outside API
|
||||
using PaletteCallback = std::function<QPalette()>;
|
||||
void setPaletteCallback(const PaletteCallback &callback);
|
||||
|
||||
private:
|
||||
QPixmap getPixmap(const QString &imageUrl, const QString &baseUrl);
|
||||
QString serifFont() const;
|
||||
QString sansSerifFont() const;
|
||||
QString monospaceFont() const;
|
||||
QUrl resolveUrl(const QString &url, const QString &baseUrl) const;
|
||||
void drawSelection(QPainter *painter, const QRect &clip) const;
|
||||
void buildIndex();
|
||||
int withFixedElementPosition(int y, const std::function<void()> &action);
|
||||
|
||||
QPaintDevice *m_paintDevice = nullptr;
|
||||
litehtml::document::ptr m_document;
|
||||
Index m_index;
|
||||
QString m_baseUrl;
|
||||
QRect m_clientRect;
|
||||
QPoint m_scrollPosition;
|
||||
QString m_caption;
|
||||
QFont m_defaultFont = QFont(sansSerifFont(), 16);
|
||||
QByteArray m_defaultFontFamilyName = m_defaultFont.family().toUtf8();
|
||||
QHash<QUrl, QPixmap> m_pixmaps;
|
||||
Selection m_selection;
|
||||
DataCallback m_dataCallback;
|
||||
CursorCallback m_cursorCallback;
|
||||
LinkCallback m_linkCallback;
|
||||
PaletteCallback m_paletteCallback;
|
||||
bool m_blockLinks = false;
|
||||
private:
|
||||
std::unique_ptr<DocumentContainerPrivate> d;
|
||||
};
|
||||
|
163
src/plugins/help/qlitehtml/container_qpainter_p.h
Normal file
163
src/plugins/help/qlitehtml/container_qpainter_p.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2020 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of QLiteHtml.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "container_qpainter.h"
|
||||
|
||||
#include <litehtml.h>
|
||||
|
||||
#include <QPaintDevice>
|
||||
#include <QPixmap>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
class Selection
|
||||
{
|
||||
public:
|
||||
struct Element
|
||||
{
|
||||
litehtml::element::ptr element;
|
||||
int index = -1;
|
||||
int x = -1;
|
||||
};
|
||||
|
||||
enum class Mode { Free, Word };
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
void update();
|
||||
QRect boundingRect() const;
|
||||
|
||||
Element startElem;
|
||||
Element endElem;
|
||||
QVector<QRect> selection;
|
||||
QString text;
|
||||
|
||||
QPoint selectionStartDocumentPos;
|
||||
Mode mode = Mode::Free;
|
||||
bool isSelecting = false;
|
||||
};
|
||||
|
||||
struct Index
|
||||
{
|
||||
QString text;
|
||||
// only contains leaf elements
|
||||
std::unordered_map<litehtml::element::ptr, int> elementToIndex;
|
||||
|
||||
using Entry = std::pair<int, litehtml::element::ptr>;
|
||||
std::vector<Entry> indexToElement;
|
||||
|
||||
Entry findElement(int index) const;
|
||||
};
|
||||
|
||||
class DocumentContainerPrivate : public litehtml::document_container
|
||||
{
|
||||
public: // document_container API
|
||||
litehtml::uint_ptr create_font(const litehtml::tchar_t *faceName,
|
||||
int size,
|
||||
int weight,
|
||||
litehtml::font_style italic,
|
||||
unsigned int decoration,
|
||||
litehtml::font_metrics *fm) override;
|
||||
void delete_font(litehtml::uint_ptr hFont) override;
|
||||
int text_width(const litehtml::tchar_t *text, litehtml::uint_ptr hFont) override;
|
||||
void draw_text(litehtml::uint_ptr hdc,
|
||||
const litehtml::tchar_t *text,
|
||||
litehtml::uint_ptr hFont,
|
||||
litehtml::web_color color,
|
||||
const litehtml::position &pos) override;
|
||||
int pt_to_px(int pt) override;
|
||||
int get_default_font_size() const override;
|
||||
const litehtml::tchar_t *get_default_font_name() const override;
|
||||
void draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker &marker) override;
|
||||
void load_image(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
bool redraw_on_ready) override;
|
||||
void get_image_size(const litehtml::tchar_t *src,
|
||||
const litehtml::tchar_t *baseurl,
|
||||
litehtml::size &sz) override;
|
||||
void draw_background(litehtml::uint_ptr hdc, const litehtml::background_paint &bg) override;
|
||||
void draw_borders(litehtml::uint_ptr hdc,
|
||||
const litehtml::borders &borders,
|
||||
const litehtml::position &draw_pos,
|
||||
bool root) override;
|
||||
void set_caption(const litehtml::tchar_t *caption) override;
|
||||
void set_base_url(const litehtml::tchar_t *base_url) override;
|
||||
void link(const std::shared_ptr<litehtml::document> &doc,
|
||||
const litehtml::element::ptr &el) override;
|
||||
void on_anchor_click(const litehtml::tchar_t *url, const litehtml::element::ptr &el) override;
|
||||
void set_cursor(const litehtml::tchar_t *cursor) override;
|
||||
void transform_text(litehtml::tstring &text, litehtml::text_transform tt) override;
|
||||
void import_css(litehtml::tstring &text,
|
||||
const litehtml::tstring &url,
|
||||
litehtml::tstring &baseurl) override;
|
||||
void set_clip(const litehtml::position &pos,
|
||||
const litehtml::border_radiuses &bdr_radius,
|
||||
bool valid_x,
|
||||
bool valid_y) override;
|
||||
void del_clip() override;
|
||||
void get_client_rect(litehtml::position &client) const override;
|
||||
std::shared_ptr<litehtml::element> create_element(const litehtml::tchar_t *tag_name,
|
||||
const litehtml::string_map &attributes,
|
||||
const std::shared_ptr<litehtml::document> &doc) override;
|
||||
void get_media_features(litehtml::media_features &media) const override;
|
||||
void get_language(litehtml::tstring &language, litehtml::tstring &culture) const override;
|
||||
|
||||
QPixmap getPixmap(const QString &imageUrl, const QString &baseUrl);
|
||||
QString serifFont() const;
|
||||
QString sansSerifFont() const;
|
||||
QString monospaceFont() const;
|
||||
QUrl resolveUrl(const QString &url, const QString &baseUrl) const;
|
||||
void drawSelection(QPainter *painter, const QRect &clip) const;
|
||||
void buildIndex();
|
||||
|
||||
QPaintDevice *m_paintDevice = nullptr;
|
||||
litehtml::document::ptr m_document;
|
||||
Index m_index;
|
||||
QString m_baseUrl;
|
||||
QRect m_clientRect;
|
||||
QPoint m_scrollPosition;
|
||||
QString m_caption;
|
||||
QFont m_defaultFont = QFont(sansSerifFont(), 16);
|
||||
QByteArray m_defaultFontFamilyName = m_defaultFont.family().toUtf8();
|
||||
QHash<QUrl, QPixmap> m_pixmaps;
|
||||
Selection m_selection;
|
||||
DocumentContainer::DataCallback m_dataCallback;
|
||||
DocumentContainer::CursorCallback m_cursorCallback;
|
||||
DocumentContainer::LinkCallback m_linkCallback;
|
||||
DocumentContainer::PaletteCallback m_paletteCallback;
|
||||
bool m_blockLinks = false;
|
||||
};
|
||||
|
||||
class DocumentContainerContextPrivate
|
||||
{
|
||||
public:
|
||||
litehtml::context context;
|
||||
};
|
@@ -147,6 +147,7 @@ exists($$PWD/litehtml/CMakeLists.txt) {
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/container_qpainter.h \
|
||||
$$PWD/container_qpainter_p.h \
|
||||
$$PWD/qlitehtmlwidget.h
|
||||
|
||||
SOURCES += \
|
||||
|
@@ -41,6 +41,7 @@ Product {
|
||||
files: [
|
||||
"container_qpainter.cpp",
|
||||
"container_qpainter.h",
|
||||
"container_qpainter_p.h",
|
||||
"qlitehtmlwidget.cpp",
|
||||
"qlitehtmlwidget.h",
|
||||
]
|
||||
|
@@ -34,8 +34,6 @@
|
||||
#include <QStyle>
|
||||
#include <QTimer>
|
||||
|
||||
#include <litehtml.h>
|
||||
|
||||
const int kScrollBarStep = 40;
|
||||
|
||||
// TODO copied from litehtml/include/master.css
|
||||
@@ -370,7 +368,7 @@ display: block;
|
||||
class QLiteHtmlWidgetPrivate
|
||||
{
|
||||
public:
|
||||
litehtml::context context;
|
||||
DocumentContainerContext context;
|
||||
QUrl url;
|
||||
DocumentContainer documentContainer;
|
||||
qreal zoomFactor = 1;
|
||||
@@ -397,7 +395,7 @@ QLiteHtmlWidget::QLiteHtmlWidget(QWidget *parent)
|
||||
});
|
||||
|
||||
// TODO adapt mastercss to palette (default text & background color)
|
||||
d->context.load_master_stylesheet(mastercss);
|
||||
d->context.setMasterStyleSheet(mastercss);
|
||||
}
|
||||
|
||||
QLiteHtmlWidget::~QLiteHtmlWidget()
|
||||
@@ -413,7 +411,7 @@ void QLiteHtmlWidget::setUrl(const QUrl &url)
|
||||
const QString urlString = urlWithoutAnchor.toString(QUrl::None);
|
||||
const int lastSlash = urlString.lastIndexOf('/');
|
||||
const QString baseUrl = lastSlash >= 0 ? urlString.left(lastSlash) : urlString;
|
||||
d->documentContainer.set_base_url(baseUrl.toUtf8().constData());
|
||||
d->documentContainer.setBaseUrl(baseUrl);
|
||||
}
|
||||
|
||||
QUrl QLiteHtmlWidget::url() const
|
||||
@@ -489,23 +487,16 @@ QFont QLiteHtmlWidget::defaultFont() const
|
||||
|
||||
void QLiteHtmlWidget::scrollToAnchor(const QString &name)
|
||||
{
|
||||
if (!d->documentContainer.document())
|
||||
if (!d->documentContainer.hasDocument())
|
||||
return;
|
||||
horizontalScrollBar()->setValue(0);
|
||||
if (name.isEmpty()) {
|
||||
verticalScrollBar()->setValue(0);
|
||||
return;
|
||||
}
|
||||
litehtml::element::ptr element = d->documentContainer.document()->root()->select_one(
|
||||
QString("#%1").arg(name).toStdString());
|
||||
if (!element) {
|
||||
element = d->documentContainer.document()->root()->select_one(
|
||||
QString("[name=%1]").arg(name).toStdString());
|
||||
}
|
||||
if (element) {
|
||||
const int y = element->get_placement().y;
|
||||
const int y = d->documentContainer.anchorY(name);
|
||||
if (y >= 0)
|
||||
verticalScrollBar()->setValue(std::min(y, verticalScrollBar()->maximum()));
|
||||
}
|
||||
}
|
||||
|
||||
void QLiteHtmlWidget::setResourceHandler(const QLiteHtmlWidget::ResourceHandler &handler)
|
||||
@@ -520,7 +511,7 @@ QString QLiteHtmlWidget::selectedText() const
|
||||
|
||||
void QLiteHtmlWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
if (!d->documentContainer.document())
|
||||
if (!d->documentContainer.hasDocument())
|
||||
return;
|
||||
d->documentContainer.setScrollPosition(scrollPosition());
|
||||
QPainter p(viewport());
|
||||
@@ -530,29 +521,6 @@ void QLiteHtmlWidget::paintEvent(QPaintEvent *event)
|
||||
d->documentContainer.draw(&p, toVirtual(event->rect()));
|
||||
}
|
||||
|
||||
static litehtml::element::ptr elementForY(int y, const litehtml::document::ptr &document)
|
||||
{
|
||||
if (!document)
|
||||
return {};
|
||||
|
||||
const std::function<litehtml::element::ptr(int, litehtml::element::ptr)> recursion =
|
||||
[&recursion](int y, const litehtml::element::ptr &element) {
|
||||
litehtml::element::ptr result;
|
||||
const int subY = y - element->get_position().y;
|
||||
if (subY <= 0)
|
||||
return element;
|
||||
for (int i = 0; i < int(element->get_children_count()); ++i) {
|
||||
const litehtml::element::ptr child = element->get_child(i);
|
||||
result = recursion(subY, child);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
return recursion(y, document->root());
|
||||
}
|
||||
|
||||
void QLiteHtmlWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
withFixedTextPosition([this, event] {
|
||||
@@ -620,17 +588,14 @@ void QLiteHtmlWidget::withFixedTextPosition(const std::function<void()> &action)
|
||||
QPoint viewportPos;
|
||||
QPoint pos;
|
||||
htmlPos({}, &viewportPos, &pos); // top-left
|
||||
const litehtml::element::ptr element = elementForY(pos.y(), d->documentContainer.document());
|
||||
action();
|
||||
if (element) {
|
||||
verticalScrollBar()->setValue(
|
||||
std::min(element->get_placement().y, verticalScrollBar()->maximum()));
|
||||
}
|
||||
const int y = d->documentContainer.withFixedElementPosition(pos.y(), action);
|
||||
if (y >= 0)
|
||||
verticalScrollBar()->setValue(std::min(y, verticalScrollBar()->maximum()));
|
||||
}
|
||||
|
||||
void QLiteHtmlWidget::render()
|
||||
{
|
||||
if (!d->documentContainer.document())
|
||||
if (!d->documentContainer.hasDocument())
|
||||
return;
|
||||
const int fullWidth = width() / d->zoomFactor;
|
||||
const QSize vViewportSize = toVirtual(viewport()->size());
|
||||
@@ -639,12 +604,10 @@ void QLiteHtmlWidget::render()
|
||||
d->documentContainer.render(w, vViewportSize.height());
|
||||
// scroll bars reflect virtual/scaled size of html document
|
||||
horizontalScrollBar()->setPageStep(vViewportSize.width());
|
||||
horizontalScrollBar()->setRange(0, std::max(0, d->documentContainer.document()->width() - w));
|
||||
horizontalScrollBar()->setRange(0, std::max(0, d->documentContainer.documentWidth() - w));
|
||||
verticalScrollBar()->setPageStep(vViewportSize.height());
|
||||
verticalScrollBar()->setRange(0,
|
||||
std::max(0,
|
||||
d->documentContainer.document()->height()
|
||||
- vViewportSize.height()));
|
||||
verticalScrollBar()
|
||||
->setRange(0, std::max(0, d->documentContainer.documentHeight() - vViewportSize.height()));
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user