]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
move Ellipsize() to wxControl so it can be easily used by other controls
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index be0a26852c268fd5ca150609eeb94d3853a58472..33031e957a9dc762c63f6a48a494f5d4919e739b 100644 (file)
@@ -57,6 +57,7 @@ const wxChar wxRichTextLineBreakChar = (wxChar) 29;
 
 inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
 {
+#if 0
     const wxFont& font1 = dc.GetFont();
     if (font1.IsOk() && font.IsOk())
     {
@@ -68,6 +69,7 @@ inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
             font1.GetFaceName() == font.GetFaceName())
             return;
     }
+#endif
     dc.SetFont(font);
 }
 
@@ -425,26 +427,31 @@ wxString wxRichTextCompositeObject::GetTextForRange(const wxRichTextRange& range
 }
 
 /// Recursively merge all pieces that can be merged.
-bool wxRichTextCompositeObject::Defragment()
+bool wxRichTextCompositeObject::Defragment(const wxRichTextRange& range)
 {
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
     {
         wxRichTextObject* child = node->GetData();
-        wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
-        if (composite)
-            composite->Defragment();
-
-        if (node->GetNext())
+        if (range == wxRICHTEXT_ALL || !child->GetRange().IsOutside(range))
         {
-            wxRichTextObject* nextChild = node->GetNext()->GetData();
-            if (child->CanMerge(nextChild) && child->Merge(nextChild))
+            wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
+            if (composite)
+                composite->Defragment();
+
+            if (node->GetNext())
             {
-                nextChild->Dereference();
-                m_children.Erase(node->GetNext());
+                wxRichTextObject* nextChild = node->GetNext()->GetData();
+                if (child->CanMerge(nextChild) && child->Merge(nextChild))
+                {
+                    nextChild->Dereference();
+                    m_children.Erase(node->GetNext());
 
-                // Don't set node -- we'll see if we can merge again with the next
-                // child.
+                    // Don't set node -- we'll see if we can merge again with the next
+                    // child.
+                }
+                else
+                    node = node->GetNext();
             }
             else
                 node = node->GetNext();
@@ -584,7 +591,7 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range,
                 // Skip
             }
             else
-                child->Draw(dc, range, selectionRange, childRect, descent, style);
+                child->Draw(dc, range, selectionRange, rect, descent, style);
         }
 
         node = node->GetNext();
@@ -852,25 +859,29 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineAtPosition(long pos, bool c
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
     {
-        // child is a paragraph
-        wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
-        wxASSERT (child != NULL);
-
-        wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
-        while (node2)
+        wxRichTextObject* obj = (wxRichTextObject*) node->GetData();
+        if (obj->GetRange().Contains(pos))
         {
-            wxRichTextLine* line = node2->GetData();
+            // child is a paragraph
+            wxRichTextParagraph* child = wxDynamicCast(obj, wxRichTextParagraph);
+            wxASSERT (child != NULL);
 
-            wxRichTextRange range = line->GetAbsoluteRange();
+            wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
+            while (node2)
+            {
+                wxRichTextLine* line = node2->GetData();
 
-            if (range.Contains(pos) ||
+                wxRichTextRange range = line->GetAbsoluteRange();
 
-                // If the position is end-of-paragraph, then return the last line of
-                // of the paragraph.
-                (range.GetEnd() == child->GetRange().GetEnd()-1) && (pos == child->GetRange().GetEnd()))
-                return line;
+                if (range.Contains(pos) ||
 
-            node2 = node2->GetNext();
+                    // If the position is end-of-paragraph, then return the last line of
+                    // of the paragraph.
+                    ((range.GetEnd() == child->GetRange().GetEnd()-1) && (pos == child->GetRange().GetEnd())))
+                    return line;
+
+                node2 = node2->GetNext();
+            }
         }
 
         node = node->GetNext();
@@ -1787,8 +1798,7 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
                 // we only want the paragraphs to hold this character style, then we _don't_ want to
                 // apply the character style. So we need to be able to choose.
 
-                // if (!paragraphStyle && characterStyle && range.GetStart() != newPara->GetRange().GetEnd())
-                if (!parasOnly && characterStyle && range.GetStart() != newPara->GetRange().GetEnd())
+                if (!parasOnly && (characterStyle|charactersOnly) && range.GetStart() != newPara->GetRange().GetEnd())
                 {
                     wxRichTextRange childRange(range);
                     childRange.LimitTo(newPara->GetRange());
@@ -1937,11 +1947,14 @@ static bool wxHasStyle(long flags, long style)
 
 /// Combines 'style' with 'currentStyle' for the purpose of summarising the attributes of a range of
 /// content.
-bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const wxTextAttr& style, long& multipleStyleAttributes, int& multipleTextEffectAttributes)
+bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const wxTextAttr& style, long& multipleStyleAttributes, int& multipleTextEffectAttributes, int& absentStyleAttributes, int& absentTextEffectAttributes)
 {
+    absentStyleAttributes |= (~style.GetFlags() & wxTEXT_ATTR_ALL);
+    absentTextEffectAttributes |= (~style.GetTextEffectFlags() & 0xFFFF);
+
     if (style.HasFont())
     {
-        if (style.HasFontSize() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_FONT_SIZE))
+        if (style.HasFontSize() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_FONT_SIZE))
         {
             if (currentStyle.HasFontSize())
             {
@@ -1958,7 +1971,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             }
         }
 
-        if (style.HasFontItalic() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_FONT_ITALIC))
+        if (style.HasFontItalic() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_FONT_ITALIC))
         {
             if (currentStyle.HasFontItalic())
             {
@@ -1975,7 +1988,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             }
         }
 
-        if (style.HasFontWeight() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_FONT_WEIGHT))
+        if (style.HasFontWeight() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_FONT_WEIGHT))
         {
             if (currentStyle.HasFontWeight())
             {
@@ -1992,7 +2005,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             }
         }
 
-        if (style.HasFontFaceName() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_FONT_FACE))
+        if (style.HasFontFaceName() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_FONT_FACE))
         {
             if (currentStyle.HasFontFaceName())
             {
@@ -2012,7 +2025,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             }
         }
 
-        if (style.HasFontUnderlined() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_FONT_UNDERLINE))
+        if (style.HasFontUnderlined() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_FONT_UNDERLINE))
         {
             if (currentStyle.HasFontUnderlined())
             {
@@ -2030,7 +2043,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
         }
     }
 
