diff options
author | Eike Ziller <eike.ziller@qt.io> | 2023-05-19 14:53:21 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2024-02-06 07:51:56 +0000 |
commit | 7071977bd53c0e5f0bc5efba55505bb898ce8136 (patch) | |
tree | 482c79fbab0e95006b836c466f132ecbd106b0c7 /src | |
parent | b8f6617f22a7bd0bf3da2e75d1613e1346b974f0 (diff) |
Update litehtml to v0.9
- lots of smaller changes needed to be adapted to, like std::string
instead of litehtml::tstring, std::list for child elements, and other
mostly mechanical changes
- element::is_visible vanished, and we don't get to the render items, so
replaced that with our own version. render_item::is_visible would also
take m_skip into account, so this might be wrong for some elements.
(only relevant for the search index)
- element::get_element_by_point was removed, replace by own depth-first
iteration deepest_child_at_point. That takes a lot less properties
into consideration compared to get_element_by_point, like z-order, no
fixed position elements, etc
Task-number: QTCREATORBUG-29169
Task-number: QTBUG-118990
Fixes: QTBUG-121861
Change-Id: I7264a8407f123f44ba47e47cecc57fbf31a85a3d
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
Reviewed-by: Kai Köhne <kai.koehne@qt.io>
Diffstat (limited to 'src')
m--------- | src/3rdparty/litehtml | 0 | ||||
-rw-r--r-- | src/3rdparty/qt_attribution.json | 8 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/container_qpainter.cpp | 461 | ||||
-rw-r--r-- | src/container_qpainter_p.h | 48 |
5 files changed, 272 insertions, 246 deletions
diff --git a/src/3rdparty/litehtml b/src/3rdparty/litehtml -Subproject 43af58e8adad70c4f1a0a9235546a246754c173 +Subproject 6ca1ab0419e770e6d35a1ef690238773a1dafce diff --git a/src/3rdparty/qt_attribution.json b/src/3rdparty/qt_attribution.json index 6cf540b..a0ec2a8 100644 --- a/src/3rdparty/qt_attribution.json +++ b/src/3rdparty/qt_attribution.json @@ -5,7 +5,7 @@ "QDocModule": "qtassistant", "QtParts": ["tools"], "QtUsage": "Used in Qt Assistant.", - + "Path": "litehtml/src/gumbo", "Description": "Gumbo is an implementation of the HTML5 parsing algorithm implemented as a pure C99 library with no outside dependencies.", "Homepage": "https://github.com/google/gumbo-parser", "Version": "0.10.1", @@ -19,13 +19,13 @@ "QDocModule": "qtassistant", "QtParts": ["tools"], "QtUsage": "Used in Qt Assistant.", - + "Path": "litehtml", "Description": "litehtml is the lightweight HTML rendering engine with CSS2/CSS3 support.", "Homepage": "https://github.com/litehtml/litehtml", - "Version": "v0.6", + "Version": "v0.9", "LicenseId": "BSD-3-Clause", "License": "BSD 3-Clause \"New\" or \"Revised\" License", "LicenseFile": "litehtml/LICENSE", "Copyright": "Copyright (c) 2013, Yuri Kobets (tordex)" } -]
\ No newline at end of file +] diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7927b50..6535b2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,7 @@ if(NOT TARGET litehtml AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/litehtml/ endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(BUILD_SHARED_LIBS OFF) + set(LITEHTML_BUILD_TESTING OFF) add_subdirectory(3rdparty/litehtml EXCLUDE_FROM_ALL) diff --git a/src/container_qpainter.cpp b/src/container_qpainter.cpp index a3e9350..eeb2b31 100644 --- a/src/container_qpainter.cpp +++ b/src/container_qpainter.cpp @@ -48,9 +48,16 @@ static QRect toQRect(litehtml::position position) return {position.x, position.y, position.width, position.height}; } -static litehtml::elements_vector path(const litehtml::element::ptr &element) +static bool isVisible(const litehtml::element::ptr &element) { - litehtml::elements_vector result; + // TODO render_item::is_visible() would also take m_skip into account, so this might be wrong + return element->css().get_display() != litehtml::display_none + && element->css().get_visibility() == litehtml::visibility_visible; +} + +static litehtml::elements_list path(const litehtml::element::ptr &element) +{ + litehtml::elements_list result; litehtml::element::ptr current = element; while (current) { result.push_back(current); @@ -60,17 +67,23 @@ static litehtml::elements_vector path(const litehtml::element::ptr &element) return result; } -static std::pair<litehtml::element::ptr, size_t> getCommonParent(const litehtml::elements_vector &a, - const litehtml::elements_vector &b) +// <parent, first_different_child_a, first_different_child_b> +static std::tuple<litehtml::element::ptr, litehtml::element::ptr, litehtml::element::ptr> +getCommonParent(const litehtml::elements_list &a, const litehtml::elements_list &b) { litehtml::element::ptr parent; - const size_t minSize = std::min(a.size(), b.size()); - for (size_t i = 0; i < minSize; ++i) { - if (a.at(i) != b.at(i)) - return {parent, i}; - parent = a.at(i); + auto ait = a.cbegin(); + auto bit = b.cbegin(); + while (ait != a.cend() && bit != b.cend()) { + if (*ait != *bit) + return {parent, *ait, *bit}; + parent = *ait; + ++ait; + ++bit; } - return {parent, minSize}; + return {parent, + (ait != a.cend() ? *ait : litehtml::element::ptr()), + (bit != b.cend() ? *bit : litehtml::element::ptr())}; } static std::pair<Selection::Element, Selection::Element> getStartAndEnd(const Selection::Element &a, @@ -81,11 +94,12 @@ static std::pair<Selection::Element, Selection::Element> getStartAndEnd(const Se return {a, b}; return {b, a}; } - const litehtml::elements_vector aPath = path(a.element); - const litehtml::elements_vector bPath = path(b.element); + const litehtml::elements_list aPath = path(a.element); + const litehtml::elements_list bPath = path(b.element); litehtml::element::ptr commonParent; - size_t firstDifferentIndex; - std::tie(commonParent, firstDifferentIndex) = getCommonParent(aPath, bPath); + litehtml::element::ptr aBranch; + litehtml::element::ptr bBranch; + std::tie(commonParent, aBranch, bBranch) = getCommonParent(aPath, bPath); if (!commonParent) { qWarning() << "internal error: litehtml elements do not have common parent"; return {a, b}; @@ -95,10 +109,7 @@ static std::pair<Selection::Element, Selection::Element> getStartAndEnd(const Se if (commonParent == b.element) return {b, b}; // find out if a or b is first in the child sub-trees of commonParent - const litehtml::element::ptr aBranch = aPath.at(firstDifferentIndex); - const litehtml::element::ptr bBranch = bPath.at(firstDifferentIndex); - for (int i = 0; i < int(commonParent->get_children_count()); ++i) { - const litehtml::element::ptr child = commonParent->get_child(i); + for (const litehtml::element::ptr &child : commonParent->children()) { if (child == aBranch) return {a, b}; if (child == bBranch) @@ -108,14 +119,6 @@ static std::pair<Selection::Element, Selection::Element> getStartAndEnd(const Se return {a, b}; } -static int findChild(const litehtml::element::ptr &child, const litehtml::element::ptr &parent) -{ - for (int i = 0; i < int(parent->get_children_count()); ++i) - if (parent->get_child(i) == child) - return i; - return -1; -} - // 1) stops right away if element == stop, otherwise stops whenever stop element is encountered // 2) moves down the first children from element until there is none anymore static litehtml::element::ptr firstLeaf(const litehtml::element::ptr &element, @@ -124,8 +127,8 @@ static litehtml::element::ptr firstLeaf(const litehtml::element::ptr &element, if (element == stop) return element; litehtml::element::ptr current = element; - while (current != stop && current->get_children_count() > 0) - current = current->get_child(0); + while (current != stop && !current->children().empty()) + current = current->children().front(); return current; } @@ -138,17 +141,23 @@ static litehtml::element::ptr nextLeaf(const litehtml::element::ptr &element, if (element == stop) return element; litehtml::element::ptr current = element; - if (current->have_parent()) { + if (!current->is_root()) { // find next sibling const litehtml::element::ptr parent = current->parent(); - const int childIndex = findChild(current, parent); - if (childIndex < 0) { + const litehtml::elements_list &children = parent->children(); + auto childIt = std::find_if(children.cbegin(), + children.cend(), + [¤t](const litehtml::element::ptr &e) { + return e == current; + }); + if (childIt == children.cend()) { qWarning() << "internal error: filed to find litehtml child element in parent"; return stop; } - if (childIndex + 1 >= int(parent->get_children_count())) // no sibling, move up + ++childIt; + if (childIt == children.cend()) // no sibling, move up return nextLeaf(parent, stop); - current = parent->get_child(childIndex + 1); + current = *childIt; } return firstLeaf(current, stop); } @@ -158,9 +167,9 @@ static Selection::Element selectionDetails(const litehtml::element::ptr &element const QPoint &pos) { // shortcut, which _might_ not really be correct - if (element->get_children_count() > 0) + if (!element->children().empty()) return {element, -1, -1}; // everything selected - const QFont &font = toQFont(element->get_font()); + const QFont &font = toQFont(element->css().get_font()); const QFontMetrics fm(font); int previous = 0; for (int i = 0; i < text.size(); ++i) { @@ -172,48 +181,63 @@ static Selection::Element selectionDetails(const litehtml::element::ptr &element return {element, int(text.size()), previous}; } -static Selection::Element deepest_child_at_point(const litehtml::document::ptr &document, - const QPoint &pos, - const QPoint &viewportPos, - Selection::Mode mode) +// Returns whether the intended child was found and stop. +// Does a depth-first iteration over elements that "pos" is inside, and executes +// \a action with them. If \a action returns \c true, the iteration is stopped. +static bool deepest_child_at_point(const litehtml::element::ptr &element, + const QPoint &pos, + const QPoint &viewportPos, + const std::function<bool(const litehtml::element::ptr &)> &action, + int level = 0) { - if (!document) - return {}; + // TODO are there elements for which we should take viewportPos into account instead? + // E.g. fixed position elements? + if (!element) + return false /*continue iterating*/; + const QRect placement = toQRect(element->get_placement()); + // Do not continue down elements that do not cover the position. Exceptions: + // - elements with 0 size (includes anchors and other weird elements) + // - html and body, which for some reason have size == viewport size + if (!placement.size().isEmpty() && element->tag() != litehtml::_html_ + && element->tag() != litehtml::_body_ && !placement.contains(pos)) { + return false /*continue iterating*/; + } + // qDebug() << qPrintable(QString(level * 2, ' ')) << element->dump_get_name() << placement << pos; - // the following does not find the "smallest" element, it often consists of children - // with individual words as text... - const litehtml::element::ptr element = document->root()->get_element_by_point(pos.x(), - pos.y(), - viewportPos.x(), - viewportPos.y()); - // ...so try to find a better match - const std::function<Selection::Element(litehtml::element::ptr, QRect)> recursion = - [&recursion, pos, mode](const litehtml::element::ptr &element, - const QRect &placement) -> Selection::Element { - if (!element) - return {}; - Selection::Element result; - for (int i = 0; i < int(element->get_children_count()); ++i) { - const litehtml::element::ptr child = element->get_child(i); - result = recursion(child, - toQRect(child->get_position()).translated(placement.topLeft())); - if (result.element) - return result; - } - if (placement.contains(pos)) { - litehtml::tstring text; - element->get_text(text); - if (!text.empty()) { - return mode == Selection::Mode::Free - ? selectionDetails(element, - QString::fromStdString(text), - pos - placement.topLeft()) - : Selection::Element({element, -1, -1}); - } - } - return {}; - }; - return recursion(element, element ? toQRect(element->get_placement()) : QRect()); + const litehtml::elements_list &children = element->children(); + for (auto it = children.cbegin(); it != children.cend(); ++it) { + if (deepest_child_at_point(*it, pos, viewportPos, action, level + 1)) + return true; + } + if (placement.contains(pos)) + return action(element); + return false /*continue iterating*/; +} + +static Selection::Element selection_element_at_point(const litehtml::element::ptr &element, + const QPoint &pos, + const QPoint &viewportPos, + Selection::Mode mode) +{ + Selection::Element result; + deepest_child_at_point(element, + pos, + viewportPos, + [mode, &result, &pos](const litehtml::element::ptr &element) { + const QRect placement = toQRect(element->get_placement()); + std::string text; + element->get_text(text); + if (!text.empty()) { + result = mode == Selection::Mode::Free + ? selectionDetails(element, + QString::fromStdString(text), + pos - placement.topLeft()) + : Selection::Element({element, -1, -1}); + return true; + } + return false; /*continue*/ + }); + return result; } // CSS: 400 == normal, 700 == bold. @@ -235,9 +259,9 @@ static QFont::Weight cssWeightToQtWeight(int cssWeight) static QFont::Style toQFontStyle(litehtml::font_style style) { switch (style) { - case litehtml::fontStyleNormal: + case litehtml::font_style_normal: return QFont::StyleNormal; - case litehtml::fontStyleItalic: + case litehtml::font_style_italic: return QFont::StyleItalic; } // should not happen @@ -355,7 +379,7 @@ void Selection::update() { const auto addElement = [this](const Selection::Element &element, const Selection::Element &end = {}) { - litehtml::tstring elemText; + std::string elemText; element.element->get_text(elemText); const QString textStr = QString::fromStdString(elemText); if (!textStr.isEmpty()) { @@ -429,7 +453,7 @@ DocumentContainer::DocumentContainer() DocumentContainer::~DocumentContainer() = default; -litehtml::uint_ptr DocumentContainerPrivate::create_font(const litehtml::tchar_t *faceName, +litehtml::uint_ptr DocumentContainerPrivate::create_font(const char *faceName, int size, int weight, litehtml::font_style italic, @@ -486,14 +510,14 @@ void DocumentContainerPrivate::delete_font(litehtml::uint_ptr hFont) delete font; } -int DocumentContainerPrivate::text_width(const litehtml::tchar_t *text, litehtml::uint_ptr hFont) +int DocumentContainerPrivate::text_width(const char *text, litehtml::uint_ptr hFont) { const QFontMetrics fm(toQFont(hFont)); return fm.horizontalAdvance(QString::fromUtf8(text)); } void DocumentContainerPrivate::draw_text(litehtml::uint_ptr hdc, - const litehtml::tchar_t *text, + const char *text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position &pos) @@ -515,7 +539,7 @@ int DocumentContainerPrivate::get_default_font_size() const return m_defaultFont.pointSize(); } -const litehtml::tchar_t *DocumentContainerPrivate::get_default_font_name() const +const char *DocumentContainerPrivate::get_default_font_name() const { return m_defaultFontFamilyName.constData(); } @@ -552,9 +576,7 @@ void DocumentContainerPrivate::draw_list_marker(litehtml::uint_ptr hdc, } } -void DocumentContainerPrivate::load_image(const litehtml::tchar_t *src, - const litehtml::tchar_t *baseurl, - bool redraw_on_ready) +void DocumentContainerPrivate::load_image(const char *src, const char *baseurl, bool redraw_on_ready) { const auto qtSrc = QString::fromUtf8(src); const auto qtBaseUrl = QString::fromUtf8(baseurl); @@ -570,8 +592,8 @@ void DocumentContainerPrivate::load_image(const litehtml::tchar_t *src, m_pixmaps.insert(url, pixmap); } -void DocumentContainerPrivate::get_image_size(const litehtml::tchar_t *src, - const litehtml::tchar_t *baseurl, +void DocumentContainerPrivate::get_image_size(const char *src, + const char *baseurl, litehtml::size &sz) { const auto qtSrc = QString::fromUtf8(src); @@ -618,8 +640,8 @@ void DocumentContainerPrivate::buildIndex() m_index.elementToIndex.insert({current, index}); if (!inBody) inBody = tagName(current).toLower() == "body"; - if (inBody && current->is_visible()) { - litehtml::tstring text; + if (inBody && isVisible(current)) { + std::string text; current->get_text(text); if (!text.empty()) { m_index.indexToElement.push_back({index, current}); @@ -658,84 +680,89 @@ void DocumentContainerPrivate::clearSelection() } void DocumentContainerPrivate::draw_background(litehtml::uint_ptr hdc, - const litehtml::background_paint &bg) + const std::vector<litehtml::background_paint> &bgs) { auto painter = toQPainter(hdc); - if (bg.is_root) { - // TODO ? - return; - } painter->save(); - painter->setClipRect(toQRect(bg.clip_box)); - const QRegion horizontalMiddle( - QRect(bg.border_box.x, - bg.border_box.y + bg.border_radius.top_left_y, - bg.border_box.width, - bg.border_box.height - bg.border_radius.top_left_y - bg.border_radius.bottom_left_y)); - const QRegion horizontalTop( - QRect(bg.border_box.x + bg.border_radius.top_left_x, - bg.border_box.y, - bg.border_box.width - bg.border_radius.top_left_x - bg.border_radius.top_right_x, - bg.border_radius.top_left_y)); - const QRegion horizontalBottom(QRect(bg.border_box.x + bg.border_radius.bottom_left_x, - bg.border_box.bottom() - bg.border_radius.bottom_left_y, - bg.border_box.width - bg.border_radius.bottom_left_x - - bg.border_radius.bottom_right_x, - bg.border_radius.bottom_left_y)); - const QRegion topLeft(QRect(bg.border_box.left(), - bg.border_box.top(), - 2 * bg.border_radius.top_left_x, - 2 * bg.border_radius.top_left_y), - QRegion::Ellipse); - const QRegion topRight(QRect(bg.border_box.right() - 2 * bg.border_radius.top_right_x, - bg.border_box.top(), - 2 * bg.border_radius.top_right_x, - 2 * bg.border_radius.top_right_y), - QRegion::Ellipse); - const QRegion bottomLeft(QRect(bg.border_box.left(), - bg.border_box.bottom() - 2 * bg.border_radius.bottom_left_y, - 2 * bg.border_radius.bottom_left_x, - 2 * bg.border_radius.bottom_left_y), - QRegion::Ellipse); - const QRegion bottomRight(QRect(bg.border_box.right() - 2 * bg.border_radius.bottom_right_x, - bg.border_box.bottom() - 2 * bg.border_radius.bottom_right_y, - 2 * bg.border_radius.bottom_right_x, - 2 * bg.border_radius.bottom_right_y), + for (const litehtml::background_paint &bg : bgs) { + if (bg.is_root) { + // TODO ? + break; + } + painter->setClipRect(toQRect(bg.clip_box)); + const QRegion horizontalMiddle(QRect(bg.border_box.x, + bg.border_box.y + bg.border_radius.top_left_y, + bg.border_box.width, + bg.border_box.height - bg.border_radius.top_left_y + - bg.border_radius.bottom_left_y)); + const QRegion horizontalTop( + QRect(bg.border_box.x + bg.border_radius.top_left_x, + bg.border_box.y, + bg.border_box.width - bg.border_radius.top_left_x - bg.border_radius.top_right_x, + bg.border_radius.top_left_y)); + const QRegion horizontalBottom(QRect(bg.border_box.x + bg.border_radius.bottom_left_x, + bg.border_box.bottom() - bg.border_radius.bottom_left_y, + bg.border_box.width - bg.border_radius.bottom_left_x + - bg.border_radius.bottom_right_x, + bg.border_radius.bottom_left_y)); + const QRegion topLeft(QRect(bg.border_box.left(), + bg.border_box.top(), + 2 * bg.border_radius.top_left_x, + 2 * bg.border_radius.top_left_y), QRegion::Ellipse); - const QRegion clipRegion = horizontalMiddle.united(horizontalTop) - .united(horizontalBottom) - .united(topLeft) - .united(topRight) - .united(bottomLeft) - .united(bottomRight); - painter->setClipRegion(clipRegion, Qt::IntersectClip); - painter->setPen(Qt::NoPen); - painter->setBrush(toQColor(bg.color)); - painter->drawRect(bg.border_box.x, bg.border_box.y, bg.border_box.width, bg.border_box.height); - drawSelection(painter, toQRect(bg.border_box)); - if (!bg.image.empty()) { - const QPixmap pixmap = getPixmap(QString::fromStdString(bg.image), - QString::fromStdString(bg.baseurl)); - if (bg.repeat == litehtml::background_repeat_no_repeat) { - painter->drawPixmap(QRect(bg.position_x, - bg.position_y, - bg.image_size.width, - bg.image_size.height), - pixmap); - } else if (bg.repeat == litehtml::background_repeat_repeat_x) { - if (bg.image_size.width > 0) { - int x = bg.border_box.left(); - while (x <= bg.border_box.right()) { - painter->drawPixmap(QRect(x, - bg.border_box.top(), - bg.image_size.width, - bg.image_size.height), - pixmap); - x += bg.image_size.width; + const QRegion topRight(QRect(bg.border_box.right() - 2 * bg.border_radius.top_right_x, + bg.border_box.top(), + 2 * bg.border_radius.top_right_x, + 2 * bg.border_radius.top_right_y), + QRegion::Ellipse); + const QRegion bottomLeft(QRect(bg.border_box.left(), + bg.border_box.bottom() - 2 * bg.border_radius.bottom_left_y, + 2 * bg.border_radius.bottom_left_x, + 2 * bg.border_radius.bottom_left_y), + QRegion::Ellipse); + const QRegion bottomRight(QRect(bg.border_box.right() - 2 * bg.border_radius.bottom_right_x, + bg.border_box.bottom() - 2 * bg.border_radius.bottom_right_y, + 2 * bg.border_radius.bottom_right_x, + 2 * bg.border_radius.bottom_right_y), + QRegion::Ellipse); + const QRegion clipRegion = horizontalMiddle.united(horizontalTop) + .united(horizontalBottom) + .united(topLeft) + .united(topRight) + .united(bottomLeft) + .united(bottomRight); + painter->setClipRegion(clipRegion, Qt::IntersectClip); + painter->setPen(Qt::NoPen); + painter->setBrush(toQColor(bg.color)); + painter->drawRect(bg.border_box.x, + bg.border_box.y, + bg.border_box.width, + bg.border_box.height); + drawSelection(painter, toQRect(bg.border_box)); + if (!bg.image.empty()) { + const QPixmap pixmap = getPixmap(QString::fromStdString(bg.image), + QString::fromStdString(bg.baseurl)); + if (bg.repeat == litehtml::background_repeat_no_repeat) { + painter->drawPixmap(QRect(bg.position_x, + bg.position_y, + bg.image_size.width, + bg.image_size.height), + pixmap); + } else if (bg.repeat == litehtml::background_repeat_repeat_x) { + if (bg.image_size.width > 0) { + int x = bg.border_box.left(); + while (x <= bg.border_box.right()) { + painter->drawPixmap(QRect(x, + bg.border_box.top(), + bg.image_size.width, + bg.image_size.height), + pixmap); + x += bg.image_size.width; + } } + } else { + qWarning(log) << "unsupported background repeat" << bg.repeat; } - } else { - qWarning(log) << "unsupported background repeat" << bg.repeat; } } painter->restore(); @@ -807,12 +834,12 @@ void DocumentContainerPrivate::draw_borders(litehtml::uint_ptr hdc, } } -void DocumentContainerPrivate::set_caption(const litehtml::tchar_t *caption) +void DocumentContainerPrivate::set_caption(const char *caption) { m_caption = QString::fromUtf8(caption); } -void DocumentContainerPrivate::set_base_url(const litehtml::tchar_t *base_url) +void DocumentContainerPrivate::set_base_url(const char *base_url) { m_baseUrl = QString::fromUtf8(base_url); } @@ -826,20 +853,19 @@ void DocumentContainerPrivate::link(const std::shared_ptr<litehtml::document> &d Q_UNUSED(el) } -void DocumentContainerPrivate::on_anchor_click(const litehtml::tchar_t *url, - const litehtml::element::ptr &el) +void DocumentContainerPrivate::on_anchor_click(const char *url, const litehtml::element::ptr &el) { Q_UNUSED(el) if (!m_blockLinks) m_linkCallback(resolveUrl(QString::fromUtf8(url), m_baseUrl)); } -void DocumentContainerPrivate::set_cursor(const litehtml::tchar_t *cursor) +void DocumentContainerPrivate::set_cursor(const char *cursor) { m_cursorCallback(toQCursor(QString::fromUtf8(cursor))); } -void DocumentContainerPrivate::transform_text(litehtml::tstring &text, litehtml::text_transform tt) +void DocumentContainerPrivate::transform_text(std::string &text, litehtml::text_transform tt) { // TODO qDebug(log) << "transform_text"; @@ -847,9 +873,9 @@ void DocumentContainerPrivate::transform_text(litehtml::tstring &text, litehtml: Q_UNUSED(tt) } -void DocumentContainerPrivate::import_css(litehtml::tstring &text, - const litehtml::tstring &url, - litehtml::tstring &baseurl) +void DocumentContainerPrivate::import_css(std::string &text, + const std::string &url, + std::string &baseurl) { const QUrl actualUrl = resolveUrl(QString::fromStdString(url), QString::fromStdString(baseurl)); const QString urlString = actualUrl.toString(QUrl::None); @@ -859,16 +885,12 @@ void DocumentContainerPrivate::import_css(litehtml::tstring &text, } void DocumentContainerPrivate::set_clip(const litehtml::position &pos, - const litehtml::border_radiuses &bdr_radius, - bool valid_x, - bool valid_y) + const litehtml::border_radiuses &bdr_radius) { // TODO qDebug(log) << "set_clip"; Q_UNUSED(pos) Q_UNUSED(bdr_radius) - Q_UNUSED(valid_x) - Q_UNUSED(valid_y) } void DocumentContainerPrivate::del_clip() @@ -883,7 +905,7 @@ void DocumentContainerPrivate::get_client_rect(litehtml::position &client) const } std::shared_ptr<litehtml::element> DocumentContainerPrivate::create_element( - const litehtml::tchar_t *tag_name, + const char *tag_name, const litehtml::string_map &attributes, const std::shared_ptr<litehtml::document> &doc) { @@ -901,7 +923,7 @@ void DocumentContainerPrivate::get_media_features(litehtml::media_features &medi qDebug(log) << "get_media_features"; } -void DocumentContainerPrivate::get_language(litehtml::tstring &language, litehtml::tstring &culture) const +void DocumentContainerPrivate::get_language(std::string &language, std::string &culture) const { // TODO qDebug(log) << "get_language"; @@ -923,7 +945,9 @@ void DocumentContainer::setDocument(const QByteArray &data, DocumentContainerCon { d->m_pixmaps.clear(); d->clearSelection(); - d->m_document = litehtml::document::createFromUTF8(data.constData(), d.get(), &context->d->context); + d->m_document = litehtml::document::createFromString(data.constData(), + d.get(), + context->d->masterCss.toUtf8().constData()); d->buildIndex(); } @@ -988,10 +1012,10 @@ QVector<QRect> DocumentContainer::mousePressEvent(const QPoint &documentPos, redrawRects.append(d->m_selection.boundingRect()); d->clearSelection(); d->m_selection.selectionStartDocumentPos = documentPos; - d->m_selection.startElem = deepest_child_at_point(d->m_document, - documentPos, - viewportPos, - d->m_selection.mode); + d->m_selection.startElem = selection_element_at_point(d->m_document->root(), + documentPos, + viewportPos, + d->m_selection.mode); // post to litehtml litehtml::position::vector redrawBoxes; if (d->m_document->on_lbutton_down( @@ -1013,10 +1037,10 @@ QVector<QRect> DocumentContainer::mouseMoveEvent(const QPoint &documentPos, || (!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, - d->m_selection.mode); + const Selection::Element element = selection_element_at_point(d->m_document->root(), + documentPos, + viewportPos, + d->m_selection.mode); if (element.element) { redrawRects.append( d->m_selection.boundingRect() /*.adjusted(-1, -1, +1, +1)*/); // redraw old selection area @@ -1068,10 +1092,10 @@ QVector<QRect> DocumentContainer::mouseDoubleClickEvent(const QPoint &documentPo QVector<QRect> redrawRects; d->clearSelection(); d->m_selection.mode = Selection::Mode::Word; - const Selection::Element element = deepest_child_at_point(d->m_document, - documentPos, - viewportPos, - d->m_selection.mode); + const Selection::Element element = selection_element_at_point(d->m_document->root(), + documentPos, + viewportPos, + d->m_selection.mode); if (element.element) { d->m_selection.startElem = element; d->m_selection.endElem = d->m_selection.startElem; @@ -1105,11 +1129,19 @@ QUrl DocumentContainer::linkAt(const QPoint &documentPos, const QPoint &viewport { if (!d->m_document) return {}; - const litehtml::element::ptr element = d->m_document->root()->get_element_by_point( - documentPos.x(), documentPos.y(), viewportPos.x(), viewportPos.y()); - if (!element) - return {}; - const char *href = element->get_attr("href"); + const char *href = nullptr; + deepest_child_at_point(d->m_document->root(), + documentPos, + viewportPos, + [&href](const litehtml::element::ptr &e) { + const litehtml::element::ptr parent = e->parent(); + if (parent && parent->tag() == litehtml::_a_) { + href = parent->get_attr("href"); + if (href) + return true; + } + return false; /*continue*/ + }); if (href) return d->resolveUrl(QString::fromUtf8(href), d->m_baseUrl); return {}; @@ -1172,10 +1204,10 @@ void DocumentContainer::findText(const QString &text, } const auto fillXPos = [](const Selection::Element &e) { - litehtml::tstring ttext; + std::string ttext; e.element->get_text(ttext); const QString text = QString::fromStdString(ttext); - const QFont &font = toQFont(e.element->get_font()); + const QFont &font = toQFont(e.element->css().get_font()); const QFontMetrics fm(font); return Selection::Element{e.element, e.index, fm.size(0, text.left(e.index)).width()}; }; @@ -1227,7 +1259,7 @@ void DocumentContainer::setDefaultFont(const QFont &font) // we need to trigger the reparse of this info. if (d->m_document && d->m_document->root()) { d->m_document->root()->refresh_styles(); - d->m_document->root()->parse_styles(); + d->m_document->root()->compute_styles(); } } @@ -1271,27 +1303,26 @@ void DocumentContainer::setClipboardCallback(const DocumentContainer::ClipboardC d->m_clipboardCallback = callback; } +static litehtml::element::ptr elementForY(int y, const litehtml::element::ptr &element) +{ + if (!element) + return {}; + if (element->get_placement().y >= y) + return element; + for (const litehtml::element::ptr &child : element->children()) { + litehtml::element::ptr result = elementForY(y, child); + if (result) + return result; + } + return {}; +} + 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()); + return elementForY(y, document->root()); } int DocumentContainer::withFixedElementPosition(int y, const std::function<void()> &action) @@ -1379,5 +1410,5 @@ DocumentContainerContext::~DocumentContainerContext() = default; void DocumentContainerContext::setMasterStyleSheet(const QString &css) { - d->context.load_master_stylesheet(css.toUtf8().constData()); + d->masterCss = css; } diff --git a/src/container_qpainter_p.h b/src/container_qpainter_p.h index e74705f..dfd8152 100644 --- a/src/container_qpainter_p.h +++ b/src/container_qpainter_p.h @@ -58,55 +58,49 @@ struct Index class DocumentContainerPrivate final : public litehtml::document_container { public: // document_container API - litehtml::uint_ptr create_font(const litehtml::tchar_t *faceName, + litehtml::uint_ptr create_font(const char *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; + int text_width(const char *text, litehtml::uint_ptr hFont) override; void draw_text(litehtml::uint_ptr hdc, - const litehtml::tchar_t *text, + const char *text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position &pos) override; int pt_to_px(int pt) const override; int get_default_font_size() const override; - const litehtml::tchar_t *get_default_font_name() const override; + const char *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 load_image(const char *src, const char *baseurl, bool redraw_on_ready) override; + void get_image_size(const char *src, const char *baseurl, litehtml::size &sz) override; + void draw_background(litehtml::uint_ptr hdc, + const std::vector<litehtml::background_paint> &bgs) 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 set_caption(const char *caption) override; + void set_base_url(const char *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 on_anchor_click(const char *url, const litehtml::element::ptr &el) override; + void set_cursor(const char *cursor) override; + void transform_text(std::string &text, litehtml::text_transform tt) override; + void import_css(std::string &text, const std::string &url, std::string &baseurl) override; void set_clip(const litehtml::position &pos, - const litehtml::border_radiuses &bdr_radius, - bool valid_x, - bool valid_y) override; + const litehtml::border_radiuses &bdr_radius) 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; + std::shared_ptr<litehtml::element> create_element( + const char *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; + void get_language(std::string &language, std::string &culture) const override; QPixmap getPixmap(const QString &imageUrl, const QString &baseUrl); QString serifFont() const; @@ -141,5 +135,5 @@ public: // document_container API class DocumentContainerContextPrivate { public: - litehtml::context context; + QString masterCss; }; |