@@ -196,9 +196,61 @@ static Selection::Element selectionDetails(const litehtml::element::ptr &element
196196 const QString &text,
197197 const QPoint &pos)
198198{
199- // shortcut, which _might_ not really be correct
200- if (element->get_children_count () > 0 )
201- return {element, -1 , -1 }; // everything selected
199+ // If element has children, the text contains all descendant text concatenated
200+ // For better precision, we should find the actual leaf child at this position
201+ if (element->get_children_count () > 0 ) {
202+ // Try to find a child leaf element that contains this position
203+ const std::function<Selection::Element (litehtml::element::ptr, QPoint)> findLeaf =
204+ [&findLeaf, pos](const litehtml::element::ptr &elem,
205+ const QPoint &offset) -> Selection::Element {
206+ if (!elem)
207+ return {};
208+
209+ const QRect elemPos = toQRect (elem->get_position ()).translated (offset);
210+
211+ if (!elemPos.contains (pos))
212+ return {};
213+
214+ // Try children first
215+ for (int i = 0 ; i < int (elem->get_children_count ()); ++i) {
216+ const litehtml::element::ptr child = elem->get_child (i);
217+ Selection::Element result = findLeaf (child, elemPos.topLeft ());
218+ if (result.element )
219+ return result;
220+ }
221+
222+ // No children found, use this element if it has text
223+ litehtml::tstring elemText;
224+ elem->get_text (elemText);
225+ if (!elemText.empty ()) {
226+ const QString textStr = QString::fromStdString (elemText);
227+ const QFont &font = toQFont (elem->get_font ());
228+ const QFontMetrics fm (font);
229+ const QPoint relativePos = pos - elemPos.topLeft ();
230+
231+ int previous = 0 ;
232+ for (int i = 0 ; i < textStr.size (); ++i) {
233+ const int width = fm.size (0 , textStr.left (i + 1 )).width ();
234+ if ((width + previous) / 2 >= relativePos.x ())
235+ return {elem, i, previous};
236+ previous = width;
237+ }
238+ return {elem, int (textStr.size ()), previous};
239+ }
240+
241+ return {};
242+ };
243+
244+ const QRect elementRect = toQRect (element->get_placement ());
245+ Selection::Element result = findLeaf (element, elementRect.topLeft ());
246+ if (result.element )
247+ return result;
248+
249+ // Fallback: return the element with index at the start
250+ return {element, 0 , 0 };
251+ }
252+
253+ // Element has no children - calculate precise character position
202254 const QFont &font = toQFont (element->get_font ());
203255 const QFontMetrics fm (font);
204256 int previous = 0 ;
@@ -219,26 +271,30 @@ static Selection::Element deepest_child_at_point(const litehtml::document::ptr &
219271 if (!document)
220272 return {};
221273
222- // the following does not find the "smallest" element, it often consists of children
223- // with individual words as text...
274+ // Find the element at this point
224275 const litehtml::element::ptr element = document->root ()->get_element_by_point (pos.x (),
225276 pos.y (),
226277 viewportPos.x (),
227278 viewportPos.y ());
228- // ...so try to find a better match
279+ // Recursively find the deepest child that contains the point and has text
229280 const std::function<Selection::Element (litehtml::element::ptr, QRect)> recursion =
230281 [&recursion, pos, mode](const litehtml::element::ptr &element,
231282 const QRect &placement) -> Selection::Element {
232283 if (!element)
233284 return {};
234- Selection::Element result;
285+
286+ // First, try to find a deeper child that contains the point
287+ Selection::Element deepestResult;
235288 for (int i = 0 ; i < int (element->get_children_count ()); ++i) {
236289 const litehtml::element::ptr child = element->get_child (i);
237- result = recursion (child,
238- toQRect (child->get_position ()).translated (placement.topLeft ()));
239- if (result.element )
240- return result;
290+ const QRect childPlacement = toQRect (child->get_position ())
291+ .translated (placement.topLeft ());
292+ deepestResult = recursion (child, childPlacement);
293+ if (deepestResult.element )
294+ return deepestResult;
241295 }
296+
297+ // No deeper child found, check if this element itself has text content
242298 if (placement.contains (pos)) {
243299 litehtml::tstring text;
244300 element->get_text (text);
@@ -250,6 +306,7 @@ static Selection::Element deepest_child_at_point(const litehtml::document::ptr &
250306 : Selection::Element ({element, -1 , -1 });
251307 }
252308 }
309+
253310 return {};
254311 };
255312 return recursion (element, element ? toQRect (element->get_placement ()) : QRect ());
0 commit comments