-    if (style.HasTextColour() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_TEXT_COLOUR))
+    if (style.HasTextColour() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_TEXT_COLOUR))
     {
         if (currentStyle.HasTextColour())
         {
@@ -2045,7 +2058,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetTextColour(style.GetTextColour());
     }
 
-    if (style.HasBackgroundColour() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_BACKGROUND_COLOUR))
+    if (style.HasBackgroundColour() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_BACKGROUND_COLOUR))
     {
         if (currentStyle.HasBackgroundColour())
         {
@@ -2060,7 +2073,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetBackgroundColour(style.GetBackgroundColour());
     }
 
-    if (style.HasAlignment() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_ALIGNMENT))
+    if (style.HasAlignment() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_ALIGNMENT))
     {
         if (currentStyle.HasAlignment())
         {
@@ -2075,7 +2088,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetAlignment(style.GetAlignment());
     }
 
-    if (style.HasTabs() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_TABS))
+    if (style.HasTabs() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_TABS))
     {
         if (currentStyle.HasTabs())
         {
@@ -2090,7 +2103,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetTabs(style.GetTabs());
     }
 
-    if (style.HasLeftIndent() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_LEFT_INDENT))
+    if (style.HasLeftIndent() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_LEFT_INDENT))
     {
         if (currentStyle.HasLeftIndent())
         {
@@ -2105,7 +2118,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetLeftIndent(style.GetLeftIndent(), style.GetLeftSubIndent());
     }
 
-    if (style.HasRightIndent() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_RIGHT_INDENT))
+    if (style.HasRightIndent() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_RIGHT_INDENT))
     {
         if (currentStyle.HasRightIndent())
         {
@@ -2120,7 +2133,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetRightIndent(style.GetRightIndent());
     }
 
-    if (style.HasParagraphSpacingAfter() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_PARA_SPACING_AFTER))
+    if (style.HasParagraphSpacingAfter() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_PARA_SPACING_AFTER))
     {
         if (currentStyle.HasParagraphSpacingAfter())
         {
@@ -2135,7 +2148,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetParagraphSpacingAfter(style.GetParagraphSpacingAfter());
     }
 
-    if (style.HasParagraphSpacingBefore() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_PARA_SPACING_BEFORE))
+    if (style.HasParagraphSpacingBefore() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_PARA_SPACING_BEFORE))
     {
         if (currentStyle.HasParagraphSpacingBefore())
         {
@@ -2150,7 +2163,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetParagraphSpacingBefore(style.GetParagraphSpacingBefore());
     }
 
-    if (style.HasLineSpacing() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_LINE_SPACING))
+    if (style.HasLineSpacing() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_LINE_SPACING))
     {
         if (currentStyle.HasLineSpacing())
         {
@@ -2165,7 +2178,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetLineSpacing(style.GetLineSpacing());
     }
 
-    if (style.HasCharacterStyleName() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_CHARACTER_STYLE_NAME))
+    if (style.HasCharacterStyleName() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_CHARACTER_STYLE_NAME))
     {
         if (currentStyle.HasCharacterStyleName())
         {
@@ -2180,7 +2193,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetCharacterStyleName(style.GetCharacterStyleName());
     }
 
-    if (style.HasParagraphStyleName() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_PARAGRAPH_STYLE_NAME))
+    if (style.HasParagraphStyleName() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_PARAGRAPH_STYLE_NAME))
     {
         if (currentStyle.HasParagraphStyleName())
         {
@@ -2195,7 +2208,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetParagraphStyleName(style.GetParagraphStyleName());
     }
 
-    if (style.HasListStyleName() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_LIST_STYLE_NAME))
+    if (style.HasListStyleName() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_LIST_STYLE_NAME))
     {
         if (currentStyle.HasListStyleName())
         {
@@ -2210,7 +2223,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetListStyleName(style.GetListStyleName());
     }
 
-    if (style.HasBulletStyle() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_BULLET_STYLE))
+    if (style.HasBulletStyle() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_BULLET_STYLE))
     {
         if (currentStyle.HasBulletStyle())
         {
@@ -2225,7 +2238,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetBulletStyle(style.GetBulletStyle());
     }
 
-    if (style.HasBulletNumber() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_BULLET_NUMBER))
+    if (style.HasBulletNumber() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_BULLET_NUMBER))
     {
         if (currentStyle.HasBulletNumber())
         {
@@ -2240,7 +2253,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetBulletNumber(style.GetBulletNumber());
     }
 
-    if (style.HasBulletText() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_BULLET_TEXT))
+    if (style.HasBulletText() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_BULLET_TEXT))
     {
         if (currentStyle.HasBulletText())
         {
@@ -2258,7 +2271,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
         }
     }
 
-    if (style.HasBulletName() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_BULLET_NAME))
+    if (style.HasBulletName() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_BULLET_NAME))
     {
         if (currentStyle.HasBulletName())
         {
@@ -2275,7 +2288,7 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
         }
     }
 
-    if (style.HasURL() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_URL))
+    if (style.HasURL() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_URL))
     {
         if (currentStyle.HasURL())
         {
@@ -2292,13 +2305,17 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
         }
     }
 
