]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
fixing compilo
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 176c09d8d6d744ecc3465a02a5413e0ebb6ce1a2..1362fab7092a822153d558ac57a8634288df701a 100644 (file)
@@ -48,6 +48,9 @@ WX_DEFINE_LIST(wxRichTextLineList)
 // Switch off if the platform doesn't like it for some reason
 #define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1
 
+// Use GetPartialTextExtents for platforms that support it natively
+#define wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 1
+
 const wxChar wxRichTextLineBreakChar = (wxChar) 29;
 
 // Helpers for efficiency
@@ -309,7 +312,8 @@ int wxRichTextCompositeObject::HitTest(wxDC& dc, const wxPoint& pt, long& textPo
         node = node->GetNext();
     }
 
-    return wxRICHTEXT_HITTEST_NONE;
+    textPosition = GetRange().GetEnd()-1;
+    return wxRICHTEXT_HITTEST_AFTER|wxRICHTEXT_HITTEST_OUTSIDE;
 }
 
 /// Finds the absolute position and row height for the given character position
@@ -421,26 +425,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 (!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();
@@ -509,13 +518,13 @@ bool wxRichTextBox::Layout(wxDC& dc, const wxRect& rect, int style)
 }
 
 /// Get/set the size for the given range. Assume only has one child.
-bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
+bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
 {
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     if (node)
     {
         wxRichTextObject* child = node->GetData();
-        return child->GetRangeSize(range, size, descent, dc, flags, position);
+        return child->GetRangeSize(range, size, descent, dc, flags, position, partialExtents);
     }
     else
         return false;
@@ -580,7 +589,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();
@@ -740,7 +749,7 @@ void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox& obj)
 }
 
 /// Get/set the size for the given range.
-bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
+bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* WXUNUSED(partialExtents)) const
 {
     wxSize sz;
 
@@ -848,25 +857,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();
@@ -1175,7 +1188,8 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextParag
             wxRichTextParagraph* firstPara = wxDynamicCast(firstParaNode->GetData(), wxRichTextParagraph);
             wxASSERT(firstPara != NULL);
 
-            para->SetAttributes(firstPara->GetAttributes());
+            if (!(fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE))
+                para->SetAttributes(firstPara->GetAttributes());
 
             // Save empty paragraph attributes for appending later
             // These are character attributes deliberately set for a new paragraph. Without this,
@@ -1252,7 +1266,9 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextParag
                 }
             }
 
-            if (finalPara && finalPara != para)
+            if ((fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE) && firstPara)
+                finalPara->SetAttributes(firstPara->GetAttributes());
+            else if (finalPara && finalPara != para)
                 finalPara->SetAttributes(originalAttr);
 
             return true;
@@ -1454,6 +1470,7 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
             obj->DeleteRange(range);
 
             wxRichTextRange thisRange = obj->GetRange();
+            wxTextAttrEx thisAttr = obj->GetAttributes();
 
             // If the whole paragraph is within the range to delete,
             // delete the whole thing.
@@ -1487,7 +1504,14 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
 
                 wxTextAttrEx nextParaAttr;
                 if (applyFinalParagraphStyle)
-                    nextParaAttr = nextParagraph->GetAttributes();
+                {
+                    // Special case when deleting the end of a paragraph - use _this_ paragraph's style,
+                    // not the next one.
+                    if (range.GetStart() == range.GetEnd() && range.GetStart() == thisRange.GetEnd())
+                        nextParaAttr = thisAttr;
+                    else
+                        nextParaAttr = nextParagraph->GetAttributes();
+                }
 
                 if (firstPara && nextParagraph && firstPara != nextParagraph)
                 {
@@ -1772,8 +1796,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());
@@ -1922,11 +1945,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())
             {
@@ -1943,7 +1969,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())
             {
@@ -1960,7 +1986,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())
             {
@@ -1977,7 +2003,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())
             {
@@ -1997,7 +2023,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())
             {
@@ -2015,7 +2041,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())
         {
@@ -2030,7 +2056,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())
         {
@@ -2045,7 +2071,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())
         {
@@ -2060,7 +2086,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())
         {
@@ -2075,7 +2101,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())
         {
@@ -2090,7 +2116,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())
         {
@@ -2105,7 +2131,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())
         {
@@ -2120,7 +2146,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())
         {
@@ -2135,7 +2161,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())
         {
@@ -2150,7 +2176,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())
         {
@@ -2165,7 +2191,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())
         {
@@ -2180,7 +2206,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())
         {
@@ -2195,7 +2221,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())
         {
@@ -2210,7 +2236,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())
         {
@@ -2225,7 +2251,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())
         {
@@ -2243,7 +2269,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())
         {
@@ -2260,7 +2286,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())
         {
@@ -2277,13 +2303,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();
 
@@ -2302,9 +2332,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())
         {
@@ -2334,6 +2372,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)
     {
@@ -2344,7 +2387,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
             {
                 wxTextAttr paraStyle = para->GetCombinedAttributes();
 
-                CollectStyle(style, paraStyle, multipleStyleAttributes, multipleTextEffectAttributes);
+                CollectStyle(style, paraStyle, multipleStyleAttributes, multipleTextEffectAttributes, absentStyleAttributesPara, absentTextEffectAttributesPara);
             }
             else
             {
@@ -2354,7 +2397,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();
 
@@ -2368,7 +2411,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();
@@ -3085,7 +3128,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();
 
@@ -3164,40 +3207,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);
 
-                // 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);
+                    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);
+                    }
 
