]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
fixing wrong constant
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 91aafbfd9eb8f70fec951de8f845ccde8fca0b23..0e7ea9831881cf18fd2ea05bd55b5e09126ffe00 100644 (file)
@@ -48,12 +48,16 @@ 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
 
 inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
 {
+#if 0
     const wxFont& font1 = dc.GetFont();
     if (font1.IsOk() && font.IsOk())
     {
@@ -65,6 +69,7 @@ inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
             font1.GetFaceName() == font.GetFaceName())
             return;
     }
+#endif
     dc.SetFont(font);
 }
 
@@ -422,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();
@@ -510,13 +520,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;
@@ -581,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();
@@ -741,7 +751,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;
 
@@ -849,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();
@@ -1784,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());
@@ -1934,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())
             {
@@ -1955,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())
             {
@@ -1972,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())
             {
@@ -1989,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())
             {
@@ -2009,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())
             {
@@ -2027,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())
         {
@@ -2042,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())
         {
@@ -2057,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())
         {
@@ -2072,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())
         {
@@ -2087,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())
         {
@@ -2102,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())
         {
@@ -2117,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())
         {
@@ -2132,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())
         {
@@ -2147,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())
         {
@@ -2162,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())
         {
@@ -2177,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())
         {
@@ -2192,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())
         {
@@ -2207,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())
         {
@@ -2222,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())
         {
@@ -2237,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())
         {
@@ -2255,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())
         {
@@ -2272,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())
         {
@@ -2289,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();
 
@@ -2314,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())
         {
@@ -2346,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)
     {
@@ -2356,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
             {
@@ -2366,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();
 
@@ -2380,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();
@@ -3097,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();
 
@@ -3176,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();
+
+            // Loop through objects until we get to the one within range
+            wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
 
-            if (!child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
+            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();
@@ -3218,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)
 {
@@ -3273,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();
@@ -3284,6 +3364,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,
@@ -3295,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?
@@ -3327,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
@@ -3341,7 +3437,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();
@@ -3356,7 +3452,19 @@ 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);
+
+            /// Use previous descent, not the wrapping descent we just found, since this may be too big
+            /// for the fragment we're about to add.
+            childDescent = maxDescent;
+
+#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);
@@ -3446,17 +3554,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;
@@ -3472,12 +3622,18 @@ 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;
+            // Lines are relative to the paragraph position
+            pos.x -= GetPosition().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;
+            // Lines are relative to the paragraph position
+            pos.x -= GetPosition().x;
             line->SetPosition(pos);
         }
 
@@ -3568,7 +3724,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;
@@ -3580,9 +3736,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))
             {
@@ -3592,12 +3756,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();
@@ -3780,6 +3979,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++)
@@ -3812,6 +4044,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
                         lastX = nextX;
                     }
                 }
+#endif
             }
         }
 
@@ -3950,7 +4183,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
                     text += textObj->GetTextForRange(range);
                 }
                 else
-                    return true;
+                {
+                    text += wxT(" ");
+                }
             }
 
             node = node->GetNext();
@@ -3970,7 +4205,9 @@ bool wxRichTextParagraph::GetContiguousPlainText(wxString& text, const wxRichTex
                     text = textObj->GetTextForRange(range) + text;
                 }
                 else
-                    return true;
+                {
+                    text = wxT(" ") + text;
+                }
             }
 
             node = node->GetPrevious();
@@ -3981,55 +4218,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;
+                }
             }
         }
     }
@@ -4254,12 +4520,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
@@ -4317,16 +4589,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())
@@ -4344,7 +4644,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())
@@ -4461,7 +4761,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
     {
@@ -4469,11 +4769,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)
@@ -4567,7 +4867,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;
@@ -4581,9 +4881,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();
 
@@ -4620,13 +4937,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)
@@ -4646,13 +4990,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;
 }
@@ -4870,6 +5259,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);
@@ -4952,8 +5350,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);
@@ -5062,6 +5466,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();
@@ -5074,14 +5497,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
@@ -5211,8 +5626,6 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttr& style)
 
     SetDefaultStyle(newStyle);
 
-    // wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize());
-
     return true;
 }
 