-    if (style.HasTextEffects() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_EFFECTS))
+    if (style.HasTextEffects() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_EFFECTS))
     {
         if (currentStyle.HasTextEffects())
         {
             // We need to find the bits in the new style that are different:
             // just look at those bits that are specified by the new style.
 
+            // We need to remove the bits and flags that are not common between current style
+            // and new style. In so doing we need to take account of the styles absent from one or more of the
+            // previous styles.
+
             int currentRelevantTextEffects = currentStyle.GetTextEffects() & style.GetTextEffectFlags();
             int newRelevantTextEffects = style.GetTextEffects() & style.GetTextEffectFlags();
 
@@ -2317,9 +2334,17 @@ bool wxRichTextParagraphLayoutBox::CollectStyle(wxTextAttr& currentStyle, const
             currentStyle.SetTextEffects(style.GetTextEffects());
             currentStyle.SetTextEffectFlags(style.GetTextEffectFlags());
         }
+
+        // Mask out the flags and values that cannot be common because they were absent in one or more objecrs
+        // that we've looked at so far
+        currentStyle.SetTextEffects(currentStyle.GetTextEffects() & ~absentTextEffectAttributes);
+        currentStyle.SetTextEffectFlags(currentStyle.GetTextEffectFlags() & ~absentTextEffectAttributes);
+
+        if (currentStyle.GetTextEffectFlags() == 0)
+            currentStyle.SetFlags(currentStyle.GetFlags() & ~wxTEXT_ATTR_EFFECTS);
     }
 
-    if (style.HasOutlineLevel() && !wxHasStyle(multipleStyleAttributes, wxTEXT_ATTR_OUTLINE_LEVEL))
+    if (style.HasOutlineLevel() && !wxHasStyle(multipleStyleAttributes|absentStyleAttributes, wxTEXT_ATTR_OUTLINE_LEVEL))
     {
         if (currentStyle.HasOutlineLevel())
         {
@@ -2349,6 +2374,11 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
     long multipleStyleAttributes = 0;
     int multipleTextEffectAttributes = 0;
 
+    int absentStyleAttributesPara = 0;
+    int absentStyleAttributesChar = 0;
+    int absentTextEffectAttributesPara = 0;
+    int absentTextEffectAttributesChar = 0;
+
     wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
     while (node)
     {
@@ -2359,7 +2389,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
             {
                 wxTextAttr paraStyle = para->GetCombinedAttributes();
 
-                CollectStyle(style, paraStyle, multipleStyleAttributes, multipleTextEffectAttributes);
+                CollectStyle(style, paraStyle, multipleStyleAttributes, multipleTextEffectAttributes, absentStyleAttributesPara, absentTextEffectAttributesPara);
             }
             else
             {
@@ -2369,7 +2399,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
                 // First collect paragraph attributes only
                 wxTextAttr paraStyle = para->GetCombinedAttributes();
                 paraStyle.SetFlags(paraStyle.GetFlags() & wxTEXT_ATTR_PARAGRAPH);
-                CollectStyle(style, paraStyle, multipleStyleAttributes, multipleTextEffectAttributes);
+                CollectStyle(style, paraStyle, multipleStyleAttributes, multipleTextEffectAttributes, absentStyleAttributesPara, absentTextEffectAttributesPara);
 
                 wxRichTextObjectList::compatibility_iterator childNode = para->GetChildren().GetFirst();
 
@@ -2383,7 +2413,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
                         // Now collect character attributes only
                         childStyle.SetFlags(childStyle.GetFlags() & wxTEXT_ATTR_CHARACTER);
 
-                        CollectStyle(style, childStyle, multipleStyleAttributes, multipleTextEffectAttributes);
+                        CollectStyle(style, childStyle, multipleStyleAttributes, multipleTextEffectAttributes, absentStyleAttributesChar, absentTextEffectAttributesChar);
                     }
 
                     childNode = childNode->GetNext();
@@ -3100,7 +3130,7 @@ wxRichTextParagraph::~wxRichTextParagraph()
 }
 
 /// Draw the item
-bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& WXUNUSED(rect), int WXUNUSED(descent), int style)
+bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int WXUNUSED(descent), int style)
 {
     wxTextAttr attr = GetCombinedAttributes();
 
@@ -3179,40 +3209,56 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
         wxRichTextLine* line = node->GetData();
         wxRichTextRange lineRange = line->GetAbsoluteRange();
 
-        int maxDescent = line->GetDescent();
-
         // Lines are specified relative to the paragraph
 
         wxPoint linePosition = line->GetPosition() + GetPosition();
-        wxPoint objectPosition = linePosition;
 
-        // Loop through objects until we get to the one within range
-        wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
-        while (node2)
+        // Don't draw if off the screen
+        if (((style & wxRICHTEXT_DRAW_IGNORE_CACHE) != 0) || ((linePosition.y + line->GetSize().y) >= rect.y && linePosition.y <= rect.y + rect.height))
         {
-            wxRichTextObject* child = node2->GetData();
+            wxPoint objectPosition = linePosition;
+            int maxDescent = line->GetDescent();
 
-            if (!child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
+            // Loop through objects until we get to the one within range
+            wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
+
+            int i = 0;
+            while (node2)
             {
-                // Draw this part of the line at the correct position
-                wxRichTextRange objectRange(child->GetRange());
-                objectRange.LimitTo(lineRange);
+                wxRichTextObject* child = node2->GetData();
 
-                wxSize objectSize;
-                int descent = 0;
-                child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
+                if (child->GetRange().GetLength() > 0 && !child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
+                {
+                    // Draw this part of the line at the correct position
+                    wxRichTextRange objectRange(child->GetRange());
+                    objectRange.LimitTo(lineRange);
+
+                    wxSize objectSize;
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING && wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+                    if (i < (int) line->GetObjectSizes().GetCount())
+                    {
+                        objectSize.x = line->GetObjectSizes()[(size_t) i];
+                    }
+                    else
+#endif
+                    {
+                        int descent = 0;
+                        child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
+                    }
 
-                // Use the child object's width, but the whole line's height
-                wxRect childRect(objectPosition, wxSize(objectSize.x, line->GetSize().y));
-                child->Draw(dc, objectRange, selectionRange, childRect, maxDescent, style);
+                    // Use the child object's width, but the whole line's height
+                    wxRect childRect(objectPosition, wxSize(objectSize.x, line->GetSize().y));
+                    child->Draw(dc, objectRange, selectionRange, childRect, maxDescent, style);
 
-                objectPosition.x += objectSize.x;
-            }
-            else if (child->GetRange().GetStart() > lineRange.GetEnd())
-                // Can break out of inner loop now since we've passed this line's range
-                break;
+                    objectPosition.x += objectSize.x;
+                    i ++;
+                }
+                else if (child->GetRange().GetStart() > lineRange.GetEnd())
+                    // Can break out of inner loop now since we've passed this line's range
+                    break;
 
-            node2 = node2->GetNext();
+                node2 = node2->GetNext();
+            }
         }
 
         node = node->GetNext();
@@ -3221,6 +3267,25 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
     return true;
 }
 
+// Get the range width using partial extents calculated for the whole paragraph.
+static int wxRichTextGetRangeWidth(const wxRichTextParagraph& para, const wxRichTextRange& range, const wxArrayInt& partialExtents)
+{
+    wxASSERT(partialExtents.GetCount() >= (size_t) range.GetLength());
+
+    if (partialExtents.GetCount() < (size_t) range.GetLength())
+        return 0;
+
+    int leftMostPos = 0;
+    if (range.GetStart() - para.GetRange().GetStart() > 0)
+        leftMostPos = partialExtents[range.GetStart() - para.GetRange().GetStart() - 1];
+
+    int rightMostPos = partialExtents[range.GetEnd() - para.GetRange().GetStart()];
+
+    int w = rightMostPos - leftMostPos;
+
+    return w;
+}
+
 /// Lay the item out
 bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
 {
@@ -3276,7 +3341,19 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
 
     int lineCount = 0;
 
-    wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+    wxRichTextObjectList::compatibility_iterator node;
+
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+    wxUnusedVar(style);
+    wxArrayInt partialExtents;
+
+    wxSize paraSize;
+    int paraDescent;
+
+    // This calculates the partial text extents
+    GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+#else
+    node = m_children.GetFirst();
     while (node)
     {
         wxRichTextObject* child = node->GetData();
@@ -3287,14 +3364,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
         node = node->GetNext();
     }
 
-#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
-    wxArrayInt partialExtents;
-
-    wxSize paraSize;
-    int paraDescent;
-
-    // This calculates the partial text extents
-    GetRangeSize(GetRange(), paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED, wxPoint(0,0), & partialExtents);
 #endif
 
     // Split up lines
@@ -3308,6 +3377,12 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
     {
         wxRichTextObject* child = node->GetData();
 
+        if (child->GetRange().GetLength() == 0)
+        {
+            node = node->GetNext();
+            continue;
+        }
+
         // If this is e.g. a composite text box, it will need to be laid out itself.
         // But if just a text fragment or image, for example, this will
         // do nothing. NB: won't we need to set the position after layout?
@@ -3340,7 +3415,15 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
             childDescent = child->GetDescent();
         }
         else
+        {
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+            // Get height only, then the width using the partial extents
+            GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
+            childSize.x = wxRichTextGetRangeWidth(*this, wxRichTextRange(lastEndPos+1, lastPosToUse), partialExtents);
+#else
             GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED, rect.GetPosition());
+#endif
+        }
 
         // Cases:
         // 1) There was a line break BEFORE the natural break
@@ -3369,7 +3452,15 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
             // Let's find the actual size of the current line now
             wxSize actualSize;
             wxRichTextRange actualRange(lastCompletedEndPos+1, wrapPosition);
+
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+            // Get height only, then the width using the partial extents
+            GetRangeSize(actualRange, actualSize, childDescent, dc, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
+            actualSize.x = wxRichTextGetRangeWidth(*this, actualRange, partialExtents);
+#else
             GetRangeSize(actualRange, actualSize, childDescent, dc, wxRICHTEXT_UNFORMATTED);
+#endif
+
             currentWidth = actualSize.x;
             lineHeight = wxMax(lineHeight, actualSize.y);
             maxDescent = wxMax(childDescent, maxDescent);
@@ -3459,17 +3550,59 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
     ClearUnusedLines(lineCount);
 
     // Apply styles to wrapped lines
-    ApplyParagraphStyle(attr, rect);
+    ApplyParagraphStyle(attr, rect, dc);
 
     SetCachedSize(wxSize(maxWidth, currentPosition.y + spaceBeforePara + spaceAfterPara));
 
     m_dirty = false;
 
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
+    // Use the text extents to calculate the size of each fragment in each line
+    wxRichTextLineList::compatibility_iterator lineNode = m_cachedLines.GetFirst();
+    while (lineNode)
+    {
+        wxRichTextLine* line = lineNode->GetData();
+        wxRichTextRange lineRange = line->GetAbsoluteRange();
+
+        // Loop through objects until we get to the one within range
+        wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
+
+        while (node2)
+        {
+            wxRichTextObject* child = node2->GetData();
+
+            if (child->GetRange().GetLength() > 0 && !child->GetRange().IsOutside(lineRange))
+            {
+                wxRichTextRange rangeToUse = lineRange;
+                rangeToUse.LimitTo(child->GetRange());
+
+                // Find the size of the child from the text extents, and store in an array
+                // for drawing later
+                int left = 0;
+                if (rangeToUse.GetStart() > GetRange().GetStart())
+                    left = partialExtents[(rangeToUse.GetStart()-1) - GetRange().GetStart()];
+                int right = partialExtents[rangeToUse.GetEnd() - GetRange().GetStart()];
+                int sz = right - left;
+                line->GetObjectSizes().Add(sz);
+            }
+            else if (child->GetRange().GetStart() > lineRange.GetEnd())
+                // Can break out of inner loop now since we've passed this line's range
+                break;
+
+            node2 = node2->GetNext();
+        }
+
+        lineNode = lineNode->GetNext();
+    }
+#endif
+#endif
+
     return true;
 }
 
 /// Apply paragraph styles, such as centering, to wrapped lines
-void wxRichTextParagraph::ApplyParagraphStyle(const wxTextAttr& attr, const wxRect& rect)
+void wxRichTextParagraph::ApplyParagraphStyle(const wxTextAttr& attr, const wxRect& rect, wxDC& dc)
 {
     if (!attr.HasAlignment())
         return;
@@ -3485,12 +3618,14 @@ void wxRichTextParagraph::ApplyParagraphStyle(const wxTextAttr& attr, const wxRe
         // centering, right-justification
         if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
         {
-            pos.x = (rect.GetWidth() - size.x)/2 + pos.x;
+            int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
+            pos.x = (rect.GetWidth() - (pos.x - rect.x) - rightIndent - size.x)/2 + pos.x;
             line->SetPosition(pos);
         }
         else if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
         {
-            pos.x = pos.x + rect.GetWidth() - size.x;
+            int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
+            pos.x = rect.x + rect.GetWidth() - size.x - rightIndent;
             line->SetPosition(pos);
         }
 
@@ -3613,11 +3748,28 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                 rangeToUse.LimitTo(child->GetRange());
                 int childDescent = 0;
 
-                if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, wxPoint(position.x + sz.x, position.y), p))
+                // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size,
+                // but it's only going to be used after caching has taken place.
+                if ((flags & wxRICHTEXT_HEIGHT_ONLY) && child->GetCachedSize().y != 0)
                 {
+                    childDescent = child->GetDescent();
+                    childSize = child->GetCachedSize();
+
                     sz.y = wxMax(sz.y, childSize.y);
                     sz.x += childSize.x;
                     descent = wxMax(descent, childDescent);
+                }
+                else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, wxPoint(position.x + sz.x, position.y), p))
+                {
+                    sz.y = wxMax(sz.y, childSize.y);
+                    sz.x += childSize.x;
+                    descent = wxMax(descent, childDescent);
+
+                    if ((flags & wxRICHTEXT_CACHE_SIZE) && (rangeToUse == child->GetRange()))
+                    {
+                        child->SetCachedSize(childSize);
+                        child->SetDescent(childDescent);
+                    }
 
                     if (partialExtents)
                     {
@@ -3819,6 +3971,39 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
             }
             else
             {
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+                wxArrayInt partialExtents;
+
+                wxSize paraSize;
+                int paraDescent;
+
+                // This calculates the partial text extents
+                GetRangeSize(lineRange, paraSize, paraDescent, dc, wxRICHTEXT_UNFORMATTED, wxPoint(0,0), & partialExtents);
+
+                int lastX = linePos.x;
+                size_t i;
+                for (i = 0; i < partialExtents.GetCount(); i++)
+                {
+                    int nextX = partialExtents[i] + linePos.x;
+
+                    if (pt.x >= lastX && pt.x <= nextX)
+                    {
+                        textPosition = i + lineRange.GetStart(); // minus 1?
+
+                        // So now we know it's between i-1 and i.
+                        // Let's see if we can be more precise about
+                        // which side of the position it's on.
+
+                        int midPoint = (nextX - lastX)/2 + lastX;
+                        if (pt.x >= midPoint)
+                            return wxRICHTEXT_HITTEST_AFTER;
+                        else
+                            return wxRICHTEXT_HITTEST_BEFORE;
+                    }
+
+                    lastX = nextX;
+                }
+#else
                 long i;
                 int lastX = linePos.x;
                 for (i = lineRange.GetStart(); i <= lineRange.GetEnd(); i++)
@@ -3851,6 +4036,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
                         lastX = nextX;
                     }
                 }