-                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;
+                    // 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);
 
-            node2 = node2->GetNext();
+                    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();
+            }
         }
 
         node = node->GetNext();
@@ -3206,6 +3265,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)
 {
@@ -3261,7 +3339,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();
@@ -3272,6 +3362,8 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
         node = node->GetNext();
     }
 
+#endif
+
     // Split up lines
 
     // We may need to go back to a previous child, in which case create the new line,
@@ -3283,6 +3375,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?
@@ -3315,7 +3413,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
@@ -3329,7 +3435,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
 
             // Find a place to wrap. This may walk back to previous children,
             // for example if a word spans several objects.
-            if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos+1, child->GetRange().GetEnd()), dc, availableSpaceForText, wrapPosition))
+            if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos+1, child->GetRange().GetEnd()), dc, availableSpaceForText, wrapPosition, & partialExtents))
             {
                 // If the function failed, just cut it off at the end of this child.
                 wrapPosition = child->GetRange().GetEnd();
@@ -3344,7 +3450,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);
@@ -3440,6 +3554,48 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
 
     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;
 }
 
@@ -3556,7 +3712,7 @@ void wxRichTextParagraph::ClearLines()
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
+bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position, wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -3568,9 +3724,17 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
         wxSize sz;
 
+        wxArrayInt childExtents;
+        wxArrayInt* p;
+        if (partialExtents)
+            p = & childExtents;
+        else
+            p = NULL;
+
         wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
         while (node)
         {
+
             wxRichTextObject* child = node->GetData();
             if (!child->GetRange().IsOutside(range))
             {
@@ -3580,12 +3744,47 @@ 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)))
+                // 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)
+                    {
+                        int lastSize;
+                        if (partialExtents->GetCount() > 0)
+                            lastSize = (*partialExtents)[partialExtents->GetCount()-1];
+                        else
+                            lastSize = 0;
+
+                        size_t i;
+                        for (i = 0; i < childExtents.GetCount(); i++)
+                        {
+                            partialExtents->Add(childExtents[i] + lastSize);
+                        }
+                    }
                 }
+
+                if (p)
+                    p->Clear();
             }
 
             node = node->GetNext();
@@ -3754,7 +3953,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
         wxSize lineSize = line->GetSize();
         wxRichTextRange lineRange = line->GetAbsoluteRange();
 
-        if (pt.y >= linePos.y && pt.y <= linePos.y + lineSize.y)
+        if (pt.y <= linePos.y + lineSize.y)
         {
             if (pt.x < linePos.x)
             {
@@ -3768,6 +3967,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++)
@@ -3800,6 +4032,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
                         lastX = nextX;
                     }
                 }
+#endif
             }
         }
 
@@ -3938,7 +4171,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
                     text += textObj->GetTextForRange(range);
                 }
                 else
-                    return true;
+                {
+                    text += wxT(" ");
+                }
             }
 
             node = node->GetNext();
@@ -3958,7 +4193,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
                     text = textObj->GetTextForRange(range) + text;
                 }
                 else
-                    return true;
+                {
+                    text = wxT(" ") + text;
+                }
             }
 
             node = node->GetPrevious();
@@ -3969,55 +4206,84 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
 }
 
 /// Find a suitable wrap position.
-bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& dc, int availableSpace, long& wrapPosition)
+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();
 
-    // Binary chop for speed
-    long minPos = range.GetStart();
-    long maxPos = range.GetEnd();
-    while (true)
+#if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
+    if (partialExtents && partialExtents->GetCount() >= (size_t) (GetRange().GetLength()-1)) // the final position in a paragraph is the newline
     {
-        if (minPos == maxPos)
-        {
-            int descent = 0;
-            GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+        int widthBefore;
 
-            if (sz.x > availableSpace)
-                breakPosition = minPos - 1;
-            break;
-        }
-        else if ((maxPos - minPos) == 1)
+        if (range.GetStart() > GetRange().GetStart())
+            widthBefore = (*partialExtents)[range.GetStart() - GetRange().GetStart() - 1];
+        else
+            widthBefore = 0;
+
+        size_t i;
+        for (i = (size_t) range.GetStart(); i < (size_t) range.GetEnd(); i++)
         {
-            int descent = 0;
-            GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+            int widthFromStartOfThisRange = (*partialExtents)[i - GetRange().GetStart()] - widthBefore;
 
-            if (sz.x > availableSpace)
-                breakPosition = minPos - 1;
-            else
+            if (widthFromStartOfThisRange > availableSpace)
             {
-                GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
-                if (sz.x > availableSpace)
-                    breakPosition = maxPos-1;
+                breakPosition = i-1;
+                break;
             }
-            break;
         }
-        else
+    }
+    else
+#endif
+    {
+        // Binary chop for speed
+        long minPos = range.GetStart();
+        long maxPos = range.GetEnd();
+        while (true)
         {
-            long nextPos = minPos + ((maxPos - minPos) / 2);
-
-            int descent = 0;
-            GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+            if (minPos == maxPos)
+            {
+                int descent = 0;
+                GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
 
-            if (sz.x > availableSpace)
+                if (sz.x > availableSpace)
+                    breakPosition = minPos - 1;
+                break;
+            }
+            else if ((maxPos - minPos) == 1)
             {
-                maxPos = nextPos;
+                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
             {
-                minPos = nextPos;
+                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;
+                }
             }
         }
     }
@@ -4242,12 +4508,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
@@ -4305,16 +4577,44 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
     long len = range.GetLength();
     wxString stringChunk = str.Mid(range.GetStart() - offset, (size_t) len);
 
-    int charHeight = dc.GetCharHeight();
-
-    int x = rect.x;
-    int y = rect.y + (rect.height - charHeight - (descent - m_descent));
-
     // Test for the optimized situations where all is selected, or none
     // is selected.
 
-    wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
-    wxCheckSetFont(dc, font);
+    wxFont textFont(GetBuffer()->GetFontTable().FindFont(textAttr));
+    wxCheckSetFont(dc, textFont);
+    int charHeight = dc.GetCharHeight();
+
+    int x, y;
+    if ( textFont.Ok() )
+    {
+        if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT) )
+        {
+            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+            textFont.SetPointSize( static_cast<int>(size) );
+            x = rect.x;
+            y = rect.y;
+            wxCheckSetFont(dc, textFont);
+        }
+        else if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) )
+        {
+            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+            textFont.SetPointSize( static_cast<int>(size) );
+            x = rect.x;
+            int sub_height = static_cast<int>( static_cast<double>(charHeight) / wxSCRIPT_MUL_FACTOR);
+            y = rect.y + (rect.height - sub_height + (descent - m_descent));
+            wxCheckSetFont(dc, textFont);
+        }
+        else
+        {
+            x = rect.x;
+            y = rect.y + (rect.height - charHeight - (descent - m_descent));
+        }
+    }
+    else
+    {
+        x = rect.x;
+        y = rect.y + (rect.height - charHeight - (descent - m_descent));
+    }
 
     // (a) All selected.
     if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
@@ -4332,7 +4632,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
         // (c) Part selected, part not
         // Let's draw unselected chunk, selected chunk, then unselected chunk.
 
-        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
 
         // 1. Initial unselected chunk, if any, up until start of selection.
         if (selectionRange.GetStart() > range.GetStart() && selectionRange.GetStart() <= range.GetEnd())
@@ -4449,7 +4749,7 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttr& attr, con
         wxCheckSetBrush(dc, wxBrush(highlightColour));
         wxCheckSetPen(dc, wxPen(highlightColour));
         dc.SetTextForeground(highlightTextColour);
