Big wxRichTextCtrl performance increase due to faster wrapping code

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/WX_2_8_BRANCH@50541 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2007-12-06 12:25:59 +00:00
parent 6d8d750e37
commit 7a6db76600
2 changed files with 119 additions and 31 deletions

View File

@@ -98,6 +98,7 @@ All (GUI):
- Ensure that wxGrid::AutoSizeColumn/Row() never sets column/row size - Ensure that wxGrid::AutoSizeColumn/Row() never sets column/row size
smaller than the minimal size. smaller than the minimal size.
- Added <scrollrate> parameter to wxScrolledWindow XRC handler. - Added <scrollrate> parameter to wxScrolledWindow XRC handler.
- wxRichTextCtrl performance has been improved considerably.
All (Unix): All (Unix):

View File

@@ -49,6 +49,48 @@ WX_DEFINE_LIST(wxRichTextLineList)
const wxChar wxRichTextLineBreakChar = (wxChar) 29; const wxChar wxRichTextLineBreakChar = (wxChar) 29;
// Helpers for efficiency
inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
{
const wxFont& font1 = dc.GetFont();
if (font1.IsOk() && font.IsOk())
{
if (font1.GetPointSize() == font.GetPointSize() &&
font1.GetFamily() == font.GetFamily() &&
font1.GetStyle() == font.GetStyle() &&
font1.GetWeight() == font.GetWeight() &&
font1.GetFaceName() == font.GetFaceName())
return;
}
dc.SetFont(font);
}
inline void wxCheckSetPen(wxDC& dc, const wxPen& pen)
{
const wxPen& pen1 = dc.GetPen();
if (pen1.IsOk() && pen.IsOk())
{
if (pen1.GetWidth() == pen.GetWidth() &&
pen1.GetStyle() == pen.GetStyle() &&
pen1.GetColour() == pen.GetColour())
return;
}
dc.SetPen(pen);
}
inline void wxCheckSetBrush(wxDC& dc, const wxBrush& brush)
{
const wxBrush& brush1 = dc.GetBrush();
if (brush1.IsOk() && brush.IsOk())
{
if (brush1.GetStyle() == brush.GetStyle() &&
brush1.GetColour() == brush.GetColour())
return;
}
dc.SetBrush(brush);
}
/*! /*!
* wxRichTextObject * wxRichTextObject
* This is the base for drawable objects. * This is the base for drawable objects.
@@ -3059,7 +3101,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
else else
font = (*wxNORMAL_FONT); font = (*wxNORMAL_FONT);
dc.SetFont(font); wxCheckSetFont(dc, font);
lineHeight = dc.GetCharHeight(); lineHeight = dc.GetCharHeight();
linePos = GetPosition(); linePos = GetPosition();
@@ -3157,7 +3199,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
// Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc. // Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc.
if (attr.GetLineSpacing() != 10 && attr.GetFont().Ok()) if (attr.GetLineSpacing() != 10 && attr.GetFont().Ok())
{ {
dc.SetFont(attr.GetFont()); wxCheckSetFont(dc, attr.GetFont());
lineSpacing = (ConvertTenthsMMToPixels(dc, dc.GetCharHeight()) * attr.GetLineSpacing())/10; lineSpacing = (ConvertTenthsMMToPixels(dc, dc.GetCharHeight()) * attr.GetLineSpacing())/10;
} }
@@ -3192,13 +3234,24 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
int lineCount = 0; int lineCount = 0;
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
wxRichTextObject* child = node->GetData();
child->SetCachedSize(wxDefaultSize);
child->Layout(dc, rect, style);
node = node->GetNext();
}
// Split up lines // Split up lines
// We may need to go back to a previous child, in which case create the new line, // We may need to go back to a previous child, in which case create the new line,
// find the child corresponding to the start position of the string, and // find the child corresponding to the start position of the string, and
// continue. // continue.
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst(); node = m_children.GetFirst();
while (node) while (node)
{ {
wxRichTextObject* child = node->GetData(); wxRichTextObject* child = node->GetData();
@@ -3210,9 +3263,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
// can't tell the position until the size is determined. So possibly introduce // can't tell the position until the size is determined. So possibly introduce
// another layout phase. // another layout phase.
// TODO: can't this be called only once per child?
child->Layout(dc, rect, style);
// Available width depends on whether we're on the first or subsequent lines // Available width depends on whether we're on the first or subsequent lines
int availableSpaceForText = (lineCount == 0 ? availableTextSpaceFirstLine : availableTextSpaceSubsequentLines); int availableSpaceForText = (lineCount == 0 ? availableTextSpaceFirstLine : availableTextSpaceSubsequentLines);
@@ -3337,7 +3387,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
if (lineHeight == 0) if (lineHeight == 0)
{ {
if (attr.GetFont().Ok()) if (attr.GetFont().Ok())
dc.SetFont(attr.GetFont()); wxCheckSetFont(dc, attr.GetFont());
lineHeight = dc.GetCharHeight(); lineHeight = dc.GetCharHeight();
} }
if (maxDescent == 0) if (maxDescent == 0)
@@ -3896,18 +3946,53 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d
{ {
// Find the first position where the line exceeds the available space. // Find the first position where the line exceeds the available space.
wxSize sz; wxSize sz;
long i;
long breakPosition = range.GetEnd(); long breakPosition = range.GetEnd();
for (i = range.GetStart(); i <= range.GetEnd(); i++)
{
int descent = 0;
GetRangeSize(wxRichTextRange(range.GetStart(), i), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace) // Binary chop for speed
long minPos = range.GetStart();
long maxPos = range.GetEnd();
while (true)
{
if (minPos == maxPos)
{ {
breakPosition = i-1; int descent = 0;
GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
breakPosition = minPos - 1;
break; break;
} }
else if ((maxPos - minPos) == 1)
{
int descent = 0;
GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
breakPosition = minPos - 1;
else
{
GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
breakPosition = maxPos-1;
}
break;
}
else
{
long nextPos = minPos + ((maxPos - minPos) / 2);
int descent = 0;
GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
if (sz.x > availableSpace)
{
maxPos = nextPos;
}
else
{
minPos = nextPos;
}
}
} }
// Now we know the last position on the line. // Now we know the last position on the line.
@@ -4202,7 +4287,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
// is selected. // is selected.
if (textAttr.GetFont().Ok()) if (textAttr.GetFont().Ok())
dc.SetFont(textAttr.GetFont()); wxCheckSetFont(dc, textAttr.GetFont());
// (a) All selected. // (a) All selected.
if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd()) if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
@@ -4334,8 +4419,8 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttrEx& attr, c
wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT)); wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT)); wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
dc.SetBrush(wxBrush(highlightColour)); wxCheckSetBrush(dc, wxBrush(highlightColour));
dc.SetPen(wxPen(highlightColour)); wxCheckSetPen(dc, wxPen(highlightColour));
dc.SetTextForeground(highlightTextColour); dc.SetTextForeground(highlightTextColour);
dc.SetBackgroundMode(wxTRANSPARENT); dc.SetBackgroundMode(wxTRANSPARENT);
} }
@@ -4387,9 +4472,9 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttrEx& attr, c
if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH)) if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH))
{ {
wxPen oldPen = dc.GetPen(); wxPen oldPen = dc.GetPen();
dc.SetPen(wxPen(attr.GetTextColour(), 1)); wxCheckSetPen(dc, wxPen(attr.GetTextColour(), 1));
dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5)); dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5));
dc.SetPen(oldPen); wxCheckSetPen(dc, oldPen);
} }
x = nextTabPos; x = nextTabPos;
@@ -4411,9 +4496,9 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttrEx& attr, c
if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH)) if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH))
{ {
wxPen oldPen = dc.GetPen(); wxPen oldPen = dc.GetPen();
dc.SetPen(wxPen(attr.GetTextColour(), 1)); wxCheckSetPen(dc, wxPen(attr.GetTextColour(), 1));
dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5)); dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5));
dc.SetPen(oldPen); wxCheckSetPen(dc, oldPen);
} }
x += w; x += w;
@@ -4425,7 +4510,9 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttrEx& attr, c
/// Lay the item out /// Lay the item out
bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style)) bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style))
{ {
GetRangeSize(GetRange(), m_size, m_descent, dc, 0, wxPoint(0, 0)); // Only lay out if we haven't already cached the size
if (m_size.x == -1)
GetRangeSize(GetRange(), m_size, m_descent, dc, 0, wxPoint(0, 0));
return true; return true;
} }
@@ -4455,7 +4542,7 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
// formatted text by doing it in chunks according to the line ranges // formatted text by doing it in chunks according to the line ranges
if (textAttr.GetFont().Ok()) if (textAttr.GetFont().Ok())
dc.SetFont(textAttr.GetFont()); wxCheckSetFont(dc, textAttr.GetFont());
int startPos = range.GetStart() - GetRange().GetStart(); int startPos = range.GetStart() - GetRange().GetStart();
long len = range.GetLength(); long len = range.GetLength();
@@ -5760,13 +5847,13 @@ bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, w
{ {
if (bulletAttr.GetTextColour().Ok()) if (bulletAttr.GetTextColour().Ok())
{ {
dc.SetPen(wxPen(bulletAttr.GetTextColour())); wxCheckSetPen(dc, wxPen(bulletAttr.GetTextColour()));
dc.SetBrush(wxBrush(bulletAttr.GetTextColour())); wxCheckSetBrush(dc, wxBrush(bulletAttr.GetTextColour()));
} }
else else
{ {
dc.SetPen(*wxBLACK_PEN); wxCheckSetPen(dc, *wxBLACK_PEN);
dc.SetBrush(*wxBLACK_BRUSH); wxCheckSetBrush(dc, *wxBLACK_BRUSH);
} }
wxFont font; wxFont font;
@@ -5775,7 +5862,7 @@ bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, w
else else
font = (*wxNORMAL_FONT); font = (*wxNORMAL_FONT);
dc.SetFont(font); wxCheckSetFont(dc, font);
int charHeight = dc.GetCharHeight(); int charHeight = dc.GetCharHeight();
@@ -5845,7 +5932,7 @@ bool wxRichTextStdRenderer::DrawTextBullet(wxRichTextParagraph* paragraph, wxDC&
else else
font = (*wxNORMAL_FONT); font = (*wxNORMAL_FONT);
dc.SetFont(font); wxCheckSetFont(dc, font);
if (attr.GetTextColour().Ok()) if (attr.GetTextColour().Ok())
dc.SetTextForeground(attr.GetTextColour()); dc.SetTextForeground(attr.GetTextColour());
@@ -6445,8 +6532,8 @@ bool wxRichTextImage::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichT
if (selectionRange.Contains(range.GetStart())) if (selectionRange.Contains(range.GetStart()))
{ {
dc.SetBrush(*wxBLACK_BRUSH); wxCheckSetBrush(dc, *wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN); wxCheckSetPen(dc, *wxBLACK_PEN);
dc.SetLogicalFunction(wxINVERT); dc.SetLogicalFunction(wxINVERT);
dc.DrawRectangle(rect); dc.DrawRectangle(rect);
dc.SetLogicalFunction(wxCOPY); dc.SetLogicalFunction(wxCOPY);