From a7dc1c0e0f60d80fb1a3cbaa909d3c28ebc44151 Mon Sep 17 00:00:00 2001 From: Pavel Kalugin Date: Thu, 11 Apr 2019 08:01:57 +0300 Subject: [PATCH] Fix text jumps during selection dragging on MSW When selecting the text in wxHtmlWindow by dragging the mouse the text to the right of the selection sometimes jumps horizontally. This happens only on MSW and only for TrueType fonts. The reason is that wxDC::GetPartialTextExtents() and wxDC::GetTextExtent() give different results if the text contains characters with underhangs or overhangs. Fix this by caching results of wxDC::GetPartialTextExtents() and using them instead of calling wxDC::GetTextExtent(). --- include/wx/html/htmlcell.h | 17 +++++++++++++++-- src/html/htmlcell.cpp | 28 +++++++++++++++++----------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h index d95fe95a2e..0068c8c173 100644 --- a/include/wx/html/htmlcell.h +++ b/include/wx/html/htmlcell.h @@ -35,7 +35,8 @@ public: wxHtmlSelection() : m_fromPos(wxDefaultPosition), m_toPos(wxDefaultPosition), m_fromCharacterPos(-1), m_toCharacterPos(-1), - m_fromCell(NULL), m_toCell(NULL) {} + m_fromCell(NULL), m_toCell(NULL), + m_extBeforeSel(0), m_extBeforeSelEnd(0) {} // this version is used for the user selection defined with the mouse void Set(const wxPoint& fromPos, const wxHtmlCell *fromCell, @@ -58,6 +59,11 @@ public: wxCoord GetFromCharacterPos () const { return m_fromCharacterPos; } wxCoord GetToCharacterPos () const { return m_toCharacterPos; } + void SetExtentBeforeSelection(unsigned ext) { m_extBeforeSel = ext; } + void SetExtentBeforeSelectionEnd(unsigned ext) { m_extBeforeSelEnd = ext; } + unsigned GetExtentBeforeSelection() const { return m_extBeforeSel; } + unsigned GetExtentBeforeSelectionEnd() const { return m_extBeforeSelEnd; } + bool IsEmpty() const { return m_fromPos == wxDefaultPosition && m_toPos == wxDefaultPosition; } @@ -66,6 +72,12 @@ private: wxPoint m_fromPos, m_toPos; wxCoord m_fromCharacterPos, m_toCharacterPos; const wxHtmlCell *m_fromCell, *m_toCell; + + // Extent of the text before selection start. + unsigned m_extBeforeSel; + + // Extent of the text from the beginning to the selection end. + unsigned m_extBeforeSelEnd; }; @@ -431,7 +443,8 @@ protected: void SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const; void Split(const wxDC& dc, const wxPoint& selFrom, const wxPoint& selTo, - unsigned& pos1, unsigned& pos2) const; + unsigned& pos1, unsigned& pos2, + unsigned& ext1, unsigned& ext2) const; wxString m_Word; bool m_allowLinebreak; diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp index a559df99f2..a853cc0084 100644 --- a/src/html/htmlcell.cpp +++ b/src/html/htmlcell.cpp @@ -343,7 +343,8 @@ void wxHtmlWordCell::SetPreviousWord(wxHtmlWordCell *cell) // where s2 and s3 start: void wxHtmlWordCell::Split(const wxDC& dc, const wxPoint& selFrom, const wxPoint& selTo, - unsigned& pos1, unsigned& pos2) const + unsigned& pos1, unsigned& pos2, + unsigned& ext1, unsigned& ext2) const { wxPoint pt1 = (selFrom == wxDefaultPosition) ? wxDefaultPosition : selFrom - GetAbsPos(); @@ -400,21 +401,30 @@ void wxHtmlWordCell::Split(const wxDC& dc, pos2 = j; wxASSERT( pos2 >= pos1 ); + + ext1 = pos1 == 0 ? 0 : (pos1 < widths.size() ? widths[pos1-1] : widths.Last()); + ext2 = pos2 == 0 ? 0 : (pos2 < widths.size() ? widths[pos2-1] : widths.Last()); } void wxHtmlWordCell::SetSelectionPrivPos(const wxDC& dc, wxHtmlSelection *s) const { - unsigned p1, p2; + unsigned p1, p2, ext1, ext2; Split(dc, this == s->GetFromCell() ? s->GetFromPos() : wxDefaultPosition, this == s->GetToCell() ? s->GetToPos() : wxDefaultPosition, - p1, p2); + p1, p2, ext1, ext2); if ( this == s->GetFromCell() ) - s->SetFromCharacterPos (p1); // selection starts here + { + s->SetFromCharacterPos(p1); // selection starts here + s->SetExtentBeforeSelection(ext1); + } if ( this == s->GetToCell() ) - s->SetToCharacterPos (p2); // selection ends here + { + s->SetToCharacterPos(p2); // selection ends here + s->SetExtentBeforeSelectionEnd(ext2); + } } @@ -459,7 +469,6 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, // Selection changing, we must draw the word piecewise: wxHtmlSelection *s = info.GetSelection(); wxString txt; - int w, h; int ofs = 0; // NB: this is quite a hack: in order to compute selection boundaries @@ -479,8 +488,7 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, { txt = m_Word.Mid(0, part1); dc.DrawText(txt, x + m_PosX, y + m_PosY); - dc.GetTextExtent(txt, &w, &h); - ofs += w; + ofs += s->GetExtentBeforeSelection(); } SwitchSelState(dc, info, true); @@ -490,11 +498,9 @@ void wxHtmlWordCell::Draw(wxDC& dc, int x, int y, if ( (size_t)part2 < m_Word.length() ) { - dc.GetTextExtent(txt, &w, &h); - ofs += w; SwitchSelState(dc, info, false); txt = m_Word.Mid(part2); - dc.DrawText(txt, ofs + x + m_PosX, y + m_PosY); + dc.DrawText(txt, x + m_PosX + s->GetExtentBeforeSelectionEnd(), y + m_PosY); } else drawSelectionAfterCell = true;