-        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
     }
     else
     {
@@ -4457,11 +4757,11 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttr& attr, con
 
         if (attr.HasFlag(wxTEXT_ATTR_BACKGROUND_COLOUR) && attr.GetBackgroundColour().IsOk())
         {
-            dc.SetBackgroundMode(wxSOLID);
+            dc.SetBackgroundMode(wxBRUSHSTYLE_SOLID);
             dc.SetTextBackground(attr.GetBackgroundColour());
         }
         else
-            dc.SetBackgroundMode(wxTRANSPARENT);
+            dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
     }
 
     while (hasTabs)
@@ -4555,7 +4855,7 @@ void wxRichTextPlainText::Copy(const wxRichTextPlainText& obj)
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags), wxPoint position) const
+bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags), wxPoint position, wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -4569,9 +4869,26 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
     // of line breaks - and we don't need it, since we'll calculate size within
     // formatted text by doing it in chunks according to the line ranges
 
+    bool bScript(false);
     wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
-    wxCheckSetFont(dc, font);
+    if (font.Ok())
+    {
+        if ( textAttr.HasTextEffects() && ( (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT)
+            || (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) ) )
+        {
+            wxFont textFont = font;
+            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+            textFont.SetPointSize( static_cast<int>(size) );
+            wxCheckSetFont(dc, textFont);
+            bScript = true;
+        }
+        else
+        {
+            wxCheckSetFont(dc, font);
+        }
+    }
 
+    bool haveDescent = false;
     int startPos = range.GetStart() - GetRange().GetStart();
     long len = range.GetLength();
 
@@ -4608,13 +4925,40 @@ 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'));
-            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;
             for (int i = 0; i < tabCount && notFound; ++i)
@@ -4634,13 +4978,58 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
                     notFound = false;
                     width = nextTabPos - position.x;
+
+                    if (partialExtents)
+                        partialExtents->Add(width);
                 }
             }
         }
     }
-    dc.GetTextExtent(stringChunk, & w, & h, & descent);
-    width += w;
-    size = wxSize(width, dc.GetCharHeight());
+
+    if (!stringChunk.IsEmpty())
+    {
+        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);
+            size_t j;
+            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);
 
     return true;
 }
@@ -4858,6 +5247,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);
@@ -4933,17 +5331,25 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl, int
     wxRichTextParagraph* para = GetParagraphAtPosition(pos, false);
     long pos1 = pos;
 
+    if (p)
+        newPara->SetAttributes(*p);
+
     if (flags & wxRICHTEXT_INSERT_INTERACTIVE)
     {
         if (para && para->GetRange().GetEnd() == pos)
             pos1 ++;
+
+        // Now see if we need to number the paragraph.
+        if (newPara->GetAttributes().HasBulletNumber())
+        {
+            wxRichTextAttr numberingAttr;
+            if (FindNextParagraphNumber(para, numberingAttr))
+                wxRichTextApplyStyle(newPara->GetAttributes(), (const wxRichTextAttr&) numberingAttr);
+        }
     }
 
     action->SetPosition(pos);
 
-    if (p)
-        newPara->SetAttributes(*p);
-
     // Use the default character style
     // Use the default character style
     if (!GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
@@ -5048,6 +5454,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();
@@ -5060,14 +5485,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
@@ -5087,22 +5504,18 @@ bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange& range, wxRichT
     // Copy the fragment that we'll need to restore in Undo
     CopyFragment(range, action->GetOldParagraphs());
 
-    // Special case: if there is only one (non-partial) paragraph,
-    // we must save the *next* paragraph's style, because that
-    // is the style we must apply when inserting the content back
-    // when undoing the delete. (This is because we're merging the
-    // paragraph with the previous paragraph and throwing away
-    // the style, and we need to restore it.)
-    if (!action->GetOldParagraphs().GetPartialParagraph() && action->GetOldParagraphs().GetChildCount() == 1)
+    // See if we're deleting a paragraph marker, in which case we need to
+    // make a note not to copy the attributes from the 2nd paragraph to the 1st.
+    if (range.GetStart() == range.GetEnd())
     {
-        wxRichTextParagraph* lastPara = GetParagraphAtPosition(range.GetStart());
-        if (lastPara)
+        wxRichTextParagraph* para = GetParagraphAtPosition(range.GetStart());
+        if (para && para->GetRange().GetEnd() == range.GetEnd())
         {
-            wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetEnd()+1);
-            if (nextPara)
+            wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetStart()+1);
+            if (nextPara && nextPara != para)
             {
-                wxRichTextParagraph* para = (wxRichTextParagraph*) action->GetOldParagraphs().GetChild(0);
-                para->SetAttributes(nextPara->GetAttributes());
+                action->GetOldParagraphs().GetChildren().GetFirst()->GetData()->SetAttributes(nextPara->GetAttributes());
+                action->GetOldParagraphs().GetAttributes().SetFlags(action->GetOldParagraphs().GetAttributes().GetFlags() | wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE);
             }
         }
     }