+#endif
             }
         }
 
@@ -3989,7 +4175,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
                     text += textObj->GetTextForRange(range);
                 }
                 else
-                    return true;
+                {
+                    text += wxT(" ");
+                }
             }
 
             node = node->GetNext();
@@ -4009,7 +4197,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
                     text = textObj->GetTextForRange(range) + text;
                 }
                 else
-                    return true;
+                {
+                    text = wxT(" ") + text;
+                }
             }
 
             node = node->GetPrevious();
@@ -4022,6 +4212,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
 /// Find a suitable wrap position.
 bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition, wxArrayInt* partialExtents)
 {
+    if (range.GetLength() <= 0)
+        return false;
+
     // Find the first position where the line exceeds the available space.
     wxSize sz;
     long breakPosition = range.GetEnd();
@@ -4037,11 +4230,11 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d
             widthBefore = 0;
 
         size_t i;
-        for (i = (size_t) range.GetStart(); i < (size_t) range.GetEnd(); i++)
+        for (i = (size_t) range.GetStart(); i <= (size_t) range.GetEnd(); i++)
         {
             int widthFromStartOfThisRange = (*partialExtents)[i - GetRange().GetStart()] - widthBefore;
 
-            if (widthFromStartOfThisRange >= availableSpace)
+            if (widthFromStartOfThisRange > availableSpace)
             {
                 breakPosition = i-1;
                 break;
@@ -4319,12 +4512,18 @@ void wxRichTextLine::Init(wxRichTextParagraph* parent)
     m_pos = wxPoint(0, 0);
     m_size = wxSize(0, 0);
     m_descent = 0;
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
+    m_objectSizes.Clear();
+#endif
 }
 
 /// Copy
 void wxRichTextLine::Copy(const wxRichTextLine& obj)
 {
     m_range = obj.m_range;
+#if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
+    m_objectSizes = obj.m_objectSizes;
+#endif
 }
 
 /// Get the absolute object position
@@ -4693,6 +4892,7 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
         }
     }
 