@@ -5492,14 +5905,15 @@ 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);
     else if (!filename.IsEmpty())
     {
         wxString path, file, ext;
-        wxSplitPath(filename, & path, & file, & ext);
+        wxFileName::SplitPath(filename, & path, & file, & ext);
         return FindHandler(ext, imageType);
     }
     else
@@ -5522,7 +5936,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)
@@ -5537,7 +5951,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)
@@ -5581,7 +5995,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)
             {
@@ -5615,7 +6029,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)
@@ -5631,7 +6045,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)
@@ -5644,7 +6058,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)
@@ -5660,7 +6074,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)
@@ -5734,7 +6148,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;
@@ -5758,7 +6172,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());
@@ -5779,10 +6193,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);
 
@@ -6019,7 +6433,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;
@@ -6181,6 +6595,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);
@@ -6195,54 +6661,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();
 
@@ -6262,10 +6686,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,
@@ -6280,6 +6701,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()));
@@ -6288,7 +6716,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,
@@ -6334,13 +6762,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,
@@ -6355,11 +6790,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,
@@ -6398,7 +6840,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)
     {
@@ -6406,11 +6848,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;
 
@@ -6421,17 +6862,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)
                 {
@@ -6451,14 +6932,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++)
                             {
@@ -6467,7 +6953,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();
@@ -6485,22 +6972,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);
         }
@@ -6591,10 +7077,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();
 }
 
@@ -6645,11 +7132,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;
 
@@ -6813,7 +7311,7 @@ bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& f
 bool wxRichTextFileHandler::CanHandle(const wxString& filename) const
 {
     wxString path, file, ext;
-    wxSplitPath(filename, & path, & file, & ext);
+    wxFileName::SplitPath(filename, & path, & file, & ext);
 
     return (ext.Lower() == GetExtension());
 }
@@ -6903,7 +7401,7 @@ void wxRichTextImageBlock::Init()
 {
     m_data = NULL;
     m_dataSize = 0;
-    m_imageType = -1;
+    m_imageType = wxBITMAP_TYPE_INVALID;
 }
 
 void wxRichTextImageBlock::Clear()
@@ -6911,7 +7409,7 @@ void wxRichTextImageBlock::Clear()
     delete[] m_data;
     m_data = NULL;
     m_dataSize = 0;
-    m_imageType = -1;
+    m_imageType = wxBITMAP_TYPE_INVALID;
 }
 
 
@@ -6921,24 +7419,23 @@ 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)
     {
-        wxString tempFile;
-        bool success = wxGetTempFileName(_("image"), tempFile) ;
+        wxString tempFile =
+            wxFileName::CreateTempFileName(_("image"));
 
-        wxASSERT(success);
-
-        wxUnusedVar(success);
+        wxASSERT(!tempFile.IsEmpty());
 
         image.SaveFile(tempFile, wxBITMAP_TYPE_JPEG);
         filenameToRead = tempFile;
@@ -6965,19 +7462,16 @@ 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;
-    bool success = wxGetTempFileName(_("image"), tempFile) ;
-
-    wxASSERT(success);
-    wxUnusedVar(success);
+    wxString tempFile = wxFileName::CreateTempFileName(_("image")) ;
+    wxASSERT(!tempFile.IsEmpty());
 
     if (!image.SaveFile(tempFile, m_imageType))
     {
@@ -7044,9 +7538,8 @@ bool wxRichTextImageBlock::Load(wxImage& image)
     wxMemoryInputStream mstream(m_data, m_dataSize);
     bool success = image.LoadFile(mstream, GetImageType());
 #else
-    wxString tempFile;
-    bool success = wxGetTempFileName(_("image"), tempFile) ;
-    wxASSERT(success);
+    wxString tempFile = wxFileName::CreateTempFileName(_("image"));
+    wxASSERT(!tempFile.IsEmpty());
 
     if (!WriteBlock(tempFile, m_data, m_dataSize))
     {
@@ -7093,14 +7586,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 ++)
@@ -7328,6 +7824,7 @@ wxRichTextFontTable::wxRichTextFontTable()
 }
 
 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
+    : wxObject()
 {
     (*this) = table;
 }