diff --git a/src/html/htmlwin.cpp b/src/html/htmlwin.cpp
index 890d647232..8fdbe56cf6 100644
--- a/src/html/htmlwin.cpp
+++ b/src/html/htmlwin.cpp
@@ -1184,6 +1184,90 @@ void wxHtmlWindow::OnPaint(wxPaintEvent& WXUNUSED(event))
}
}
+namespace
+{
+
+// Returns true if leftCell is an ancestor of rightCell.
+bool IsAncestor(const wxHtmlCell* leftCell, const wxHtmlCell* rightCell)
+{
+ for ( const wxHtmlCell* parent = rightCell->GetParent();
+ parent; parent = parent->GetParent() )
+ {
+ if ( leftCell == parent )
+ return true;
+ }
+ return false;
+}
+
+// Returns minimum bounding rectangle of all the cells between fromCell
+// and toCell, inclusive.
+wxRect GetBoundingRect(const wxHtmlCell* const fromCell,
+ const wxHtmlCell* const toCell)
+{
+ wxCHECK_MSG(fromCell || toCell, wxRect(), "At least one cell is required");
+
+ // Check if we have only one cell or the cells are equal.
+ if ( !fromCell )
+ return toCell->GetRect();
+ else if ( !toCell || fromCell == toCell )
+ return fromCell->GetRect();
+
+ // Check if one of the cells is an ancestor of the other.
+ if ( IsAncestor(fromCell, toCell) )
+ return fromCell->GetRect();
+ else if ( IsAncestor(toCell, fromCell) )
+ return toCell->GetRect();
+
+ // Combine MBRs, starting with the fromCell.
+ wxRect boundingRect = fromCell->GetRect();
+
+ // For each subtree toward the lowest common ancestor,
+ // combine MBRs until the (subtree of) toCell is reached.
+ for ( const wxHtmlCell *startCell = fromCell,
+ *parent = fromCell->GetParent();
+ parent;
+ startCell = parent, parent = parent->GetParent() )
+ {
+ if ( IsAncestor(parent, toCell) )
+ {
+ // Combine all the cells up to the toCell or its subtree.
+ for ( const wxHtmlCell* nextCell = startCell->GetNext();
+ nextCell;
+ nextCell = nextCell->GetNext() )
+ {
+ if ( nextCell == toCell )
+ return boundingRect.Union(toCell->GetRect());
+
+ if ( IsAncestor(nextCell, toCell) )
+ {
+ return boundingRect.Union(GetBoundingRect(
+ nextCell->GetFirstTerminal(), toCell));
+ }
+
+ boundingRect.Union(nextCell->GetRect());
+ }
+
+ wxFAIL_MSG("Unexpected: toCell is not reachable from the fromCell");
+ return GetBoundingRect(toCell, fromCell);
+ }
+ else
+ {
+ // Combine rest of current container.
+ for ( const wxHtmlCell* nextCell = startCell->GetNext();
+ nextCell;
+ nextCell = nextCell->GetNext() )
+ {
+ boundingRect.Union(nextCell->GetRect());
+ }
+ }
+ }
+
+ wxFAIL_MSG("The cells have no common ancestor");
+ return wxRect();
+}
+
+} // namespace
+
void wxHtmlWindow::OnFocusEvent(wxFocusEvent& event)
{
event.Skip();
@@ -1198,16 +1282,16 @@ void wxHtmlWindow::OnFocusEvent(wxFocusEvent& event)
const wxHtmlCell* toCell = m_selection->GetToCell();
wxCHECK_RET(fromCell || toCell,
"Unexpected: selection is set but cells are not");
- if ( !fromCell )
- fromCell = toCell;
- if ( !toCell )
- toCell = fromCell;
- const wxPoint topLeft = fromCell->GetAbsPos();
- const wxPoint bottomRight = toCell->GetAbsPos() +
- wxSize(toCell->GetWidth(), toCell->GetHeight());
- RefreshRect(wxRect(CalcScrolledPosition(topLeft),
- CalcScrolledPosition(bottomRight)));
+ wxRect boundingRect = GetBoundingRect(fromCell, toCell);
+
+ boundingRect = wxRect
+ (
+ CalcScrolledPosition(boundingRect.GetTopLeft()),
+ CalcScrolledPosition(boundingRect.GetBottomRight())
+ );
+
+ RefreshRect(boundingRect);
}