+    bool haveDescent = false;
     int startPos = range.GetStart() - GetRange().GetStart();
     long len = range.GetLength();
 
@@ -4729,23 +4929,39 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
         while (stringChunk.Find(wxT('\t')) >= 0)
         {
+            int absoluteWidth = 0;
+
             // the string has a tab
             // break up the string at the Tab
             wxString stringFragment = stringChunk.BeforeFirst(wxT('\t'));
             stringChunk = stringChunk.AfterFirst(wxT('\t'));
-            int oldWidth = width;
-            dc.GetTextExtent(stringFragment, & w, & h);
-            width += w;
-            int absoluteWidth = width + position.x;
 
             if (partialExtents)
             {
+                int oldWidth;
+                if (partialExtents->GetCount() > 0)
+                    oldWidth = (*partialExtents)[partialExtents->GetCount()-1];
+                else
+                    oldWidth = 0;
+
                 // Add these partial extents
                 wxArrayInt p;
                 dc.GetPartialTextExtents(stringFragment, p);
                 size_t j;
                 for (j = 0; j < p.GetCount(); j++)
                     partialExtents->Add(oldWidth + p[j]);
+
+                if (partialExtents->GetCount() > 0)
+                    absoluteWidth = (*partialExtents)[(*partialExtents).GetCount()-1] + position.x;
+                else
+                    absoluteWidth = position.x;
+            }
+            else
+            {
+                dc.GetTextExtent(stringFragment, & w, & h);
+                width += w;
+                absoluteWidth = width + position.x;
+                haveDescent = true;
             }
 
             bool notFound = true;
@@ -4776,12 +4992,14 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
     if (!stringChunk.IsEmpty())
     {
-        dc.GetTextExtent(stringChunk, & w, & h, & descent);
-        int oldWidth = width;
-        width += w;
-
         if (partialExtents)
         {
+            int oldWidth;
+            if (partialExtents->GetCount() > 0)
+                oldWidth = (*partialExtents)[partialExtents->GetCount()-1];
+            else
+                oldWidth = 0;
+
             // Add these partial extents
             wxArrayInt p;
             dc.GetPartialTextExtents(stringChunk, p);
@@ -4789,13 +5007,34 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
             for (j = 0; j < p.GetCount(); j++)
                 partialExtents->Add(oldWidth + p[j]);
         }
+        else
+        {
+            dc.GetTextExtent(stringChunk, & w, & h, & descent);
+            width += w;
+            haveDescent = true;
+        }
     }
 
+    if (partialExtents)
+    {
+        int charHeight = dc.GetCharHeight();
+        if ((*partialExtents).GetCount() > 0)
+            w = (*partialExtents)[partialExtents->GetCount()-1];
+        else
+            w = 0;
+        size = wxSize(w, charHeight);
+    }
+    else
+    {
+        size = wxSize(width, dc.GetCharHeight());
+    }
+
+    if (!haveDescent)
+        dc.GetTextExtent(wxT("X"), & w, & h, & descent);
+
     if ( bScript )
         dc.SetFont(font);
 
-    size = wxSize(width, dc.GetCharHeight());
-
     return true;
 }
 
@@ -5012,6 +5251,15 @@ bool wxRichTextBuffer::InsertParagraphsWithUndo(long pos, const wxRichTextParagr
 
     action->GetNewParagraphs() = paragraphs;
 
+    if (p && !p->IsDefault())
+    {
+        for (wxRichTextObjectList::compatibility_iterator node = action->GetNewParagraphs().GetChildren().GetFirst(); node; node = node->GetNext())
+        {
+            wxRichTextObject* child = node->GetData();
+            child->SetAttributes(*p);
+        }
+    }
+
     action->SetPosition(pos);
 
     wxRichTextRange range = wxRichTextRange(pos, pos + paragraphs.GetRange().GetEnd() - 1);
@@ -5094,8 +5342,14 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl, int
     {
         if (para && para->GetRange().GetEnd() == pos)
             pos1 ++;
+
+        // Now see if we need to number the paragraph.
         if (newPara->GetAttributes().HasBulletNumber())
-            newPara->GetAttributes().SetBulletNumber(newPara->GetAttributes().GetBulletNumber()+1);
+        {
+            wxRichTextAttr numberingAttr;
+            if (FindNextParagraphNumber(para, numberingAttr))
+                wxRichTextApplyStyle(newPara->GetAttributes(), (const wxRichTextAttr&) numberingAttr);
+        }
     }
 
     action->SetPosition(pos);
@@ -5204,6 +5458,25 @@ wxTextAttr wxRichTextBuffer::GetStyleForNewParagraph(long pos, bool caretPositio
                 }
             }
         }
+
+        // Also apply list style if present
+        if (lookUpNewParaStyle && !para->GetAttributes().GetListStyleName().IsEmpty() && GetStyleSheet())
+        {
+            wxRichTextListStyleDefinition* listDef = GetStyleSheet()->FindListStyle(para->GetAttributes().GetListStyleName());
+            if (listDef)
+            {
+                int thisIndent = para->GetAttributes().GetLeftIndent();
+                int thisLevel = para->GetAttributes().HasOutlineLevel() ? para->GetAttributes().GetOutlineLevel() : listDef->FindLevelForIndent(thisIndent);
+
+                // Apply the overall list style, and item style for this level
+                wxRichTextAttr listStyle(listDef->GetCombinedStyleForLevel(thisLevel, GetStyleSheet()));
+                wxRichTextApplyStyle(attr, listStyle);
+                attr.SetOutlineLevel(thisLevel);
+                if (para->GetAttributes().HasBulletNumber())
+                    attr.SetBulletNumber(para->GetAttributes().GetBulletNumber());
+            }
+        }
+
         if (!foundAttributes)
         {
             attr = para->GetAttributes();
@@ -5216,14 +5489,6 @@ wxTextAttr wxRichTextBuffer::GetStyleForNewParagraph(long pos, bool caretPositio
             attr.SetFlags(flags);
         }
 
-        // Now see if we need to number the paragraph.
-        if (attr.HasBulletStyle())
-        {
-            wxTextAttr numberingAttr;
-            if (FindNextParagraphNumber(para, numberingAttr))
-                wxRichTextApplyStyle(attr, (const wxTextAttr&) numberingAttr);
-        }
-
         return attr;
     }
     else