@@ -5201,8 +5614,6 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttr& style)
 
     SetDefaultStyle(newStyle);
 
-    // wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize());
-
     return true;
 }
 
@@ -5482,7 +5893,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);
@@ -5512,7 +5924,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)
@@ -5527,7 +5939,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)
@@ -5571,7 +5983,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)
             {
@@ -5605,7 +6017,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)
@@ -5621,7 +6033,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)
@@ -5634,7 +6046,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)
@@ -5650,7 +6062,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)
@@ -5724,7 +6136,9 @@ 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;
                 }
             }
@@ -5746,7 +6160,10 @@ 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());
 
                 success = true;
             }
@@ -5764,10 +6181,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);
 
@@ -6004,7 +6421,7 @@ bool wxRichTextStdRenderer::DrawTextBullet(wxRichTextParagraph* paragraph, wxDC&
         if (attr.GetTextColour().Ok())
             dc.SetTextForeground(attr.GetTextColour());
 
-        dc.SetBackgroundMode(wxTRANSPARENT);
+        dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
 
         int charHeight = dc.GetCharHeight();
         wxCoord tw, th;
@@ -6166,6 +6583,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);
@@ -6180,54 +6649,12 @@ 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);
             m_buffer->UpdateRanges();
-            m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart()-1, GetRange().GetEnd()));
+            m_buffer->Invalidate(wxRichTextRange(wxMax(0, GetRange().GetStart()-1), GetRange().GetEnd()));
 
             long newCaretPosition = GetPosition() + m_newParagraphs.GetRange().GetLength();
 
@@ -6247,10 +6674,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,
@@ -6265,6 +6689,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()));
@@ -6273,7 +6704,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,
@@ -6319,13 +6750,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,
@@ -6340,11 +6778,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,
@@ -6383,7 +6828,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)
     {
@@ -6391,11 +6836,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;
 
@@ -6406,17 +6850,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)
                 {
@@ -6436,14 +6920,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++)
                             {
@@ -6452,7 +6941,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();
@@ -6470,22 +6960,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);
         }
@@ -6630,11 +7119,22 @@ bool wxRichTextImage::Layout(wxDC& WXUNUSED(dc), const wxRect& rect, int WXUNUSE
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags), wxPoint WXUNUSED(position)) const
+bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags), wxPoint WXUNUSED(position), wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
 
+    if (!m_image.Ok())
+        ((wxRichTextImage*) this)->LoadFromBlock();
+
+    if (partialExtents)
+    {
+        if (m_image.Ok())
+            partialExtents->Add(m_image.GetWidth());
+        else
+            partialExtents->Add(0);
+    }
+
     if (!m_image.Ok())
         return false;
 
@@ -6888,7 +7388,7 @@ void wxRichTextImageBlock::Init()
 {
     m_data = NULL;
     m_dataSize = 0;
-    m_imageType = -1;
+    m_imageType = wxBITMAP_TYPE_INVALID;
 }
 
 void wxRichTextImageBlock::Clear()
@@ -6896,7 +7396,7 @@ void wxRichTextImageBlock::Clear()
     delete[] m_data;
     m_data = NULL;
     m_dataSize = 0;
-    m_imageType = -1;
+    m_imageType = wxBITMAP_TYPE_INVALID;
 }
 
 
@@ -6906,7 +7406,8 @@ 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;
 
@@ -6950,7 +7451,7 @@ 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);
@@ -7078,7 +7579,7 @@ 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;
 
@@ -7313,6 +7814,7 @@ wxRichTextFontTable::wxRichTextFontTable()
 }
 
 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
+    : wxObject()
 {
     (*this) = table;
 }