@@ -5353,8 +5618,6 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttr& style)
 
     SetDefaultStyle(newStyle);
 
-    // wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize());
-
     return true;
 }
 
@@ -5634,7 +5897,8 @@ bool wxRichTextBuffer::RemoveHandler(const wxString& name)
 }
 
 /// Finds a handler by filename or, if supplied, type
-wxRichTextFileHandler *wxRichTextBuffer::FindHandlerFilenameOrType(const wxString& filename, int imageType)
+wxRichTextFileHandler *wxRichTextBuffer::FindHandlerFilenameOrType(const wxString& filename,
+                                                                   wxRichTextFileType imageType)
 {
     if (imageType != wxRICHTEXT_TYPE_ANY)
         return FindHandler(imageType);
@@ -5664,7 +5928,7 @@ wxRichTextFileHandler* wxRichTextBuffer::FindHandler(const wxString& name)
 }
 
 /// Finds a handler by extension and type
-wxRichTextFileHandler* wxRichTextBuffer::FindHandler(const wxString& extension, int type)
+wxRichTextFileHandler* wxRichTextBuffer::FindHandler(const wxString& extension, wxRichTextFileType type)
 {
     wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
@@ -5679,7 +5943,7 @@ wxRichTextFileHandler* wxRichTextBuffer::FindHandler(const wxString& extension,
 }
 
 /// Finds a handler by type
-wxRichTextFileHandler* wxRichTextBuffer::FindHandler(int type)
+wxRichTextFileHandler* wxRichTextBuffer::FindHandler(wxRichTextFileType type)
 {
     wxList::compatibility_iterator node = sm_handlers.GetFirst();
     while (node)
@@ -5723,7 +5987,7 @@ wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save, wxArrayInt* t
     while (node)
     {
         wxRichTextFileHandler* handler = (wxRichTextFileHandler*) node->GetData();
-        if (handler->IsVisible() && ((save && handler->CanSave()) || !save && handler->CanLoad()))
+        if (handler->IsVisible() && ((save && handler->CanSave()) || (!save && handler->CanLoad())))
         {
             if (combine)
             {
@@ -5757,7 +6021,7 @@ wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save, wxArrayInt* t
 }
 
 /// Load a file
-bool wxRichTextBuffer::LoadFile(const wxString& filename, int type)
+bool wxRichTextBuffer::LoadFile(const wxString& filename, wxRichTextFileType type)
 {
     wxRichTextFileHandler* handler = FindHandlerFilenameOrType(filename, type);
     if (handler)
@@ -5773,7 +6037,7 @@ bool wxRichTextBuffer::LoadFile(const wxString& filename, int type)
 }
 
 /// Save a file
-bool wxRichTextBuffer::SaveFile(const wxString& filename, int type)
+bool wxRichTextBuffer::SaveFile(const wxString& filename, wxRichTextFileType type)
 {
     wxRichTextFileHandler* handler = FindHandlerFilenameOrType(filename, type);
     if (handler)
@@ -5786,7 +6050,7 @@ bool wxRichTextBuffer::SaveFile(const wxString& filename, int type)
 }
 
 /// Load from a stream
-bool wxRichTextBuffer::LoadFile(wxInputStream& stream, int type)
+bool wxRichTextBuffer::LoadFile(wxInputStream& stream, wxRichTextFileType type)
 {
     wxRichTextFileHandler* handler = FindHandler(type);
     if (handler)
@@ -5802,7 +6066,7 @@ bool wxRichTextBuffer::LoadFile(wxInputStream& stream, int type)
 }
 
 /// Save to a stream
-bool wxRichTextBuffer::SaveFile(wxOutputStream& stream, int type)
+bool wxRichTextBuffer::SaveFile(wxOutputStream& stream, wxRichTextFileType type)
 {
     wxRichTextFileHandler* handler = FindHandler(type);
     if (handler)
@@ -5876,7 +6140,7 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
                 wxRichTextBuffer* richTextBuffer = data.GetRichTextBuffer();
                 if (richTextBuffer)
                 {
-                    InsertParagraphsWithUndo(position+1, *richTextBuffer, GetRichTextCtrl(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+                    InsertParagraphsWithUndo(position+1, *richTextBuffer, GetRichTextCtrl(), 0);
                     if (GetRichTextCtrl())
                         GetRichTextCtrl()->ShowPosition(position + richTextBuffer->GetRange().GetEnd());
                     delete richTextBuffer;
@@ -5900,7 +6164,7 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
 #else
                 wxString text2 = text;
 #endif
-                InsertTextWithUndo(position+1, text2, GetRichTextCtrl());
+                InsertTextWithUndo(position+1, text2, GetRichTextCtrl(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
 
                 if (GetRichTextCtrl())
                     GetRichTextCtrl()->ShowPosition(position + text2.Length());
@@ -5921,10 +6185,10 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
                 if (action->GetNewParagraphs().GetChildCount() == 1)
                     action->GetNewParagraphs().SetPartialParagraph(true);
 
-                action->SetPosition(position);
+                action->SetPosition(position+1);
 
                 // Set the range we'll need to delete in Undo
-                action->SetRange(wxRichTextRange(position, position));
+                action->SetRange(wxRichTextRange(position+1, position+1));
 
                 SubmitAction(action);
 
@@ -6323,6 +6587,58 @@ wxRichTextAction::~wxRichTextAction()
 {
 }
 
+void wxRichTextAction::CalculateRefreshOptimizations(wxArrayInt& optimizationLineCharPositions, wxArrayInt& optimizationLineYPositions)
+{
+    // Store a list of line start character and y positions so we can figure out which area
+    // we need to refresh
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+    // NOTE: we're assuming that the buffer is laid out correctly at this point.
+    // If we had several actions, which only invalidate and leave layout until the
+    // paint handler is called, then this might not be true. So we may need to switch
+    // optimisation on only when we're simply adding text and not simultaneously
+    // deleting a selection, for example. Or, we make sure the buffer is laid out correctly
+    // first, but of course this means we'll be doing it twice.
+    if (!m_buffer->GetDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
+    {
+        wxSize clientSize = m_ctrl->GetClientSize();
+        wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+        int lastY = firstVisiblePt.y + clientSize.y;
+
+        wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetRange().GetStart());
+        wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
+        while (node)
+        {
+            wxRichTextParagraph* child = (wxRichTextParagraph*) node->GetData();
+            wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
+            while (node2)
+            {
+                wxRichTextLine* line = node2->GetData();
+                wxPoint pt = line->GetAbsolutePosition();
+                wxRichTextRange range = line->GetAbsoluteRange();
+
+                if (pt.y > lastY)
+                {
+                    node2 = wxRichTextLineList::compatibility_iterator();
+                    node = wxRichTextObjectList::compatibility_iterator();
+                }
+                else if (range.GetStart() > GetPosition() && pt.y >= firstVisiblePt.y)
+                {
+                    optimizationLineCharPositions.Add(range.GetStart());
+                    optimizationLineYPositions.Add(pt.y);
+                }
+
+                if (node2)
+                    node2 = node2->GetNext();
+            }
+
+            if (node)
+                node = node->GetNext();
+        }
+    }
+#endif
+}
+
 bool wxRichTextAction::Do()
 {
     m_buffer->Modify(true);
@@ -6337,49 +6653,7 @@ bool wxRichTextAction::Do()
             wxArrayInt optimizationLineYPositions;
 
 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING
-            // NOTE: we're assuming that the buffer is laid out correctly at this point.
-            // If we had several actions, which only invalidate and leave layout until the
-            // paint handler is called, then this might not be true. So we may need to switch
-            // optimisation on only when we're simply adding text and not simultaneously
-            // deleting a selection, for example. Or, we make sure the buffer is laid out correctly
-            // first, but of course this means we'll be doing it twice.
-            if (!m_buffer->GetDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
-            {
-                wxSize clientSize = m_ctrl->GetClientSize();
-                wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
-                int lastY = firstVisiblePt.y + clientSize.y;
-
-                wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetRange().GetStart());
-                wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
-                while (node)
-                {
-                    wxRichTextParagraph* child = (wxRichTextParagraph*) node->GetData();
-                    wxRichTextLineList::compatibility_iterator node2 = child->GetLines().GetFirst();
-                    while (node2)
-                    {
-                        wxRichTextLine* line = node2->GetData();
-                        wxPoint pt = line->GetAbsolutePosition();
-                        wxRichTextRange range = line->GetAbsoluteRange();
-
-                        if (pt.y > lastY)
-                        {
-                            node2 = wxRichTextLineList::compatibility_iterator();
-                            node = wxRichTextObjectList::compatibility_iterator();
-                        }
-                        else if (range.GetStart() > GetPosition() && pt.y >= firstVisiblePt.y)
-                        {
-                            optimizationLineCharPositions.Add(range.GetStart());
-                            optimizationLineYPositions.Add(pt.y);
-                        }
-
-                        if (node2)
-                            node2 = node2->GetNext();
-                    }
-
-                    if (node)
-                        node = node->GetNext();
-                }
-            }
+            CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
 #endif
 
             m_buffer->InsertFragment(GetRange().GetStart(), m_newParagraphs);
@@ -6404,10 +6678,7 @@ bool wxRichTextAction::Do()
 
             newCaretPosition = wxMin(newCaretPosition, (m_buffer->GetRange().GetEnd()-1));
 
-            if (optimizationLineCharPositions.GetCount() > 0)
-                UpdateAppearance(newCaretPosition, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions);
-            else
-                UpdateAppearance(newCaretPosition, true /* send update event */);
+            UpdateAppearance(newCaretPosition, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
@@ -6422,6 +6693,13 @@ bool wxRichTextAction::Do()
         }
     case wxRICHTEXT_DELETE:
         {
+            wxArrayInt optimizationLineCharPositions;
+            wxArrayInt optimizationLineYPositions;
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+            CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
+#endif
+
             m_buffer->DeleteRange(GetRange());
             m_buffer->UpdateRanges();
             m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
@@ -6430,7 +6708,7 @@ bool wxRichTextAction::Do()
             if (caretPos >= m_buffer->GetRange().GetEnd())
                 caretPos --;
 
-            UpdateAppearance(caretPos, true /* send update event */);
+            UpdateAppearance(caretPos, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
@@ -6476,13 +6754,20 @@ bool wxRichTextAction::Undo()
     {
     case wxRICHTEXT_INSERT:
         {
+            wxArrayInt optimizationLineCharPositions;
+            wxArrayInt optimizationLineYPositions;
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+            CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
+#endif
+
             m_buffer->DeleteRange(GetRange());
             m_buffer->UpdateRanges();
             m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
 
             long newCaretPosition = GetPosition() - 1;
 
-            UpdateAppearance(newCaretPosition, true /* send update event */);
+            UpdateAppearance(newCaretPosition, true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
@@ -6497,11 +6782,18 @@ bool wxRichTextAction::Undo()
         }
     case wxRICHTEXT_DELETE:
         {
+            wxArrayInt optimizationLineCharPositions;
+            wxArrayInt optimizationLineYPositions;
+
+#if wxRICHTEXT_USE_OPTIMIZED_DRAWING
+            CalculateRefreshOptimizations(optimizationLineCharPositions, optimizationLineYPositions);
+#endif
+
             m_buffer->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
             m_buffer->UpdateRanges();
             m_buffer->Invalidate(GetRange());
 
-            UpdateAppearance(GetPosition(), true /* send update event */);
+            UpdateAppearance(GetPosition(), true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
 
             wxRichTextEvent cmdEvent(
                 wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
@@ -6540,7 +6832,7 @@ bool wxRichTextAction::Undo()
 }
 
 /// Update the control appearance
-void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent, wxArrayInt* optimizationLineCharPositions, wxArrayInt* optimizationLineYPositions)
+void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent, wxArrayInt* optimizationLineCharPositions, wxArrayInt* optimizationLineYPositions, bool isDoCmd)
 {
     if (m_ctrl)
     {
@@ -6548,11 +6840,10 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
         if (!m_ctrl->IsFrozen())
         {
             m_ctrl->LayoutContent();
-            m_ctrl->PositionCaret();
 
 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING
             // Find refresh rectangle if we are in a position to optimise refresh
-            if (m_cmdId == wxRICHTEXT_INSERT && optimizationLineCharPositions && optimizationLineCharPositions->GetCount() > 0)
+            if ((m_cmdId == wxRICHTEXT_INSERT || m_cmdId == wxRICHTEXT_DELETE) && optimizationLineCharPositions)
             {
                 size_t i;
 
@@ -6563,17 +6854,57 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                 int firstY = 0;
                 int lastY = firstVisiblePt.y + clientSize.y;
 
-                bool foundStart = false;
                 bool foundEnd = false;
 
                 // position offset - how many characters were inserted
                 int positionOffset = GetRange().GetLength();
 
+                // Determine whether this is Do or Undo, and adjust positionOffset accordingly
+                if ((m_cmdId == wxRICHTEXT_DELETE && isDoCmd) || (m_cmdId == wxRICHTEXT_INSERT && !isDoCmd))
+                    positionOffset = - positionOffset;
+
                 // find the first line which is being drawn at the same position as it was
                 // before. Since we're talking about a simple insertion, we can assume
                 // that the rest of the window does not need to be redrawn.
 
                 wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetPosition());
+                if (para)
+                {
+                    // Find line containing GetPosition().
+                    wxRichTextLine* line = NULL;
+                    wxRichTextLineList::compatibility_iterator node2 = para->GetLines().GetFirst();
+                    while (node2)
+                    {
+                        wxRichTextLine* l = node2->GetData();
+                        wxRichTextRange range = l->GetAbsoluteRange();
+                        if (range.Contains(GetRange().GetStart()-1))
+                        {
+                            line = l;
+                            break;
+                        }
+                        node2 = node2->GetNext();
+                    }
+
+                    if (line)
+                    {
+                        // Step back a couple of lines to where we can be sure of reformatting correctly
+                        wxRichTextLineList::compatibility_iterator lineNode = para->GetLines().Find(line);
+                        if (lineNode)
+                        {
+                            lineNode = lineNode->GetPrevious();
+                            if (lineNode)
+                            {
+                                line = (wxRichTextLine*) lineNode->GetData();
+                                lineNode = lineNode->GetPrevious();
+                                if (lineNode)
+                                    line = (wxRichTextLine*) lineNode->GetData();
+                            }
+                        }
+
+                        firstY = line->GetAbsolutePosition().y;
+                    }
+                }
+
                 wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
                 while (node)
                 {
@@ -6593,14 +6924,19 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                             node2 = wxRichTextLineList::compatibility_iterator();
                             node = wxRichTextObjectList::compatibility_iterator();
                         }
-                        else
+                        // Detect last line in the buffer
+                        else if (!node2->GetNext() && para->GetRange().Contains(m_buffer->GetRange().GetEnd()))
                         {
-                            if (!foundStart)
-                            {
-                                firstY = pt.y - firstVisiblePt.y;
-                                foundStart = true;
-                            }
+                            foundEnd = true;
+                            lastY = pt.y + line->GetSize().y;
 
+                            node2 = wxRichTextLineList::compatibility_iterator();
+                            node = wxRichTextObjectList::compatibility_iterator();
+
+                            break;
+                        }
+                        else
+                        {
                             // search for this line being at the same position as before
                             for (i = 0; i < optimizationLineCharPositions->GetCount(); i++)
                             {
@@ -6609,7 +6945,8 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                                 {
                                     // Stop, we're now the same as we were
                                     foundEnd = true;
-                                    lastY = pt.y - firstVisiblePt.y;
+
+                                    lastY = pt.y;
 
                                     node2 = wxRichTextLineList::compatibility_iterator();
                                     node = wxRichTextObjectList::compatibility_iterator();
@@ -6627,22 +6964,21 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                         node = node->GetNext();
                 }
 
-                if (!foundStart)
-                    firstY = firstVisiblePt.y;
+                firstY = wxMax(firstVisiblePt.y, firstY);
                 if (!foundEnd)
                     lastY = firstVisiblePt.y + clientSize.y;
 
-                wxRect rect(firstVisiblePt.x, firstY, firstVisiblePt.x + clientSize.x, lastY - firstY);
+                // Convert to device coordinates
+                wxRect rect(m_ctrl->GetPhysicalPoint(wxPoint(firstVisiblePt.x, firstY)), wxSize(clientSize.x, lastY - firstY));
                 m_ctrl->RefreshRect(rect);
-
-                // TODO: we need to make sure that lines are only drawn if in the update region. The rect
-                // passed to Draw is currently used in different ways (to pass the position the content should
-                // be drawn at as well as the relevant region).
             }
             else
 #endif
                 m_ctrl->Refresh(false);
 
+#if wxRICHTEXT_USE_OWN_CARET
+            m_ctrl->PositionCaret();
+#endif
             if (sendUpdateEvent)
                 wxTextCtrl::SendTextUpdatedEvent(m_ctrl);
         }
@@ -6733,10 +7069,11 @@ bool wxRichTextImage::LoadFromBlock()
 /// Make block from the wxImage
 bool wxRichTextImage::MakeBlock()
 {
-    if (m_imageBlock.GetImageType() == wxBITMAP_TYPE_ANY || m_imageBlock.GetImageType() == -1)
-        m_imageBlock.SetImageType(wxBITMAP_TYPE_PNG);
+    wxBitmapType type = m_imageBlock.GetImageType();
+    if ( type == wxBITMAP_TYPE_ANY || type == wxBITMAP_TYPE_INVALID )
+        m_imageBlock.SetImageType(type = wxBITMAP_TYPE_PNG);
 
-    m_imageBlock.MakeImageBlock(m_image, m_imageBlock.GetImageType());
+    m_imageBlock.MakeImageBlock(m_image, type);
     return m_imageBlock.Ok();
 }
 
@@ -6792,6 +7129,9 @@ bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, i
     if (!range.IsWithin(GetRange()))
         return false;
 
+    if (!m_image.Ok())
+        ((wxRichTextImage*) this)->LoadFromBlock();
+
     if (partialExtents)
     {
         if (m_image.Ok())
@@ -7053,7 +7393,7 @@ void wxRichTextImageBlock::Init()
 {
     m_data = NULL;
     m_dataSize = 0;
-    m_imageType = -1;
+    m_imageType = wxBITMAP_TYPE_INVALID;
 }
 
 void wxRichTextImageBlock::Clear()
@@ -7061,7 +7401,7 @@ void wxRichTextImageBlock::Clear()
     delete[] m_data;
     m_data = NULL;
     m_dataSize = 0;
-    m_imageType = -1;
+    m_imageType = wxBITMAP_TYPE_INVALID;
 }
 
 
@@ -7071,14 +7411,15 @@ void wxRichTextImageBlock::Clear()
 // If it's not a JPEG we can make use of 'image', already scaled, so we don't have to
 // load the image a 2nd time.
 
-bool wxRichTextImageBlock::MakeImageBlock(const wxString& filename, int imageType, wxImage& image, bool convertToJPEG)
+bool wxRichTextImageBlock::MakeImageBlock(const wxString& filename, wxBitmapType imageType,
+                                          wxImage& image, bool convertToJPEG)
 {
     m_imageType = imageType;
 
     wxString filenameToRead(filename);
     bool removeFile = false;
 
-    if (imageType == -1)
+    if (imageType == wxBITMAP_TYPE_INVALID)
         return false; // Could not determine image type
 
     if ((imageType != wxBITMAP_TYPE_JPEG) && convertToJPEG)
@@ -7115,12 +7456,12 @@ bool wxRichTextImageBlock::MakeImageBlock(const wxString& filename, int imageTyp
 
 // Make an image block from the wxImage in the given
 // format.
-bool wxRichTextImageBlock::MakeImageBlock(wxImage& image, int imageType, int quality)
+bool wxRichTextImageBlock::MakeImageBlock(wxImage& image, wxBitmapType imageType, int quality)
 {
     m_imageType = imageType;
     image.SetOption(wxT("quality"), quality);
 
-    if (imageType == -1)
+    if (imageType == wxBITMAP_TYPE_INVALID)
         return false; // Could not determine image type
 
     wxString tempFile;
@@ -7243,14 +7584,17 @@ bool wxRichTextImageBlock::WriteHex(wxOutputStream& stream)
 }
 
 // Read data in hex from a stream
-bool wxRichTextImageBlock::ReadHex(wxInputStream& stream, int length, int imageType)
+bool wxRichTextImageBlock::ReadHex(wxInputStream& stream, int length, wxBitmapType imageType)
 {
     int dataSize = length/2;
 
     if (m_data)
         delete[] m_data;
 
-    wxChar str[2];
+    // create a null terminated temporary string:
+    char str[3];
+    str[2] = '\0';
+
     m_data = new unsigned char[dataSize];
     int i;
     for (i = 0; i < dataSize; i ++)
@@ -7478,6 +7822,7 @@ wxRichTextFontTable::wxRichTextFontTable()
 }
 
 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
+    : wxObject()
 {
     (*this) = table;
 }