]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
The UIProgressView is somehow not doing layout :(.
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 82b67e7d684ecff3efde8152e5e75e267836f7a3..cc4f3de5bc6844e937ef721008fa61bedfdaeedd 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Julian Smart
 // Modified by:
 // Created:     2005-09-30
 // Author:      Julian Smart
 // Modified by:
 // Created:     2005-09-30
-// RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -42,6 +41,7 @@
 #include "wx/richtext/richtextstyles.h"
 #include "wx/richtext/richtextimagedlg.h"
 #include "wx/richtext/richtextsizepage.h"
 #include "wx/richtext/richtextstyles.h"
 #include "wx/richtext/richtextimagedlg.h"
 #include "wx/richtext/richtextsizepage.h"
+#include "wx/richtext/richtextxml.h"
 
 #include "wx/listimpl.cpp"
 #include "wx/arrimpl.cpp"
 
 #include "wx/listimpl.cpp"
 #include "wx/arrimpl.cpp"
@@ -464,21 +464,6 @@ int wxRichTextFloatCollector::HitTest(wxDC& dc, wxRichTextDrawingContext& contex
 // Helpers for efficiency
 inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
 {
 // Helpers for efficiency
 inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
 {
-    // JACS: did I do this some time ago when testing? Should we re-enable it?
-#if 0
-    const wxFont& font1 = dc.GetFont();
-    if (font1.IsOk() && font.IsOk())
-    {
-        if (font1.GetPointSize() == font.GetPointSize() &&
-            font1.GetFamily() == font.GetFamily() &&
-            font1.GetStyle() == font.GetStyle() &&
-            font1.GetWeight() == font.GetWeight() &&
-            font1.GetUnderlined() == font.GetUnderlined() &&
-            font1.GetFamily() == font.GetFamily() &&
-            font1.GetFaceName() == font.GetFaceName())
-            return;
-    }
-#endif
     dc.SetFont(font);
 }
 
     dc.SetFont(font);
 }
 
@@ -616,7 +601,7 @@ void wxRichTextObject::Invalidate(const wxRichTextRange& invalidRange)
         // If this is a floating object, size may not be recalculated
         // after floats have been collected in an early stage of Layout.
         // So avoid resetting the cache for floating objects during layout.
         // If this is a floating object, size may not be recalculated
         // after floats have been collected in an early stage of Layout.
         // So avoid resetting the cache for floating objects during layout.
-        if (!IsFloating())
+        if (!IsFloating() || !wxRichTextBuffer::GetFloatingLayoutMode())
             SetCachedSize(wxDefaultSize);
         SetMaxSize(wxDefaultSize);
         SetMinSize(wxDefaultSize);
             SetCachedSize(wxDefaultSize);
         SetMaxSize(wxDefaultSize);
         SetMinSize(wxDefaultSize);
@@ -629,7 +614,7 @@ int wxRichTextObject::ConvertTenthsMMToPixels(wxDC& dc, int units) const
     // Unscale
     double scale = 1.0;
     if (GetBuffer())
     // Unscale
     double scale = 1.0;
     if (GetBuffer())
-        scale = GetBuffer()->GetScale();
+        scale = GetBuffer()->GetScale() / GetBuffer()->GetDimensionScale();
     int p = ConvertTenthsMMToPixels(dc.GetPPI().x, units, scale);
 
     return p;
     int p = ConvertTenthsMMToPixels(dc.GetPPI().x, units, scale);
 
     return p;
@@ -677,7 +662,7 @@ int wxRichTextObject::ConvertPixelsToTenthsMM(int ppi, int pixels, double scale)
 
 // Draw the borders and background for the given rectangle and attributes.
 // Width and height are taken to be the outer margin size, not the content.
 
 // Draw the borders and background for the given rectangle and attributes.
 // Width and height are taken to be the outer margin size, not the content.
-bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, const wxRichTextAttr& attr, const wxRect& boxRect, int flags)
+bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, const wxRichTextAttr& attr, const wxRect& boxRect, int flags, wxRichTextObject* obj)
 {
     // Assume boxRect is the area around the content
     wxRect marginRect = boxRect;
 {
     // Assume boxRect is the area around the content
     wxRect marginRect = boxRect;
@@ -707,12 +692,24 @@ bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, con
 
     if (flags & wxRICHTEXT_DRAW_GUIDELINES)
     {
 
     if (flags & wxRICHTEXT_DRAW_GUIDELINES)
     {
-        wxRichTextAttr editBorderAttr = attr;
+        wxRichTextAttr editBorderAttr;
         // TODO: make guideline colour configurable
         editBorderAttr.GetTextBoxAttr().GetBorder().SetColour(*wxLIGHT_GREY);
         editBorderAttr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
         editBorderAttr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
 
         // TODO: make guideline colour configurable
         editBorderAttr.GetTextBoxAttr().GetBorder().SetColour(*wxLIGHT_GREY);
         editBorderAttr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
         editBorderAttr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
 
+        if (obj)
+        {
+            wxRichTextCell* cell = wxDynamicCast(obj, wxRichTextCell);
+            if (cell)
+            {
+                // This ensures that thin lines drawn by adjacent cells (left and above)
+                // don't get overwritten by the guidelines.
+                editBorderAttr.GetTextBoxAttr().GetBorder().GetLeft().Reset();
+                editBorderAttr.GetTextBoxAttr().GetBorder().GetTop().Reset();
+            }
+        }
+
         DrawBorder(dc, buffer, editBorderAttr.GetTextBoxAttr().GetBorder(), borderRect, flags);
     }
 
         DrawBorder(dc, buffer, editBorderAttr.GetTextBoxAttr().GetBorder(), borderRect, flags);
     }
 
@@ -746,8 +743,9 @@ bool wxRichTextObject::DrawBorder(wxDC& dc, wxRichTextBuffer* buffer, const wxTe
                 penStyle = wxLONG_DASH;
             wxPen pen(col, 1, penStyle);
             dc.SetPen(pen);
                 penStyle = wxLONG_DASH;
             wxPen pen(col, 1, penStyle);
             dc.SetPen(pen);
-            dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
 
 
+            // Note that the last point is not drawn.
+            dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
         }
         else if (borderLeft > 1)
         {
         }
         else if (borderLeft > 1)
         {
@@ -775,8 +773,8 @@ bool wxRichTextObject::DrawBorder(wxDC& dc, wxRichTextBuffer* buffer, const wxTe
                 penStyle = wxLONG_DASH;
             wxPen pen(col, 1, penStyle);
             dc.SetPen(pen);
                 penStyle = wxLONG_DASH;
             wxPen pen(col, 1, penStyle);
             dc.SetPen(pen);
-            dc.DrawLine(rect.x + rect.width, rect.y, rect.x + rect.width, rect.y + rect.height + 1);
-
+            // Note that the last point is not drawn.
+            dc.DrawLine(rect.x + rect.width - 1, rect.y, rect.x + rect.width - 1, rect.y + rect.height);
         }
         else if (borderRight > 1)
         {
         }
         else if (borderRight > 1)
         {
@@ -820,7 +818,7 @@ bool wxRichTextObject::DrawBorder(wxDC& dc, wxRichTextBuffer* buffer, const wxTe
     if (attr.GetBottom().IsValid() && attr.GetBottom().GetStyle() != wxTEXT_BOX_ATTR_BORDER_NONE)
     {
         borderBottom = converter.GetPixels(attr.GetBottom().GetWidth());
     if (attr.GetBottom().IsValid() && attr.GetBottom().GetStyle() != wxTEXT_BOX_ATTR_BORDER_NONE)
     {
         borderBottom = converter.GetPixels(attr.GetBottom().GetWidth());
-        wxColour col(attr.GetTop().GetColour());
+        wxColour col(attr.GetBottom().GetColour());
 
         // If pen width is > 1, resorts to a solid rectangle.
         if (borderBottom == 1)
 
         // If pen width is > 1, resorts to a solid rectangle.
         if (borderBottom == 1)
@@ -832,8 +830,7 @@ bool wxRichTextObject::DrawBorder(wxDC& dc, wxRichTextBuffer* buffer, const wxTe
                 penStyle = wxLONG_DASH;
             wxPen pen(col, 1, penStyle);
             dc.SetPen(pen);
                 penStyle = wxLONG_DASH;
             wxPen pen(col, 1, penStyle);
             dc.SetPen(pen);
-            dc.DrawLine(rect.x, rect.y + rect.height, rect.x + rect.width, rect.y + rect.height);
-
+            dc.DrawLine(rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height - 1);
         }
         else if (borderBottom > 1)
         {
         }
         else if (borderBottom > 1)
         {
@@ -1022,7 +1019,7 @@ void wxRichTextObject::Dump(wxTextOutputStream& stream)
 wxRichTextBuffer* wxRichTextObject::GetBuffer() const
 {
     const wxRichTextObject* obj = this;
 wxRichTextBuffer* wxRichTextObject::GetBuffer() const
 {
     const wxRichTextObject* obj = this;
-    while (obj && !obj->IsKindOf(CLASSINFO(wxRichTextBuffer)))
+    while (obj && !wxDynamicCast(obj, wxRichTextBuffer))
         obj = obj->GetParent();
     return wxDynamicCast(obj, wxRichTextBuffer);
 }
         obj = obj->GetParent();
     return wxDynamicCast(obj, wxRichTextBuffer);
 }
@@ -1090,7 +1087,8 @@ bool wxRichTextObject::LayoutToBestSize(wxDC& dc, wxRichTextDrawingContext& cont
         // If a paragraph, align the whole paragraph.
         // Problem with this: if we're limited by a floating object, a line may be centered
         // w.r.t. the smaller resulting box rather than the actual available width.
         // If a paragraph, align the whole paragraph.
         // Problem with this: if we're limited by a floating object, a line may be centered
         // w.r.t. the smaller resulting box rather than the actual available width.
-        if (attr.HasAlignment() && !GetContainer()->GetFloatCollector()->HasFloats()) // FIXME: aligning whole paragraph not compatible with floating objects
+        // FIXME: aligning whole paragraph not compatible with floating objects
+        if (attr.HasAlignment() && (!wxRichTextBuffer::GetFloatingLayoutMode() || (GetContainer()->GetFloatCollector() && !GetContainer()->GetFloatCollector()->HasFloats())))
         {
             // centering, right-justification
             if (attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
         {
             // centering, right-justification
             if (attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
@@ -1413,7 +1411,7 @@ wxRichTextObject* wxRichTextCompositeObject::GetChildAtPosition(long pos) const
 }
 
 /// Recursively merge all pieces that can be merged.
 }
 
 /// Recursively merge all pieces that can be merged.
-bool wxRichTextCompositeObject::Defragment(const wxRichTextRange& range)
+bool wxRichTextCompositeObject::Defragment(wxRichTextDrawingContext& context, const wxRichTextRange& range)
 {
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
 {
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
@@ -1423,24 +1421,84 @@ bool wxRichTextCompositeObject::Defragment(const wxRichTextRange& range)
         {
             wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
             if (composite)
         {
             wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
             if (composite)
-                composite->Defragment();
+                composite->Defragment(context);
 
 
-            if (node->GetNext())
+            // Optimization: if there are no virtual attributes, we won't need to
+            // to split objects in order to paint individually attributed chunks.
+            // So only merge in this case.
+            if (!context.GetVirtualAttributesEnabled())
             {
             {
-                wxRichTextObject* nextChild = node->GetNext()->GetData();
-                if (child->CanMerge(nextChild) && child->Merge(nextChild))
+                if (node->GetNext())
                 {
                 {
-                    nextChild->Dereference();
-                    m_children.Erase(node->GetNext());
-
-                    // Don't set node -- we'll see if we can merge again with the next
-                    // child.
+                    wxRichTextObject* nextChild = node->GetNext()->GetData();
+                    if (child->CanMerge(nextChild, context) && child->Merge(nextChild, context))
+                    {
+                        nextChild->Dereference();
+                        m_children.Erase(node->GetNext());
+                    }
+                    else
+                        node = node->GetNext();
                 }
                 else
                     node = node->GetNext();
             }
             else
                 }
                 else
                     node = node->GetNext();
             }
             else
-                node = node->GetNext();
+            {
+                // If we might have virtual attributes, we first see if we have to split
+                // objects so that they may be painted with potential virtual attributes,
+                // since text objects can only draw or measure with a single attributes object
+                // at a time.
+                wxRichTextObject* childAfterSplit = child;
+                if (child->CanSplit(context))
+                {
+                    childAfterSplit = child->Split(context);
+                    node = m_children.Find(childAfterSplit);                        
+                }
+
+                if (node->GetNext())
+                {
+                    wxRichTextObject* nextChild = node->GetNext()->GetData();
+                    
+                    // First split child and nextChild so we have smaller fragments to merge.
+                    // Then Merge only has to test per-object virtual attributes
+                    // because for an object with all the same sub-object attributes,
+                    // then any general virtual attributes should be merged with sub-objects by
+                    // the implementation.
+                    
+                    wxRichTextObject* nextChildAfterSplit = nextChild;
+
+                    if (nextChildAfterSplit->CanSplit(context))
+                        nextChildAfterSplit = nextChild->Split(context);
+
+                    bool splitNextChild = nextChild != nextChildAfterSplit;
+                        
+                    // See if we can merge this new fragment with (perhaps the first part of) the next object.
+                    // Note that we use nextChild because if we had split nextChild, the first object always
+                    // remains (and further parts are appended). However we must use childAfterSplit since
+                    // it's the last part of a possibly split child.
+                    
+                    if (childAfterSplit->CanMerge(nextChild, context) && childAfterSplit->Merge(nextChild, context))
+                    {
+                        nextChild->Dereference();
+                        m_children.Erase(node->GetNext());
+
+                        // Don't set node -- we'll see if we can merge again with the next
+                        // child. UNLESS we split this or the next child, in which case we know we have to
+                        // move on to the end of the next child.
+                        if (splitNextChild)
+                            node = m_children.Find(nextChildAfterSplit);
+                    }
+                    else
+                    {
+                        if (splitNextChild)
+                            node = m_children.Find(nextChildAfterSplit); // start from the last object in the split
+                        else
+                            node = node->GetNext();
+                    }
+                }
+                else
+                    node = node->GetNext();
+            }
         }
         else
             node = node->GetNext();
         }
         else
             node = node->GetNext();
@@ -1485,7 +1543,7 @@ void wxRichTextCompositeObject::Dump(wxTextOutputStream& stream)
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, const wxPoint& position, const wxSize& parentSize, wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -1506,7 +1564,7 @@ bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSiz
         if (!child->GetRange().IsOutside(range))
         {
             // Floating objects have a zero size within the paragraph.
         if (!child->GetRange().IsOutside(range))
         {
             // Floating objects have a zero size within the paragraph.
-            if (child->IsFloating())
+            if (child->IsFloating() && wxRichTextBuffer::GetFloatingLayoutMode())
             {
                 if (partialExtents)
                 {
             {
                 if (partialExtents)
                 {
@@ -1541,7 +1599,7 @@ bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSiz
                     sz.x += childSize.x;
                     descent = wxMax(descent, childDescent);
                 }
                     sz.x += childSize.x;
                     descent = wxMax(descent, childDescent);
                 }
-                else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), p))
+                else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), parentSize, p))
                 {
                     sz.y = wxMax(sz.y, childSize.y);
                     sz.x += childSize.x;
                 {
                     sz.y = wxMax(sz.y, childSize.y);
                     sz.x += childSize.x;
@@ -1595,10 +1653,17 @@ void wxRichTextCompositeObject::Invalidate(const wxRichTextRange& invalidRange)
         }
         else if (child->IsTopLevel())
         {
         }
         else if (child->IsTopLevel())
         {
-            if (invalidRange == wxRICHTEXT_NONE)
-                child->Invalidate(wxRICHTEXT_NONE);
+            if (wxRichTextBuffer::GetFloatingLayoutMode() && child->IsFloating() && GetBuffer()->GetFloatCollector() && GetBuffer()->GetFloatCollector()->HasFloat(child))
+            {
+                // Don't invalidate subhierarchy if we've already been laid out
+            }
             else
             else
-                child->Invalidate(wxRICHTEXT_ALL); // All children must be invalidated if within parent range
+            {
+                if (invalidRange == wxRICHTEXT_NONE)
+                    child->Invalidate(wxRICHTEXT_NONE);
+                else
+                    child->Invalidate(wxRICHTEXT_ALL); // All children must be invalidated if within parent range
+            }
         }
         else
             child->Invalidate(invalidRange);
         }
         else
             child->Invalidate(invalidRange);
@@ -1657,7 +1722,6 @@ void wxRichTextParagraphLayoutBox::Init()
 
     m_invalidRange = wxRICHTEXT_ALL;
 
 
     m_invalidRange = wxRICHTEXT_ALL;
 
-    SetMargins(4);
     m_partialParagraph = false;
     m_floatCollector = NULL;
 }
     m_partialParagraph = false;
     m_floatCollector = NULL;
 }
@@ -1748,7 +1812,7 @@ int wxRichTextParagraphLayoutBox::HitTest(wxDC& dc, wxRichTextDrawingContext& co
         return wxRICHTEXT_HITTEST_NONE;
 
     int ret = wxRICHTEXT_HITTEST_NONE;
         return wxRICHTEXT_HITTEST_NONE;
 
     int ret = wxRICHTEXT_HITTEST_NONE;
-    if (m_floatCollector && (flags & wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS) == 0)
+    if (wxRichTextBuffer::GetFloatingLayoutMode() && m_floatCollector && (flags & wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS) == 0)
         ret = m_floatCollector->HitTest(dc, context, pt, textPosition, obj, flags);
 
     if (ret == wxRICHTEXT_HITTEST_NONE)
         ret = m_floatCollector->HitTest(dc, context, pt, textPosition, obj, flags);
 
     if (ret == wxRICHTEXT_HITTEST_NONE)
@@ -1763,7 +1827,7 @@ int wxRichTextParagraphLayoutBox::HitTest(wxDC& dc, wxRichTextDrawingContext& co
 /// Draw the floating objects
 void wxRichTextParagraphLayoutBox::DrawFloats(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
 {
 /// Draw the floating objects
 void wxRichTextParagraphLayoutBox::DrawFloats(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
 {
-    if (m_floatCollector)
+    if (wxRichTextBuffer::GetFloatingLayoutMode() && m_floatCollector)
         m_floatCollector->Draw(dc, context, range, selection, rect, descent, style);
 }
 
         m_floatCollector->Draw(dc, context, range, selection, rect, descent, style);
 }
 
@@ -1788,16 +1852,18 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, wxRichTextDrawingContext& cont
     context.ApplyVirtualAttributes(attr, this);
 
     int flags = style;
     context.ApplyVirtualAttributes(attr, this);
 
     int flags = style;
-    if (selection.IsValid() && GetParentContainer() != this && selection.WithinSelection(GetRange().GetStart(), GetParentContainer()))
+    if (selection.IsValid() && GetParentContainer() != this && selection.GetContainer() == this && selection.WithinSelection(GetRange().GetStart(), GetParentContainer()))
         flags |= wxRICHTEXT_DRAW_SELECTED;
 
     // Don't draw guidelines if at top level
     int theseFlags = flags;
     if (!GetParent())
         theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
         flags |= wxRICHTEXT_DRAW_SELECTED;
 
     // Don't draw guidelines if at top level
     int theseFlags = flags;
     if (!GetParent())
         theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
-    DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags);
+    DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags, this);
 
 
-    DrawFloats(dc, context, range, selection, rect, descent, style);
+    if (wxRichTextBuffer::GetFloatingLayoutMode())
+        DrawFloats(dc, context, range, selection, rect, descent, style);
+    
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
     {
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
     {
@@ -1870,6 +1936,10 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
         availableSpace = GetAvailableContentArea(dc, context, rect);
     }
 
         availableSpace = GetAvailableContentArea(dc, context, rect);
     }
 
+    // Fix the width if we're at the top level
+    if (!GetParent())
+        attr.GetTextBoxAttr().GetWidth().SetValue(rect.GetWidth(), wxTEXT_ATTR_UNITS_PIXELS);
+
     int leftMargin, rightMargin, topMargin, bottomMargin;
     wxRichTextObject::GetTotalMargin(dc, GetBuffer(), attr, leftMargin, rightMargin,
             topMargin, bottomMargin);
     int leftMargin, rightMargin, topMargin, bottomMargin;
     wxRichTextObject::GetTotalMargin(dc, GetBuffer(), attr, leftMargin, rightMargin,
             topMargin, bottomMargin);
@@ -1927,7 +1997,8 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
 
     // Gather information about only those floating objects that will not be formatted,
     // after which floats will be gathered per-paragraph during layout.
 
     // Gather information about only those floating objects that will not be formatted,
     // after which floats will be gathered per-paragraph during layout.
-    UpdateFloatingObjects(availableSpace, node ? node->GetData() : (wxRichTextObject*) NULL);
+    if (wxRichTextBuffer::GetFloatingLayoutMode())
+        UpdateFloatingObjects(availableSpace, node ? node->GetData() : (wxRichTextObject*) NULL);
 
     // A way to force speedy rest-of-buffer layout (the 'else' below)
     bool forceQuickLayout = false;
 
     // A way to force speedy rest-of-buffer layout (the 'else' below)
     bool forceQuickLayout = false;
@@ -2031,7 +2102,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
         maxHeight = 0; // topMargin + bottomMargin;
 
     // Check the bottom edge of any floating object
         maxHeight = 0; // topMargin + bottomMargin;
 
     // Check the bottom edge of any floating object
-    if (GetFloatCollector() && GetFloatCollector()->HasFloats())
+    if (wxRichTextBuffer::GetFloatingLayoutMode() && GetFloatCollector() && GetFloatCollector()->HasFloats())
     {
         int bottom = GetFloatCollector()->GetLastRectBottom();
         if (bottom > maxHeight)
     {
         int bottom = GetFloatCollector()->GetLastRectBottom();
         if (bottom > maxHeight)
@@ -2048,6 +2119,12 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
         maxWidth = wxMax(maxWidth, w);
         maxMaxWidth = wxMax(maxMaxWidth, w);
     }
         maxWidth = wxMax(maxWidth, w);
         maxMaxWidth = wxMax(maxMaxWidth, w);
     }
+    else
+    {
+        // TODO: Make sure the layout box's position reflects
+        // the position of the children, but without
+        // breaking layout of a box within a paragraph.
+    }
 
     // TODO: (also in para layout) should set the
     // object's size to an absolute one if specified,
 
     // TODO: (also in para layout) should set the
     // object's size to an absolute one if specified,
@@ -2116,7 +2193,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
 }
 
 /// Get/set the size for the given range.
 }
 
 /// Get/set the size for the given range.
-bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* WXUNUSED(partialExtents)) const
+bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, const wxPoint& position, const wxSize& parentSize, wxArrayInt* WXUNUSED(partialExtents)) const
 {
     wxSize sz;
 
 {
     wxSize sz;
 
@@ -2175,7 +2252,7 @@ bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wx
         wxSize childSize;
 
         int childDescent = 0;
         wxSize childSize;
 
         int childDescent = 0;
-        child->GetRangeSize(rangeToFind, childSize, childDescent, dc, context, flags, position);
+        child->GetRangeSize(rangeToFind, childSize, childDescent, dc, context, flags, position, parentSize);
 
         descent = wxMax(childDescent, descent);
 
 
         descent = wxMax(childDescent, descent);
 
@@ -2368,6 +2445,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraph(const wxString& text,
     wxRichTextAttr* cStyle = & defaultCharStyle;
 
     wxRichTextParagraph* para = new wxRichTextParagraph(text, this, pStyle, cStyle);
     wxRichTextAttr* cStyle = & defaultCharStyle;
 
     wxRichTextParagraph* para = new wxRichTextParagraph(text, this, pStyle, cStyle);
+    para->GetAttributes().GetTextBoxAttr().Reset();
 
     AppendChild(para);
 
 
     AppendChild(para);
 
@@ -2409,6 +2487,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
     size_t len = text.length();
     wxString line;
     wxRichTextParagraph* para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
     size_t len = text.length();
     wxString line;
     wxRichTextParagraph* para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+    para->GetAttributes().GetTextBoxAttr().Reset();
 
     AppendChild(para);
 
 
     AppendChild(para);
 
@@ -2426,6 +2505,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
                 plainText->SetText(line);
 
                 para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
                 plainText->SetText(line);
 
                 para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+                para->GetAttributes().GetTextBoxAttr().Reset();
 
                 AppendChild(para);
 
 
                 AppendChild(para);
 
@@ -2475,6 +2555,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddImage(const wxImage& image, wxR
     wxRichTextAttr* cStyle = & defaultCharStyle;
 
     wxRichTextParagraph* para = new wxRichTextParagraph(this, pStyle);
     wxRichTextAttr* cStyle = & defaultCharStyle;
 
     wxRichTextParagraph* para = new wxRichTextParagraph(this, pStyle);
+    para->GetAttributes().GetTextBoxAttr().Reset();
     AppendChild(para);
     para->AppendChild(new wxRichTextImage(image, this, cStyle));
 
     AppendChild(para);
     para->AppendChild(new wxRichTextImage(image, this, cStyle));
 
@@ -3248,7 +3329,17 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
                             wxRichTextRemoveStyle(child->GetAttributes(), style);
                         }
                         else if (resetExistingStyle)
                             wxRichTextRemoveStyle(child->GetAttributes(), style);
                         }
                         else if (resetExistingStyle)
+                        {
+                            // Preserve the URL as it's not really a formatting style but a property of the object
+                            wxString url;
+                            if (child->GetAttributes().HasURL() && !characterAttributes.HasURL())
+                                url = child->GetAttributes().GetURL();
+
                             child->GetAttributes() = characterAttributes;
                             child->GetAttributes() = characterAttributes;
+
+                            if (!url.IsEmpty())
+                                child->GetAttributes().SetURL(url);
+                        }
                         else
                         {
                             if (applyMinimal)
                         else
                         {
                             if (applyMinimal)
@@ -3338,6 +3429,7 @@ bool wxRichTextParagraphLayoutBox::DoGetStyle(long position, wxRichTextAttr& sty
             {
                 // Start with the base style
                 style = GetAttributes();
             {
                 // Start with the base style
                 style = GetAttributes();
+                style.GetTextBoxAttr().Reset();
 
                 // Apply the paragraph style
                 wxRichTextApplyStyle(style, obj->GetAttributes());
 
                 // Apply the paragraph style
                 wxRichTextApplyStyle(style, obj->GetAttributes());
@@ -3389,7 +3481,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
 {
     style = wxRichTextAttr();
 
 {
     style = wxRichTextAttr();
 
-    wxRichTextAttr clashingAttr;
+    wxRichTextAttr clashingAttrPara, clashingAttrChar;
     wxRichTextAttr absentAttrPara, absentAttrChar;
 
     wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
     wxRichTextAttr absentAttrPara, absentAttrChar;
 
     wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
@@ -3402,7 +3494,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
             {
                 wxRichTextAttr paraStyle = para->GetCombinedAttributes(true /* use box attributes */);
 
             {
                 wxRichTextAttr paraStyle = para->GetCombinedAttributes(true /* use box attributes */);
 
-                CollectStyle(style, paraStyle, clashingAttr, absentAttrPara);
+                CollectStyle(style, paraStyle, clashingAttrPara, absentAttrPara);
             }
             else
             {
             }
             else
             {
@@ -3412,7 +3504,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
                 // First collect paragraph attributes only
                 wxRichTextAttr paraStyle = para->GetCombinedAttributes();
                 paraStyle.SetFlags(paraStyle.GetFlags() & wxTEXT_ATTR_PARAGRAPH);
                 // First collect paragraph attributes only
                 wxRichTextAttr paraStyle = para->GetCombinedAttributes();
                 paraStyle.SetFlags(paraStyle.GetFlags() & wxTEXT_ATTR_PARAGRAPH);
-                CollectStyle(style, paraStyle, clashingAttr, absentAttrPara);
+                CollectStyle(style, paraStyle, clashingAttrPara, absentAttrPara);
 
                 wxRichTextObjectList::compatibility_iterator childNode = para->GetChildren().GetFirst();
 
 
                 wxRichTextObjectList::compatibility_iterator childNode = para->GetChildren().GetFirst();
 
@@ -3426,7 +3518,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
                         // Now collect character attributes only
                         childStyle.SetFlags(childStyle.GetFlags() & wxTEXT_ATTR_CHARACTER);
 
                         // Now collect character attributes only
                         childStyle.SetFlags(childStyle.GetFlags() & wxTEXT_ATTR_CHARACTER);
 
-                        CollectStyle(style, childStyle, clashingAttr, absentAttrChar);
+                        CollectStyle(style, childStyle, clashingAttrChar, absentAttrChar);
                     }
 
                     childNode = childNode->GetNext();
                     }
 
                     childNode = childNode->GetNext();
@@ -3478,12 +3570,12 @@ bool wxRichTextParagraphLayoutBox::HasCharacterAttributes(const wxRichTextRange&
                     if (childRange.GetLength() == 0 && GetRange().GetLength() == 1)
                         childRange.SetEnd(childRange.GetEnd()+1);
 
                     if (childRange.GetLength() == 0 && GetRange().GetLength() == 1)
                         childRange.SetEnd(childRange.GetEnd()+1);
 
-                    if (!childRange.IsOutside(range) && child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
+                    if (!childRange.IsOutside(range) && wxDynamicCast(child, wxRichTextPlainText))
                     {
                         foundCount ++;
                         wxRichTextAttr textAttr = para->GetCombinedAttributes(child->GetAttributes());
 
                     {
                         foundCount ++;
                         wxRichTextAttr textAttr = para->GetCombinedAttributes(child->GetAttributes());
 
-                        if (wxTextAttrEqPartial(textAttr, style))
+                        if (textAttr.EqPartial(style, false /* strong test - attributes must be valid in both objects */))
                             matchingCount ++;
                     }
 
                             matchingCount ++;
                     }
 
@@ -3526,7 +3618,7 @@ bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange&
                 wxRichTextApplyStyle(textAttr, para->GetAttributes());
 
                 foundCount ++;
                 wxRichTextApplyStyle(textAttr, para->GetAttributes());
 
                 foundCount ++;
-                if (wxTextAttrEqPartial(textAttr, style))
+                if (textAttr.EqPartial(style, false /* strong test */))
                     matchingCount ++;
             }
         }
                     matchingCount ++;
             }
         }
@@ -3543,7 +3635,6 @@ void wxRichTextParagraphLayoutBox::PrepareContent(wxRichTextParagraphLayoutBox&
         buffer->GetRichTextCtrl()->PrepareContent(container);
 }
 
         buffer->GetRichTextCtrl()->PrepareContent(container);
 }
 
-
 /// Set character or paragraph properties
 bool wxRichTextParagraphLayoutBox::SetProperties(const wxRichTextRange& range, const wxRichTextProperties& properties, int flags)
 {
 /// Set character or paragraph properties
 bool wxRichTextParagraphLayoutBox::SetProperties(const wxRichTextRange& range, const wxRichTextProperties& properties, int flags)
 {
@@ -3708,7 +3799,7 @@ void wxRichTextParagraphLayoutBox::Reset()
     wxRichTextBuffer* buffer = GetBuffer();
     if (buffer && buffer->GetRichTextCtrl())
     {
     wxRichTextBuffer* buffer = GetBuffer();
     if (buffer && buffer->GetRichTextCtrl())
     {
-        wxRichTextEvent event(wxEVT_COMMAND_RICHTEXT_BUFFER_RESET, buffer->GetRichTextCtrl()->GetId());
+        wxRichTextEvent event(wxEVT_RICHTEXT_BUFFER_RESET, buffer->GetRichTextCtrl()->GetId());
         event.SetEventObject(buffer->GetRichTextCtrl());
         event.SetContainer(this);
 
         event.SetEventObject(buffer->GetRichTextCtrl());
         event.SetContainer(this);
 
@@ -3785,8 +3876,21 @@ wxRichTextRange wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagrap
         wxRichTextParagraph* para1 = GetParagraphAtPosition(range.GetStart());
         if (para1)
             range.SetStart(para1->GetRange().GetStart());
         wxRichTextParagraph* para1 = GetParagraphAtPosition(range.GetStart());
         if (para1)
             range.SetStart(para1->GetRange().GetStart());
-        // floating layout make all child should be relayout
-        range.SetEnd(GetOwnRange().GetEnd());
+
+        // FIXME: be more intelligent about this. Check if we have floating objects
+        // before the end of the range. But it's not clear how we can in general
+        // tell where it's safe to stop laying out.
+        // Anyway, this code is central to efficiency when laying in floating mode.
+        if (!wxRichTextBuffer::GetFloatingLayoutMode())
+        {
+            wxRichTextParagraph* para2 = GetParagraphAtPosition(range.GetEnd());
+            if (para2)
+                range.SetEnd(para2->GetRange().GetEnd());
+        }
+        else
+            // Floating layout means that all children should be laid out,
+            // because we can't tell how the whole buffer will be affected.
+            range.SetEnd(GetOwnRange().GetEnd());
     }
     return range;
 }
     }
     return range;
 }
@@ -3986,12 +4090,18 @@ bool wxRichTextParagraphLayoutBox::SetListStyle(const wxRichTextRange& range, wx
                     wxRichTextApplyStyle(newPara->GetAttributes(), listStyle);
 
                     // Now we need to do numbering
                     wxRichTextApplyStyle(newPara->GetAttributes(), listStyle);
 
                     // Now we need to do numbering
-                    if (renumber)
+                    // Preserve the existing list item continuation bullet style, if any
+                    if (para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION))
+                        newPara->GetAttributes().SetBulletStyle(newPara->GetAttributes().GetBulletStyle()|wxTEXT_ATTR_BULLET_STYLE_CONTINUATION);
+                    else
                     {
                     {
-                        newPara->GetAttributes().SetBulletNumber(n);
-                    }
+                        if (renumber)
+                        {
+                            newPara->GetAttributes().SetBulletNumber(n);
+                        }
 
 
-                    n ++;
+                        n ++;
+                    }
                 }
                 else if (!newPara->GetAttributes().GetListStyleName().IsEmpty())
                 {
                 }
                 else if (!newPara->GetAttributes().GetListStyleName().IsEmpty())
                 {
@@ -4001,6 +4111,7 @@ bool wxRichTextParagraphLayoutBox::SetListStyle(const wxRichTextRange& range, wx
                     newPara->GetAttributes().SetListStyleName(wxEmptyString);
                     newPara->GetAttributes().SetLeftIndent(0, 0);
                     newPara->GetAttributes().SetBulletText(wxEmptyString);
                     newPara->GetAttributes().SetListStyleName(wxEmptyString);
                     newPara->GetAttributes().SetLeftIndent(0, 0);
                     newPara->GetAttributes().SetBulletText(wxEmptyString);
+                    newPara->GetAttributes().SetBulletStyle(0);
 
                     // Eliminate the main list-related attributes
                     newPara->GetAttributes().SetFlags(newPara->GetAttributes().GetFlags() & ~wxTEXT_ATTR_LEFT_INDENT & ~wxTEXT_ATTR_BULLET_STYLE & ~wxTEXT_ATTR_BULLET_NUMBER & ~wxTEXT_ATTR_BULLET_TEXT & wxTEXT_ATTR_LIST_STYLE_NAME);
 
                     // Eliminate the main list-related attributes
                     newPara->GetAttributes().SetFlags(newPara->GetAttributes().GetFlags() & ~wxTEXT_ATTR_LEFT_INDENT & ~wxTEXT_ATTR_BULLET_STYLE & ~wxTEXT_ATTR_BULLET_NUMBER & ~wxTEXT_ATTR_BULLET_TEXT & wxTEXT_ATTR_LIST_STYLE_NAME);
@@ -4164,6 +4275,10 @@ bool wxRichTextParagraphLayoutBox::DoNumberList(const wxRichTextRange& range, co
                     wxRichTextAttr listStyle(defToUse->GetCombinedStyleForLevel(thisLevel, styleSheet));
                     wxRichTextApplyStyle(newPara->GetAttributes(), listStyle);
 
                     wxRichTextAttr listStyle(defToUse->GetCombinedStyleForLevel(thisLevel, styleSheet));
                     wxRichTextApplyStyle(newPara->GetAttributes(), listStyle);
 
+                    // Preserve the existing list item continuation bullet style, if any
+                    if (para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION))
+                        newPara->GetAttributes().SetBulletStyle(newPara->GetAttributes().GetBulletStyle()|wxTEXT_ATTR_BULLET_STYLE_CONTINUATION);
+
                     // OK, we've (re)applied the style, now let's get the numbering right.
 
                     if (currentLevel == -1)
                     // OK, we've (re)applied the style, now let's get the numbering right.
 
                     if (currentLevel == -1)
@@ -4197,7 +4312,8 @@ bool wxRichTextParagraphLayoutBox::DoNumberList(const wxRichTextRange& range, co
                     }
                     else
                     {
                     }
                     else
                     {
-                        levels[currentLevel] ++;
+                        if (!(para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION)))
+                            levels[currentLevel] ++;
                     }
 
                     newPara->GetAttributes().SetBulletNumber(levels[currentLevel]);
                     }
 
                     newPara->GetAttributes().SetBulletNumber(levels[currentLevel]);
@@ -4276,7 +4392,24 @@ bool wxRichTextParagraphLayoutBox::PromoteList(int promoteBy, const wxRichTextRa
 /// position of the paragraph that it had to start looking from.
 bool wxRichTextParagraphLayoutBox::FindNextParagraphNumber(wxRichTextParagraph* previousParagraph, wxRichTextAttr& attr) const
 {
 /// position of the paragraph that it had to start looking from.
 bool wxRichTextParagraphLayoutBox::FindNextParagraphNumber(wxRichTextParagraph* previousParagraph, wxRichTextAttr& attr) const
 {
-    if (!previousParagraph->GetAttributes().HasFlag(wxTEXT_ATTR_BULLET_STYLE) || previousParagraph->GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
+    // TODO: add GetNextChild/GetPreviousChild to composite
+    // Search for a paragraph that isn't a continuation paragraph (no bullet)
+    while (previousParagraph && previousParagraph->GetAttributes().HasBulletStyle() && previousParagraph->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION)
+    {
+        wxRichTextObjectList::compatibility_iterator node = ((wxRichTextCompositeObject*) previousParagraph->GetParent())->GetChildren().Find(previousParagraph);
+        if (node)
+        {
+            node = node->GetPrevious();
+            if (node)
+                previousParagraph = wxDynamicCast(node->GetData(), wxRichTextParagraph);
+            else
+                previousParagraph = NULL;
+        }
+        else
+            previousParagraph = NULL;
+    }
+
+    if (!previousParagraph || !previousParagraph->GetAttributes().HasFlag(wxTEXT_ATTR_BULLET_STYLE) || previousParagraph->GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
         return false;
 
     wxRichTextBuffer* buffer = GetBuffer();
         return false;
 
     wxRichTextBuffer* buffer = GetBuffer();
@@ -4375,7 +4508,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
     DrawBoxAttributes(dc, GetBuffer(), attr, paraRect);
 
     // Draw the bullet, if any
     DrawBoxAttributes(dc, GetBuffer(), attr, paraRect);
 
     // Draw the bullet, if any
-    if (attr.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
+    if ((attr.GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE) == 0 && (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION) == 0)
     {
         if (attr.GetLeftSubIndent() != 0)
         {
     {
         if (attr.GetLeftSubIndent() != 0)
         {
@@ -4467,7 +4600,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
             {
                 wxRichTextObject* child = node2->GetData();
 
             {
                 wxRichTextObject* child = node2->GetData();
 
-                if (!child->IsFloating() && child->GetRange().GetLength() > 0 && !child->GetRange().IsOutside(lineRange) && !lineRange.IsOutside(range))
+                if ((!child->IsFloating() || !wxRichTextBuffer::GetFloatingLayoutMode()) && 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());
                 {
                     // Draw this part of the line at the correct position
                     wxRichTextRange objectRange(child->GetRange());
@@ -4540,9 +4673,15 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
     // Deal with floating objects firstly before the normal layout
     wxRichTextBuffer* buffer = GetBuffer();
     wxASSERT(buffer);
     // Deal with floating objects firstly before the normal layout
     wxRichTextBuffer* buffer = GetBuffer();
     wxASSERT(buffer);
+
     wxRichTextFloatCollector* collector = GetContainer()->GetFloatCollector();
     wxRichTextFloatCollector* collector = GetContainer()->GetFloatCollector();
-    wxASSERT(collector);
-    LayoutFloat(dc, context, rect, style, collector);
+
+    if (wxRichTextBuffer::GetFloatingLayoutMode())
+    {
+        wxASSERT(collector != NULL);
+        if (collector)
+            LayoutFloat(dc, context, rect, parentRect, style, collector);
+    }
 
     wxRichTextAttr attr = GetCombinedAttributes();
     context.ApplyVirtualAttributes(attr, this);
 
     wxRichTextAttr attr = GetCombinedAttributes();
     context.ApplyVirtualAttributes(attr, this);
@@ -4559,10 +4698,14 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
     int lineSpacing = 0;
 
     // Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc.
     int lineSpacing = 0;
 
     // Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc.
-    if (attr.HasLineSpacing() && attr.GetLineSpacing() > 0 && attr.GetFont().IsOk())
+    if (attr.HasLineSpacing() && attr.GetLineSpacing() > 0 && attr.HasFont())
     {
     {
-        wxCheckSetFont(dc, attr.GetFont());
-        lineSpacing = (int) (double(dc.GetCharHeight()) * (double(attr.GetLineSpacing())/10.0 - 1.0));
+        wxFont font(buffer->GetFontTable().FindFont(attr));
+        if (font.IsOk())
+        {
+            wxCheckSetFont(dc, font);
+            lineSpacing = (int) (double(dc.GetCharHeight()) * (double(attr.GetLineSpacing())/10.0 - 1.0));
+        }
     }
 
     // Start position for each line relative to the paragraph
     }
 
     // Start position for each line relative to the paragraph
@@ -4600,7 +4743,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
     int paraDescent = 0;
 
     // This calculates the partial text extents
     int paraDescent = 0;
 
     // This calculates the partial text extents
-    GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, rect.GetPosition(), & partialExtents);
+    GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, rect.GetPosition(), parentRect.GetSize(), & partialExtents);
 #else
     node = m_children.GetFirst();
     while (node)
 #else
     node = m_children.GetFirst();
     while (node)
@@ -4612,7 +4755,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
 
         node = node->GetNext();
     }
 
         node = node->GetNext();
     }
-
 #endif
 
     // Split up lines
 #endif
 
     // Split up lines
@@ -4631,8 +4773,8 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         // If floating, ignore. We already laid out floats.
         // Also ignore if empty object, except if we haven't got any
         // size yet.
         // If floating, ignore. We already laid out floats.
         // Also ignore if empty object, except if we haven't got any
         // size yet.
-        if (child->IsFloating() || !child->IsShown() ||
-            (child->GetRange().GetLength() == 0 && maxHeight > spaceBeforePara)
+        if ((child->IsFloating() && wxRichTextBuffer::GetFloatingLayoutMode())
+            || !child->IsShown() || (child->GetRange().GetLength() == 0 && maxHeight > spaceBeforePara)
             )
         {
             node = node->GetNext();
             )
         {
             node = node->GetNext();
@@ -4683,7 +4825,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 partialExtents.Clear();
 
                 // Recalculate the partial text extents since the child object changed size
                 partialExtents.Clear();
 
                 // Recalculate the partial text extents since the child object changed size
-                GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+                GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), parentRect.GetSize(), & partialExtents);
             }
         }
 
             }
         }
 
@@ -4700,10 +4842,10 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         {
 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
             // Get height only, then the width using the partial extents
         {
 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
             // Get height only, then the width using the partial extents
-            GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
+            GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY, wxPoint(0,0), parentRect.GetSize());
             childSize.x = wxRichTextGetRangeWidth(*this, wxRichTextRange(lastEndPos+1, lastPosToUse), partialExtents);
 #else
             childSize.x = wxRichTextGetRangeWidth(*this, wxRichTextRange(lastEndPos+1, lastPosToUse), partialExtents);
 #else
-            GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED, rect.GetPosition());
+            GetRangeSize(wxRichTextRange(lastEndPos+1, lastPosToUse), childSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED, rect.GetPosition(), parentRect.GetSize());
 #endif
         }
 
 #endif
         }
 
@@ -4725,7 +4867,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             wxRect oldAvailableRect = availableRect;
 
             // Available width depends on the floating objects and the line height.
             wxRect oldAvailableRect = availableRect;
 
             // Available width depends on the floating objects and the line height.
-            // Note: the floating objects may be placed vertically along the two side of
+            // Note: the floating objects may be placed vertically along the two sides of
             // buffer, so we may have different available line widths with different
             // [startY, endY]. So, we can't determine how wide the available
             // space is until we know the exact line height.
             // buffer, so we may have different available line widths with different
             // [startY, endY]. So, we can't determine how wide the available
             // space is until we know the exact line height.
@@ -4742,20 +4884,23 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             }
             lineHeight = wxMax(lineHeight, (lineDescent + lineAscent));
 
             }
             lineHeight = wxMax(lineHeight, (lineDescent + lineAscent));
 
-            wxRect floatAvailableRect = collector->GetAvailableRect(rect.y + currentPosition.y, rect.y + currentPosition.y + lineHeight);
+            if (wxRichTextBuffer::GetFloatingLayoutMode() && collector)
+            {
+                wxRect floatAvailableRect = collector->GetAvailableRect(rect.y + currentPosition.y, rect.y + currentPosition.y + lineHeight);
 
 
-            // Adjust availableRect to the space that is available when taking floating objects into account.
+                // Adjust availableRect to the space that is available when taking floating objects into account.
 
 
-            if (floatAvailableRect.x + startOffset > availableRect.x)
-            {
-                int newX = floatAvailableRect.x + startOffset;
-                int newW = availableRect.width - (newX - availableRect.x);
-                availableRect.x = newX;
-                availableRect.width = newW;
-            }
+                if (floatAvailableRect.x + startOffset > availableRect.x)
+                {
+                    int newX = floatAvailableRect.x + startOffset;
+                    int newW = availableRect.width - (newX - availableRect.x);
+                    availableRect.x = newX;
+                    availableRect.width = newW;
+                }
 
 
-            if (floatAvailableRect.width < availableRect.width)
-                availableRect.width = floatAvailableRect.width;
+                if (floatAvailableRect.width < availableRect.width)
+                    availableRect.width = floatAvailableRect.width;
+            }
 
             currentPosition.x = availableRect.x - rect.x;
 
 
             currentPosition.x = availableRect.x - rect.x;
 
@@ -4765,22 +4910,20 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 {
                     wxSize oldSize = child->GetCachedSize();
 
                 {
                     wxSize oldSize = child->GetCachedSize();
 
-                    //child->SetCachedSize(wxDefaultSize);
                     // Lays out the object first with a given amount of space, and then if no width was specified in attr,
                     // lays out the object again using the minimum size
                     child->Invalidate(wxRICHTEXT_ALL);
                     child->LayoutToBestSize(dc, context, buffer,
                     // Lays out the object first with a given amount of space, and then if no width was specified in attr,
                     // lays out the object again using the minimum size
                     child->Invalidate(wxRICHTEXT_ALL);
                     child->LayoutToBestSize(dc, context, buffer,
-                                attr, child->GetAttributes(), availableRect, parentRect, style);
+                                attr, child->GetAttributes(), availableRect, parentRect.GetSize(), style);
                     childSize = child->GetCachedSize();
                     childDescent = child->GetDescent();
                     childSize = child->GetCachedSize();
                     childDescent = child->GetDescent();
-                    //child->SetPosition(availableRect.GetPosition());
 
                     if (oldSize != child->GetCachedSize())
                     {
                         partialExtents.Clear();
 
                         // Recalculate the partial text extents since the child object changed size
 
                     if (oldSize != child->GetCachedSize())
                     {
                         partialExtents.Clear();
 
                         // Recalculate the partial text extents since the child object changed size
-                        GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), & partialExtents);
+                        GetRangeSize(GetRange(), paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_CACHE_SIZE, wxPoint(0,0), parentRect.GetSize(), & partialExtents);
                     }
 
                     // Go around the loop finding the available rect for the given floating objects
                     }
 
                     // Go around the loop finding the available rect for the given floating objects
@@ -4793,6 +4936,13 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         }
         while (doLoop);
 
         }
         while (doLoop);
 
+        if (child->IsTopLevel())
+        {
+            // We can move it to the correct position at this point
+            // TODO: probably need to add margin
+            child->Move(GetPosition() + wxPoint(currentWidth + (wxMax(leftIndent, leftIndent + leftSubIndent)), currentPosition.y));
+        }
+
         // Cases:
         // 1) There was a line break BEFORE the natural break
         // 2) There was a line break AFTER the natural break
         // Cases:
         // 1) There was a line break BEFORE the natural break
         // 2) There was a line break AFTER the natural break
@@ -4802,17 +4952,12 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         if ((lineBreakInThisObject && (childSize.x + currentWidth <= availableRect.width))
             ||
             (childSize.x + currentWidth > availableRect.width)
         if ((lineBreakInThisObject && (childSize.x + currentWidth <= availableRect.width))
             ||
             (childSize.x + currentWidth > availableRect.width)
+#if 0
             ||
             ((childSize.x + currentWidth <= availableRect.width) && !node->GetNext())
             ||
             ((childSize.x + currentWidth <= availableRect.width) && !node->GetNext())
-
+#endif
             )
         {
             )
         {
-            if (child->IsTopLevel())
-            {
-                // We can move it to the correct position at this point
-                child->Move(GetPosition() + wxPoint(currentWidth, currentPosition.y));
-            }
-
             long wrapPosition = 0;
             if ((childSize.x + currentWidth <= availableRect.width) && !node->GetNext() && !lineBreakInThisObject)
                 wrapPosition = child->GetRange().GetEnd();
             long wrapPosition = 0;
             if ((childSize.x + currentWidth <= availableRect.width) && !node->GetNext() && !lineBreakInThisObject)
                 wrapPosition = child->GetRange().GetEnd();
@@ -4835,7 +4980,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
 
             // Line end position shouldn't be the same as the end, or greater.
             if (wrapPosition >= GetRange().GetEnd())
 
             // Line end position shouldn't be the same as the end, or greater.
             if (wrapPosition >= GetRange().GetEnd())
-                wrapPosition = GetRange().GetEnd()-1;
+                wrapPosition = wxMax(0, GetRange().GetEnd()-1);
 
             // wxLogDebug(wxT("Split at %ld"), wrapPosition);
 
 
             // wxLogDebug(wxT("Split at %ld"), wrapPosition);
 
@@ -4849,12 +4994,12 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             if (!child->IsEmpty())
             {
                 // Get height only, then the width using the partial extents
             if (!child->IsEmpty())
             {
                 // Get height only, then the width using the partial extents
-                GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY);
+                GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED|wxRICHTEXT_HEIGHT_ONLY, wxPoint(0,0), parentRect.GetSize());
                 actualSize.x = wxRichTextGetRangeWidth(*this, actualRange, partialExtents);
             }
             else
 #endif
                 actualSize.x = wxRichTextGetRangeWidth(*this, actualRange, partialExtents);
             }
             else
 #endif
-                GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED);
+                GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED, wxPoint(0,0), parentRect.GetSize());
 
             currentWidth = actualSize.x;
 
 
             currentWidth = actualSize.x;
 
@@ -4952,6 +5097,44 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
 
     //wxASSERT(!(lastCompletedEndPos != -1 && lastCompletedEndPos < GetRange().GetEnd()-1));
 
 
     //wxASSERT(!(lastCompletedEndPos != -1 && lastCompletedEndPos < GetRange().GetEnd()-1));
 
+    // Add the last line - it's the current pos -> last para pos
+    // Substract -1 because the last position is always the end-paragraph position.
+    if (lastCompletedEndPos <= GetRange().GetEnd()-1)
+    {
+        currentPosition.x = (lineCount == 0 ? startPositionFirstLine : startPositionSubsequentLines);
+
+        wxRichTextLine* line = AllocateLine(lineCount);
+
+        wxRichTextRange actualRange(lastCompletedEndPos+1, GetRange().GetEnd()-1);
+
+        // Set relative range so we won't have to change line ranges when paragraphs are moved
+        line->SetRange(wxRichTextRange(actualRange.GetStart() - GetRange().GetStart(), actualRange.GetEnd() - GetRange().GetStart()));
+
+        line->SetPosition(currentPosition);
+
+        if (lineHeight == 0 && buffer)
+        {
+            wxFont font(buffer->GetFontTable().FindFont(attr));
+            wxCheckSetFont(dc, font);
+            lineHeight = dc.GetCharHeight();
+        }
+        
+        if (maxDescent == 0)
+        {
+            int w, h;
+            dc.GetTextExtent(wxT("X"), & w, &h, & maxDescent);
+        }
+
+        line->SetSize(wxSize(currentWidth, lineHeight));
+        line->SetDescent(maxDescent);
+        currentPosition.y += lineHeight;
+        currentPosition.y += lineSpacing;
+        lineCount ++;
+
+        // Apply paragraph styles such as alignment to the wrapped line
+        ApplyParagraphStyle(line, attr, availableRect, dc);
+    }
+
     // Remove remaining unused line objects, if any
     ClearUnusedLines(lineCount);
 
     // Remove remaining unused line objects, if any
     ClearUnusedLines(lineCount);
 
@@ -4986,7 +5169,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             // If floating, ignore. We already laid out floats.
             // Also ignore if empty object, except if we haven't got any
             // size yet.
             // If floating, ignore. We already laid out floats.
             // Also ignore if empty object, except if we haven't got any
             // size yet.
-            if (!child->IsFloating() && child->GetRange().GetLength() != 0 && !child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
+            if ((!child->IsFloating() || !wxRichTextBuffer::GetFloatingLayoutMode()) && child->GetRange().GetLength() != 0 && !wxDynamicCast(child, wxRichTextPlainText))
             {
                 if (child->GetCachedSize().x > minWidth)
                     minWidth = child->GetMinSize().x;
             {
                 if (child->GetCachedSize().x > minWidth)
                     minWidth = child->GetMinSize().x;
@@ -5000,7 +5183,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         SetMinSize(marginRect.GetSize());
     }
 
         SetMinSize(marginRect.GetSize());
     }
 
-
 #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
 #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
@@ -5054,6 +5236,7 @@ void wxRichTextParagraph::ApplyParagraphStyle(wxRichTextLine* line, const wxRich
         return;
 
     wxPoint pos = line->GetPosition();
         return;
 
     wxPoint pos = line->GetPosition();
+    wxPoint originalPos = pos;
     wxSize size = line->GetSize();
 
     // centering, right-justification
     wxSize size = line->GetSize();
 
     // centering, right-justification
@@ -5069,6 +5252,22 @@ void wxRichTextParagraph::ApplyParagraphStyle(wxRichTextLine* line, const wxRich
         pos.x = pos.x + rect.GetWidth() - size.x - rightIndent;
         line->SetPosition(pos);
     }
         pos.x = pos.x + rect.GetWidth() - size.x - rightIndent;
         line->SetPosition(pos);
     }
+
+    if (pos != originalPos)
+    {
+        wxPoint inc = pos - originalPos;
+
+        wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+
+        while (node)
+        {
+            wxRichTextObject* child = node->GetData();
+            if (child->IsTopLevel() && !child->GetRange().IsOutside(line->GetAbsoluteRange()))
+                child->Move(child->GetPosition() + inc);
+
+            node = node->GetNext();
+        }
+    }
 }
 
 /// Insert text at the given position
 }
 
 /// Insert text at the given position
@@ -5154,7 +5353,7 @@ void wxRichTextParagraph::ClearLines()
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
 
 /// 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, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, const wxPoint& position, const wxSize& parentSize, wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -5178,12 +5377,11 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
         wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
         while (node)
         {
         wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
         while (node)
         {
-
             wxRichTextObject* child = node->GetData();
             if (!child->GetRange().IsOutside(range))
             {
                 // Floating objects have a zero size within the paragraph.
             wxRichTextObject* child = node->GetData();
             if (!child->GetRange().IsOutside(range))
             {
                 // Floating objects have a zero size within the paragraph.
-                if (child->IsFloating())
+                if (child->IsFloating() && wxRichTextBuffer::GetFloatingLayoutMode())
                 {
                     if (partialExtents)
                     {
                 {
                     if (partialExtents)
                     {
@@ -5204,7 +5402,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                     rangeToUse.LimitTo(child->GetRange());
                     int childDescent = 0;
 
                     rangeToUse.LimitTo(child->GetRange());
                     int childDescent = 0;
 
-                    // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size,
+                    // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we've 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)
                     {
                     // but it's only going to be used after caching has taken place.
                     if ((flags & wxRICHTEXT_HEIGHT_ONLY) && child->GetCachedSize().y != 0)
                     {
@@ -5269,7 +5467,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                             partialExtents->Add(childSize.x + lastSize);
                         }
                     }
                             partialExtents->Add(childSize.x + lastSize);
                         }
                     }
-                    else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), p))
+                    else if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), parentSize, p))
                     {
                         if (childDescent == 0)
                         {
                     {
                         if (childDescent == 0)
                         {
@@ -5347,7 +5545,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                 {
                     wxRichTextObject* child = node2->GetData();
 
                 {
                     wxRichTextObject* child = node2->GetData();
 
-                    if (!child->IsFloating() && !child->GetRange().IsOutside(lineRange))
+                    if ((!child->IsFloating() || !wxRichTextBuffer::GetFloatingLayoutMode()) && !child->GetRange().IsOutside(lineRange))
                     {
                         wxRichTextRange rangeToUse = lineRange;
                         rangeToUse.LimitTo(child->GetRange());
                     {
                         wxRichTextRange rangeToUse = lineRange;
                         rangeToUse.LimitTo(child->GetRange());
@@ -5356,7 +5554,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
                         wxSize childSize;
                         int childDescent = 0;
 
                         wxSize childSize;
                         int childDescent = 0;
-                        if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y)))
+                        if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, context, flags, wxPoint(position.x + sz.x, position.y), parentSize))
                         {
                             if (childDescent == 0)
                             {
                         {
                             if (childDescent == 0)
                             {
@@ -5373,7 +5571,6 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                             maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
                             maxLineWidth += childSize.x;
                         }
                             maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
                             maxLineWidth += childSize.x;
                         }
-                        descent = wxMax(descent, childDescent);
                     }
 
                     node2 = node2->GetNext();
                     }
 
                     node2 = node2->GetNext();
@@ -5512,7 +5709,11 @@ int wxRichTextParagraph::HitTest(wxDC& dc, wxRichTextDrawingContext& context, co
     while (objNode)
     {
         wxRichTextObject* child = objNode->GetData();
     while (objNode)
     {
         wxRichTextObject* child = objNode->GetData();
-        if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0))
+        // Don't recurse if we have wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS,
+        // and also, if this seems composite but actually is marked as atomic,
+        // don't recurse.
+        if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0) &&
+            (! (((flags & wxRICHTEXT_HITTEST_HONOUR_ATOMIC) != 0) && child->IsAtomic())))
         {
             {
                 int hitTest = child->HitTest(dc, context, pt, textPosition, obj, contextObj);
         {
             {
                 int hitTest = child->HitTest(dc, context, pt, textPosition, obj, contextObj);
@@ -5559,7 +5760,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, wxRichTextDrawingContext& context, co
                 int paraDescent;
 
                 // This calculates the partial text extents
                 int paraDescent;
 
                 // This calculates the partial text extents
-                GetRangeSize(lineRange, paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED, linePos, & partialExtents);
+                GetRangeSize(lineRange, paraSize, paraDescent, dc, context, wxRICHTEXT_UNFORMATTED, linePos, wxDefaultSize, & partialExtents);
 
                 int lastX = linePos.x;
                 size_t i;
 
                 int lastX = linePos.x;
                 size_t i;
@@ -6070,7 +6271,7 @@ void wxRichTextParagraph::ClearDefaultTabs()
     sm_defaultTabs.Clear();
 }
 
     sm_defaultTabs.Clear();
 }
 
-void wxRichTextParagraph::LayoutFloat(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, int style, wxRichTextFloatCollector* floatCollector)
+void wxRichTextParagraph::LayoutFloat(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style, wxRichTextFloatCollector* floatCollector)
 {
     wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
     while (node)
 {
     wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
     while (node)
@@ -6078,9 +6279,23 @@ void wxRichTextParagraph::LayoutFloat(wxDC& dc, wxRichTextDrawingContext& contex
         wxRichTextObject* anchored = node->GetData();
         if (anchored && anchored->IsFloating() && !floatCollector->HasFloat(anchored))
         {
         wxRichTextObject* anchored = node->GetData();
         if (anchored && anchored->IsFloating() && !floatCollector->HasFloat(anchored))
         {
+            int x = 0;
+            wxRichTextAttr parentAttr(GetAttributes());
+            context.ApplyVirtualAttributes(parentAttr, this);
+#if 1
+            // 27-09-2012
+            wxRect availableSpace = GetParent()->GetAvailableContentArea(dc, context, rect);
+
+            anchored->LayoutToBestSize(dc, context, GetBuffer(),
+                parentAttr, anchored->GetAttributes(),
+                parentRect, availableSpace,
+                style);
+            wxSize size = anchored->GetCachedSize();
+#else
             wxSize size;
             wxSize size;
-            int descent, x = 0;
+            int descent = 0;
             anchored->GetRangeSize(anchored->GetRange(), size, descent, dc, context, style);
             anchored->GetRangeSize(anchored->GetRange(), size, descent, dc, context, style);
+#endif
 
             int offsetY = 0;
             if (anchored->GetAttributes().GetTextBoxAttr().GetTop().IsValid())
 
             int offsetY = 0;
             if (anchored->GetAttributes().GetTextBoxAttr().GetTop().IsValid())
@@ -6108,7 +6323,8 @@ void wxRichTextParagraph::LayoutFloat(wxDC& dc, wxRichTextDrawingContext& contex
             else if (anchored->GetAttributes().GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT)
                 x = rect.x + rect.width - size.x;
 
             else if (anchored->GetAttributes().GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT)
                 x = rect.x + rect.width - size.x;
 
-            anchored->SetPosition(wxPoint(x, pos));
+            //anchored->SetPosition(wxPoint(x, pos));
+            anchored->Move(wxPoint(x, pos)); // should move children
             anchored->SetCachedSize(size);
             floatCollector->CollectFloat(this, anchored);
         }
             anchored->SetCachedSize(size);
             floatCollector->CollectFloat(this, anchored);
         }
@@ -6234,11 +6450,17 @@ bool wxRichTextPlainText::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
 
     int offset = GetRange().GetStart();
 
 
     int offset = GetRange().GetStart();
 
-    // Replace line break characters with spaces
     wxString str = m_text;
     wxString str = m_text;
+    if (context.HasVirtualText(this))
+    {
+        if (!context.GetVirtualText(this, str) || str.Length() != m_text.Length())
+            str = m_text;
+    }
+
+    // Replace line break characters with spaces
     wxString toRemove = wxRichTextLineBreakChar;
     str.Replace(toRemove, wxT(" "));
     wxString toRemove = wxRichTextLineBreakChar;
     str.Replace(toRemove, wxT(" "));
-    if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
+    if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & (wxTEXT_ATTR_EFFECT_CAPITALS|wxTEXT_ATTR_EFFECT_SMALL_CAPITALS)))
         str.MakeUpper();
 
     long len = range.GetLength();
         str.MakeUpper();
 
     long len = range.GetLength();
@@ -6254,21 +6476,49 @@ bool wxRichTextPlainText::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
     int x, y;
     if ( textFont.IsOk() )
     {
     int x, y;
     if ( textFont.IsOk() )
     {
+        if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SMALL_CAPITALS))
+        {
+            textFont.SetPointSize((int) (textFont.GetPointSize()*0.75));
+            wxCheckSetFont(dc, textFont);
+            charHeight = dc.GetCharHeight();
+        }
+
         if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT) )
         {
         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;
+            if (textFont.IsUsingSizeInPixels())
+            {
+                double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+                x = rect.x;
+                y = rect.y;
+            }
+            else
+            {
+                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) )
         {
             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));
+            if (textFont.IsUsingSizeInPixels())
+            {
+                double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPixelSize(wxSize(0, 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));
+            }
+            else
+            {
+                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
             wxCheckSetFont(dc, textFont);
         }
         else
@@ -6507,8 +6757,8 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxRichTextAttr& attr,
 
         x += w;
     }
 
         x += w;
     }
-    return true;
 
 
+    return true;
 }
 
 /// Lay the item out
 }
 
 /// Lay the item out
@@ -6533,7 +6783,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.
 
 /// 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, wxRichTextDrawingContext& context, int WXUNUSED(flags), wxPoint position, wxArrayInt* partialExtents) const
+bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int WXUNUSED(flags), const wxPoint& position, const wxSize& WXUNUSED(parentSize), wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -6558,8 +6808,23 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
             || (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) ) )
         {
             wxFont textFont = font;
             || (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) );
+            if (textFont.IsUsingSizeInPixels())
+            {
+                double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+            }
+            else
+            {
+                double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPointSize(static_cast<int>(size));
+            }
+            wxCheckSetFont(dc, textFont);
+            bScript = true;
+        }
+        else if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SMALL_CAPITALS))
+        {
+            wxFont textFont = font;
+            textFont.SetPointSize((int) (textFont.GetPointSize()*0.75));
             wxCheckSetFont(dc, textFont);
             bScript = true;
         }
             wxCheckSetFont(dc, textFont);
             bScript = true;
         }
@@ -6574,12 +6839,18 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
     long len = range.GetLength();
 
     wxString str(m_text);
     long len = range.GetLength();
 
     wxString str(m_text);
+    if (context.HasVirtualText(this))
+    {
+        if (!context.GetVirtualText(this, str) || str.Length() != m_text.Length())
+            str = m_text;
+    }
+
     wxString toReplace = wxRichTextLineBreakChar;
     str.Replace(toReplace, wxT(" "));
 
     wxString stringChunk = str.Mid(startPos, (size_t) len);
 
     wxString toReplace = wxRichTextLineBreakChar;
     str.Replace(toReplace, wxT(" "));
 
     wxString stringChunk = str.Mid(startPos, (size_t) len);
 
-    if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
+    if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & (wxTEXT_ATTR_EFFECT_CAPITALS|wxTEXT_ATTR_EFFECT_SMALL_CAPITALS)))
         stringChunk.MakeUpper();
 
     wxCoord w, h;
         stringChunk.MakeUpper();
 
     wxCoord w, h;
@@ -6780,15 +7051,44 @@ wxString wxRichTextPlainText::GetTextForRange(const wxRichTextRange& range) cons
 }
 
 /// Returns true if this object can merge itself with the given one.
 }
 
 /// Returns true if this object can merge itself with the given one.
-bool wxRichTextPlainText::CanMerge(wxRichTextObject* object) const
+bool wxRichTextPlainText::CanMerge(wxRichTextObject* object, wxRichTextDrawingContext& context) const
 {
 {
-    return object->GetClassInfo() == CLASSINFO(wxRichTextPlainText) &&
-        (m_text.empty() || (wxTextAttrEq(GetAttributes(), object->GetAttributes()) && m_properties == object->GetProperties()));
+    // JACS 2013-01-27
+    if (!context.GetVirtualAttributesEnabled())
+    {
+        return object->GetClassInfo() == wxCLASSINFO(wxRichTextPlainText) &&
+            (m_text.empty() || (wxTextAttrEq(GetAttributes(), object->GetAttributes()) && m_properties == object->GetProperties()));
+    }
+    else
+    {
+        wxRichTextPlainText* otherObj = wxDynamicCast(object, wxRichTextPlainText);
+        if (!otherObj || m_text.empty())
+            return false;
+            
+        if (!wxTextAttrEq(GetAttributes(), object->GetAttributes()) || !(m_properties == object->GetProperties()))
+            return false;
+            
+        // Check if differing virtual attributes makes it impossible to merge
+        // these strings.
+        
+        bool hasVirtualAttr1 = context.HasVirtualAttributes((wxRichTextObject*) this);
+        bool hasVirtualAttr2 = context.HasVirtualAttributes((wxRichTextObject*) object);
+        if (!hasVirtualAttr1 && !hasVirtualAttr2)
+            return true;
+        else if (hasVirtualAttr1 != hasVirtualAttr2)
+            return false;
+        else
+        {
+            wxRichTextAttr virtualAttr1 = context.GetVirtualAttributes((wxRichTextObject*) this);
+            wxRichTextAttr virtualAttr2 = context.GetVirtualAttributes((wxRichTextObject*) object);
+            return virtualAttr1 == virtualAttr2;
+        }
+    }
 }
 
 /// Returns true if this object merged itself with the given one.
 /// The calling code will then delete the given object.
 }
 
 /// Returns true if this object merged itself with the given one.
 /// The calling code will then delete the given object.
-bool wxRichTextPlainText::Merge(wxRichTextObject* object)
+bool wxRichTextPlainText::Merge(wxRichTextObject* object, wxRichTextDrawingContext& WXUNUSED(context))
 {
     wxRichTextPlainText* textObject = wxDynamicCast(object, wxRichTextPlainText);
     wxASSERT( textObject != NULL );
 {
     wxRichTextPlainText* textObject = wxDynamicCast(object, wxRichTextPlainText);
     wxASSERT( textObject != NULL );
@@ -6803,6 +7103,214 @@ bool wxRichTextPlainText::Merge(wxRichTextObject* object)
         return false;
 }
 
         return false;
 }
 
+bool wxRichTextPlainText::CanSplit(wxRichTextDrawingContext& context) const
+{
+    // If this object has any virtual attributes at all, whether for the whole object
+    // or individual ones, we should try splitting it by calling Split.
+    // Must be more than one character in order to be able to split.
+    return m_text.Length() > 1 && context.HasVirtualAttributes((wxRichTextObject*) this);
+}
+
+wxRichTextObject* wxRichTextPlainText::Split(wxRichTextDrawingContext& context)
+{
+    int count = context.GetVirtualSubobjectAttributesCount(this);
+    if (count > 0 && GetParent())
+    {
+        wxRichTextCompositeObject* parent = wxDynamicCast(GetParent(), wxRichTextCompositeObject);
+        wxRichTextObjectList::compatibility_iterator node = parent->GetChildren().Find(this);
+        if (node)
+        {
+            const wxRichTextAttr emptyAttr;
+            wxRichTextObjectList::compatibility_iterator next = node->GetNext();
+    
+            wxArrayInt positions;
+            wxRichTextAttrArray attributes;
+            if (context.GetVirtualSubobjectAttributes(this, positions, attributes) && positions.GetCount() > 0)
+            {
+                wxASSERT(positions.GetCount() == attributes.GetCount());
+                
+                // We will gather up runs of text with the same virtual attributes
+                
+                int len = m_text.Length();
+                int i = 0;
+                
+                // runStart and runEnd represent the accumulated run with a consistent attribute
+                // that hasn't yet been appended
+                int runStart = -1;
+                int runEnd = -1;
+                wxRichTextAttr currentAttr;
+                wxString text = m_text;
+                wxRichTextPlainText* lastPlainText = this;
+                
+                for (i = 0; i < (int) positions.GetCount(); i++)
+                {
+                    int pos = positions[i];
+                    wxASSERT(pos >= 0 && pos < len);
+                    if (pos >= 0 && pos < len)
+                    {
+                        const wxRichTextAttr& attr = attributes[i];
+                        
+                        if (pos == 0)
+                        {
+                            runStart = 0;
+                            currentAttr = attr;
+                        }
+                        // Check if there was a gap from the last known attribute and this.
+                        // In that case, we need to do something with the span of non-attributed text.
+                        else if ((pos-1) > runEnd)
+                        {
+                            if (runEnd == -1)
+                            {
+                                // We hadn't processed anything previously, so the previous run is from the text start
+                                // to just before this position. The current attribute remains empty.
+                                runStart = 0;
+                                runEnd = pos-1;
+                            }
+                            else
+                            {
+                                // If the previous attribute matches the gap's attribute (i.e., no attributes)
+                                // then just extend the run.
+                                if (currentAttr.IsDefault())
+                                {
+                                    runEnd = pos-1;
+                                }
+                                else
+                                {
+                                    // We need to add an object, or reuse the existing one.
+                                    if (runStart == 0)
+                                    {
+                                        lastPlainText = this;
+                                        SetText(text.Mid(runStart, runEnd - runStart + 1));
+                                    }
+                                    else
+                                    {
+                                        wxRichTextPlainText* obj = new wxRichTextPlainText;
+                                        lastPlainText = obj;
+                                        obj->SetAttributes(GetAttributes());
+                                        obj->SetProperties(GetProperties());
+                                        obj->SetParent(parent);
+
+                                        obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+                                        if (next)
+                                            parent->GetChildren().Insert(next, obj);
+                                        else
+                                            parent->GetChildren().Append(obj);
+                                    }
+                                    
+                                    runStart = runEnd+1;
+                                    runEnd = pos-1;
+
+                                    currentAttr = emptyAttr;
+                                }
+                            }
+                        }
+                            
+                        wxASSERT(runEnd == pos-1);
+
+                        // Now we only have to deal with the previous run
+                        if (currentAttr == attr)
+                        {
+                            // If we still have the same attributes, then we
+                            // simply increase the run size.
+                            runEnd = pos;
+                        }
+                        else
+                        {
+                            if (runEnd >= 0)
+                            {
+                                // We need to add an object, or reuse the existing one.
+                                if (runStart == 0)
+                                {
+                                    lastPlainText = this;
+                                    SetText(text.Mid(runStart, runEnd - runStart + 1));
+                                }
+                                else
+                                {
+                                    wxRichTextPlainText* obj = new wxRichTextPlainText;
+                                    lastPlainText = obj;
+                                    obj->SetAttributes(GetAttributes());
+                                    obj->SetProperties(GetProperties());
+                                    obj->SetParent(parent);
+
+                                    obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+                                    if (next)
+                                        parent->GetChildren().Insert(next, obj);
+                                    else
+                                        parent->GetChildren().Append(obj);
+                                }
+                            }
+
+                            runStart = pos;
+                            runEnd = pos;
+
+                            currentAttr = attr;
+                        }
+                    }
+                }
+                
+                // We may still have a run to add, and possibly a no-attribute text fragment after that.
+                // If the whole string was already a single attribute (the run covers the whole string), don't split.
+                if ((runStart != -1) && !(runStart == 0 && runEnd == (len-1)))
+                {
+                    // If the current attribute is empty, merge the run with the next fragment
+                    // which by definition (because it's not specified) has empty attributes.
+                    if (currentAttr.IsDefault())
+                        runEnd = (len-1);
+
+                    if (runEnd < (len-1))
+                    {
+                        // We need to add an object, or reuse the existing one.
+                        if (runStart == 0)
+                        {
+                            lastPlainText = this;
+                            SetText(text.Mid(runStart, runEnd - runStart + 1));
+                        }
+                        else
+                        {
+                            wxRichTextPlainText* obj = new wxRichTextPlainText;
+                            lastPlainText = obj;
+                            obj->SetAttributes(GetAttributes());
+                            obj->SetProperties(GetProperties());
+                            obj->SetParent(parent);
+                        
+                            obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+                            if (next)
+                                parent->GetChildren().Insert(next, obj);
+                            else
+                                parent->GetChildren().Append(obj);                        
+                        }
+                        
+                        runStart = runEnd+1;
+                        runEnd = (len-1);
+                    }
+
+                    // Now the last, non-attributed fragment at the end, if any
+                    if ((runStart < len) && !(runStart == 0 && runEnd == (len-1)))
+                    {
+                        wxASSERT(runStart != 0);
+
+                        wxRichTextPlainText* obj = new wxRichTextPlainText;
+                        obj->SetAttributes(GetAttributes());
+                        obj->SetProperties(GetProperties());
+                        obj->SetParent(parent);
+                        
+                        obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+                        if (next)
+                            parent->GetChildren().Insert(next, obj);
+                        else
+                            parent->GetChildren().Append(obj);
+                        
+                        lastPlainText = obj;
+                    }
+                }
+                
+                return lastPlainText;
+            }
+        }
+    }
+    return this;
+}
+
 /// Dump to output stream for debugging
 void wxRichTextPlainText::Dump(wxTextOutputStream& stream)
 {
 /// Dump to output stream for debugging
 void wxRichTextPlainText::Dump(wxTextOutputStream& stream)
 {
@@ -6834,11 +7342,13 @@ long wxRichTextPlainText::GetFirstLineBreakPosition(long pos)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer, wxRichTextParagraphLayoutBox)
 
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer, wxRichTextParagraphLayoutBox)
 
-wxList                  wxRichTextBuffer::sm_handlers;
-wxList                  wxRichTextBuffer::sm_drawingHandlers;
-wxRichTextRenderer*     wxRichTextBuffer::sm_renderer = NULL;
-int                     wxRichTextBuffer::sm_bulletRightMargin = 20;
-float                   wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
+wxList                      wxRichTextBuffer::sm_handlers;
+wxList                      wxRichTextBuffer::sm_drawingHandlers;
+wxRichTextFieldTypeHashMap  wxRichTextBuffer::sm_fieldTypes;
+wxRichTextRenderer*         wxRichTextBuffer::sm_renderer = NULL;
+int                         wxRichTextBuffer::sm_bulletRightMargin = 20;
+float                       wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
+bool                        wxRichTextBuffer::sm_floatingLayoutMode = true;
 
 /// Initialisation
 void wxRichTextBuffer::Init()
 
 /// Initialisation
 void wxRichTextBuffer::Init()
@@ -6851,6 +7361,9 @@ void wxRichTextBuffer::Init()
     m_suppressUndo = 0;
     m_handlerFlags = 0;
     m_scale = 1.0;
     m_suppressUndo = 0;
     m_handlerFlags = 0;
     m_scale = 1.0;
+    m_dimensionScale = 1.0;
+    m_fontScale = 1.0;
+    SetMargins(4);
 }
 
 /// Initialisation
 }
 
 /// Initialisation
@@ -6885,6 +7398,8 @@ void wxRichTextBuffer::Copy(const wxRichTextBuffer& obj)
     m_batchedCommand = NULL;
     m_suppressUndo = obj.m_suppressUndo;
     m_invalidRange = obj.m_invalidRange;
     m_batchedCommand = NULL;
     m_suppressUndo = obj.m_suppressUndo;
     m_invalidRange = obj.m_invalidRange;
+    m_dimensionScale = obj.m_dimensionScale;
+    m_fontScale = obj.m_fontScale;
 }
 
 /// Push style sheet to top of stack
 }
 
 /// Push style sheet to top of stack
@@ -6943,7 +7458,10 @@ bool wxRichTextParagraphLayoutBox::InsertParagraphsWithUndo(wxRichTextBuffer* bu
 /// Submit command to insert the given text
 bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags)
 {
 /// Submit command to insert the given text
 bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags)
 {
-    return ctrl->GetFocusObject()->InsertTextWithUndo(this, pos, text, ctrl, flags);
+    if (ctrl)
+        return ctrl->GetFocusObject()->InsertTextWithUndo(this, pos, text, ctrl, flags);
+    else
+        return wxRichTextParagraphLayoutBox::InsertTextWithUndo(this, pos, text, ctrl, flags);
 }
 
 /// Submit command to insert the given text
 }
 
 /// Submit command to insert the given text
@@ -7005,6 +7523,8 @@ bool wxRichTextParagraphLayoutBox::InsertNewlineWithUndo(wxRichTextBuffer* buffe
     }
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
     }
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
 
     wxRichTextParagraph* newPara = new wxRichTextParagraph(wxEmptyString, this, & attr);
     action->GetNewParagraphs().AppendChild(newPara);
 
     wxRichTextParagraph* newPara = new wxRichTextParagraph(wxEmptyString, this, & attr);
     action->GetNewParagraphs().AppendChild(newPara);
@@ -7032,13 +7552,13 @@ bool wxRichTextParagraphLayoutBox::InsertNewlineWithUndo(wxRichTextBuffer* buffe
 
     action->SetPosition(pos);
 
 
     action->SetPosition(pos);
 
-    // Use the default character style
     // Use the default character style
     if (!buffer->GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
     {
         // Check whether the default style merely reflects the paragraph/basic style,
         // in which case don't apply it.
         wxRichTextAttr defaultStyle(buffer->GetDefaultStyle());
     // Use the default character style
     if (!buffer->GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
     {
         // Check whether the default style merely reflects the paragraph/basic style,
         // in which case don't apply it.
         wxRichTextAttr defaultStyle(buffer->GetDefaultStyle());
+        defaultStyle.GetTextBoxAttr().Reset();
         wxRichTextAttr toApply;
         if (para)
         {
         wxRichTextAttr toApply;
         if (para)
         {
@@ -7088,6 +7608,9 @@ bool wxRichTextParagraphLayoutBox::InsertImageWithUndo(wxRichTextBuffer* buffer,
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
 
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
 
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
+
     wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
     if (p)
         newPara->SetAttributes(*p);
     wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
     if (p)
         newPara->SetAttributes(*p);
@@ -7132,6 +7655,9 @@ wxRichTextObject* wxRichTextParagraphLayoutBox::InsertObjectWithUndo(wxRichTextB
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
 
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
 
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
+
     wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
     if (p)
         newPara->SetAttributes(*p);
     wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
     if (p)
         newPara->SetAttributes(*p);
@@ -7153,6 +7679,83 @@ wxRichTextObject* wxRichTextParagraphLayoutBox::InsertObjectWithUndo(wxRichTextB
     return obj;
 }
 
     return obj;
 }
 
+wxRichTextField* wxRichTextParagraphLayoutBox::InsertFieldWithUndo(wxRichTextBuffer* buffer, long pos, const wxString& fieldType,
+                                                        const wxRichTextProperties& properties,
+                                                        wxRichTextCtrl* ctrl, int flags,
+                                                        const wxRichTextAttr& textAttr)
+{
+    wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Field"), wxRICHTEXT_INSERT, buffer, this, ctrl, false);
+
+    wxRichTextAttr* p = NULL;
+    wxRichTextAttr paraAttr;
+    if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
+    {
+        paraAttr = GetStyleForNewParagraph(buffer, pos);
+        if (!paraAttr.IsDefault())
+            p = & paraAttr;
+    }
+
+    wxRichTextAttr attr(buffer->GetDefaultStyle());
+
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
+
+    wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
+    if (p)
+        newPara->SetAttributes(*p);
+
+    wxRichTextField* fieldObject = new wxRichTextField();
+    fieldObject->wxRichTextObject::SetProperties(properties);
+    fieldObject->SetFieldType(fieldType);
+    fieldObject->SetAttributes(textAttr);
+    newPara->AppendChild(fieldObject);
+    action->GetNewParagraphs().AppendChild(newPara);
+    action->GetNewParagraphs().UpdateRanges();
+    action->GetNewParagraphs().SetPartialParagraph(true);
+    action->SetPosition(pos);
+
+    // Set the range we'll need to delete in Undo
+    action->SetRange(wxRichTextRange(pos, pos));
+
+    buffer->SubmitAction(action);
+
+    wxRichTextField* obj = wxDynamicCast(GetLeafObjectAtPosition(pos), wxRichTextField);
+    return obj;
+}
+
+bool wxRichTextParagraphLayoutBox::SetObjectPropertiesWithUndo(wxRichTextObject& obj, const wxRichTextProperties& properties, wxRichTextObject* objToSet)
+{
+    wxRichTextBuffer* buffer = GetBuffer();
+    wxCHECK_MSG(buffer, false, wxT("Invalid buffer"));
+    wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
+    wxCHECK_MSG(rtc, false, wxT("Invalid rtc"));
+
+    wxRichTextAction* action = NULL;
+    wxRichTextObject* clone = NULL;
+
+    // The object on which to set properties will usually be 'obj', but use objToSet if it's valid.
+    // This is necessary e.g. on setting a wxRichTextCell's properties, when obj will be the parent table
+    if (objToSet == NULL)
+        objToSet = &obj;
+
+    if (rtc->SuppressingUndo())
+        objToSet->SetProperties(properties);
+    else
+    {
+        clone = obj.Clone();
+        objToSet->SetProperties(properties);
+
+        // The 'true' parameter in the next line says "Ignore first time"; otherwise the objects are prematurely switched
+        action = new wxRichTextAction(NULL, _("Change Properties"), wxRICHTEXT_CHANGE_OBJECT, buffer, obj.GetParentContainer(), rtc, true);
+        action->SetOldAndNewObjects(& obj, clone);
+        action->SetPosition(obj.GetRange().GetStart());
+        action->SetRange(obj.GetRange());
+        buffer->SubmitAction(action);
+    }
+
+    return true;
+}
+
 /// Get the style that is appropriate for a new paragraph at this position.
 /// If the previous paragraph has a paragraph style name, look up the next-paragraph
 /// style.
 /// Get the style that is appropriate for a new paragraph at this position.
 /// If the previous paragraph has a paragraph style name, look up the next-paragraph
 /// style.
@@ -7309,11 +7912,14 @@ bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
 
     if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
     {
 
     if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
     {
-        wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
-        cmd->AddAction(action);
-        cmd->Do();
-        cmd->GetActions().Clear();
-        delete cmd;
+        if (!action->GetIgnoreFirstTime())
+        {
+            wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
+            cmd->AddAction(action);
+            cmd->Do();
+            cmd->GetActions().Clear();
+            delete cmd;
+        }
 
         m_batchedCommand->AddAction(action);
     }
 
         m_batchedCommand->AddAction(action);
     }
@@ -7323,7 +7929,14 @@ bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
         cmd->AddAction(action);
 
         // Only store it if we're not suppressing undo.
         cmd->AddAction(action);
 
         // Only store it if we're not suppressing undo.
-        return GetCommandProcessor()->Submit(cmd, !SuppressingUndo());
+        if (!action->GetIgnoreFirstTime())
+        {
+            return GetCommandProcessor()->Submit(cmd, !SuppressingUndo());
+        }
+        else if (!SuppressingUndo())
+        {
+            GetCommandProcessor()->Store(cmd); // Just store it, without Do()ing anything
+        }
     }
 
     return true;
     }
 
     return true;
@@ -7349,9 +7962,10 @@ bool wxRichTextBuffer::EndSuppressUndo()
 bool wxRichTextBuffer::BeginStyle(const wxRichTextAttr& style)
 {
     wxRichTextAttr newStyle(GetDefaultStyle());
 bool wxRichTextBuffer::BeginStyle(const wxRichTextAttr& style)
 {
     wxRichTextAttr newStyle(GetDefaultStyle());
+    newStyle.GetTextBoxAttr().Reset();
 
     // Save the old default style
 
     // Save the old default style
-    m_attributeStack.Append((wxObject*) new wxRichTextAttr(GetDefaultStyle()));
+    m_attributeStack.Append((wxObject*) new wxRichTextAttr(newStyle));
 
     wxRichTextApplyStyle(newStyle, style);
     newStyle.SetFlags(style.GetFlags()|newStyle.GetFlags());
 
     wxRichTextApplyStyle(newStyle, style);
     newStyle.SetFlags(style.GetFlags()|newStyle.GetFlags());
@@ -7760,6 +8374,7 @@ wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save, wxArrayInt* t
     return wildcard;
 }
 
     return wildcard;
 }
 
+#if wxUSE_FFILE && wxUSE_STREAMS
 /// Load a file
 bool wxRichTextBuffer::LoadFile(const wxString& filename, wxRichTextFileType type)
 {
 /// Load a file
 bool wxRichTextBuffer::LoadFile(const wxString& filename, wxRichTextFileType type)
 {
@@ -7788,7 +8403,9 @@ bool wxRichTextBuffer::SaveFile(const wxString& filename, wxRichTextFileType typ
     else
         return false;
 }
     else
         return false;
 }
+#endif // wxUSE_FFILE && wxUSE_STREAMS
 
 
+#if wxUSE_STREAMS
 /// Load from a stream
 bool wxRichTextBuffer::LoadFile(wxInputStream& stream, wxRichTextFileType type)
 {
 /// Load from a stream
 bool wxRichTextBuffer::LoadFile(wxInputStream& stream, wxRichTextFileType type)
 {
@@ -7817,6 +8434,7 @@ bool wxRichTextBuffer::SaveFile(wxOutputStream& stream, wxRichTextFileType type)
     else
         return false;
 }
     else
         return false;
 }
+#endif // wxUSE_STREAMS
 
 /// Copy the range to the clipboard
 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
 
 /// Copy the range to the clipboard
 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
@@ -8046,7 +8664,7 @@ bool wxRichTextBuffer::SetStyleSheetAndNotify(wxRichTextStyleSheet* sheet)
     if (GetRichTextCtrl())
         winid = GetRichTextCtrl()->GetId();
 
     if (GetRichTextCtrl())
         winid = GetRichTextCtrl()->GetId();
 
-    wxRichTextEvent event(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING, winid);
+    wxRichTextEvent event(wxEVT_RICHTEXT_STYLESHEET_REPLACING, winid);
     event.SetEventObject(GetRichTextCtrl());
     event.SetContainer(GetRichTextCtrl()->GetFocusObject());
     event.SetOldStyleSheet(oldSheet);
     event.SetEventObject(GetRichTextCtrl());
     event.SetContainer(GetRichTextCtrl()->GetFocusObject());
     event.SetOldStyleSheet(oldSheet);
@@ -8066,7 +8684,7 @@ bool wxRichTextBuffer::SetStyleSheetAndNotify(wxRichTextStyleSheet* sheet)
 
     SetStyleSheet(sheet);
 
 
     SetStyleSheet(sheet);
 
-    event.SetEventType(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED);
+    event.SetEventType(wxEVT_RICHTEXT_STYLESHEET_REPLACED);
     event.SetOldStyleSheet(NULL);
     event.Allow();
 
     event.SetOldStyleSheet(NULL);
     event.Allow();
 
@@ -8099,6 +8717,17 @@ int wxRichTextBuffer::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const
     }
 }
 
     }
 }
 
+void wxRichTextBuffer::SetFontScale(double fontScale)
+{
+    m_fontScale = fontScale;
+    m_fontTable.SetFontScale(fontScale);
+}
+
+void wxRichTextBuffer::SetDimensionScale(double dimScale)
+{
+    m_dimensionScale = dimScale;
+}
+
 bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxRichTextAttr& bulletAttr, const wxRect& rect)
 {
     if (bulletAttr.GetTextColour().IsOk())
 bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxRichTextAttr& bulletAttr, const wxRect& rect)
 {
     if (bulletAttr.GetTextColour().IsOk())
@@ -8187,7 +8816,10 @@ bool wxRichTextStdRenderer::DrawTextBullet(wxRichTextParagraph* paragraph, wxDC&
         if ((attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL) && !attr.GetBulletFont().IsEmpty() && attr.HasFont())
         {
             wxRichTextAttr fontAttr;
         if ((attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL) && !attr.GetBulletFont().IsEmpty() && attr.HasFont())
         {
             wxRichTextAttr fontAttr;
-            fontAttr.SetFontSize(attr.GetFontSize());
+            if (attr.HasFontPixelSize())
+                fontAttr.SetFontPixelSize(attr.GetFontSize());
+            else
+                fontAttr.SetFontPointSize(attr.GetFontSize());
             fontAttr.SetFontStyle(attr.GetFontStyle());
             fontAttr.SetFontWeight(attr.GetFontWeight());
             fontAttr.SetFontUnderlined(attr.GetFontUnderlined());
             fontAttr.SetFontStyle(attr.GetFontStyle());
             fontAttr.SetFontWeight(attr.GetFontWeight());
             fontAttr.SetFontUnderlined(attr.GetFontUnderlined());
@@ -8298,6 +8930,345 @@ bool wxRichTextBox::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
         return false;
 }
 
+/*!
+ * wxRichTextField
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextField, wxRichTextParagraphLayoutBox)
+
+wxRichTextField::wxRichTextField(const wxString& fieldType, wxRichTextObject* parent):
+    wxRichTextParagraphLayoutBox(parent)
+{
+    SetFieldType(fieldType);
+}
+
+/// Draw the item
+bool wxRichTextField::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+{
+    if (!IsShown())
+        return true;
+
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType && fieldType->Draw(this, dc, context, range, selection, rect, descent, style))
+        return true;
+
+    // Fallback; but don't draw guidelines.
+    style &= ~wxRICHTEXT_DRAW_GUIDELINES;
+    return wxRichTextParagraphLayoutBox::Draw(dc, context, range, selection, rect, descent, style);
+}
+
+bool wxRichTextField::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType && fieldType->Layout(this, dc, context, rect, parentRect, style))
+        return true;
+
+    // Fallback
+    return wxRichTextParagraphLayoutBox::Layout(dc, context, rect, parentRect, style);
+}
+
+bool wxRichTextField::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, const wxPoint& position, const wxSize& parentSize, wxArrayInt* partialExtents) const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->GetRangeSize((wxRichTextField*) this, range, size, descent, dc, context, flags, position, parentSize, partialExtents);
+
+    return wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, parentSize, partialExtents);
+}
+
+/// Calculate range
+void wxRichTextField::CalculateRange(long start, long& end)
+{
+    if (IsTopLevel())
+        wxRichTextParagraphLayoutBox::CalculateRange(start, end);
+    else
+        wxRichTextObject::CalculateRange(start, end);
+}
+
+/// Copy
+void wxRichTextField::Copy(const wxRichTextField& obj)
+{
+    wxRichTextParagraphLayoutBox::Copy(obj);
+
+    UpdateField(GetBuffer());
+}
+
+// Edit properties via a GUI
+bool wxRichTextField::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->EditProperties(this, parent, buffer);
+
+    return false;
+}
+
+bool wxRichTextField::CanEditProperties() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->CanEditProperties((wxRichTextField*) this);
+
+    return false;
+}
+
+wxString wxRichTextField::GetPropertiesMenuLabel() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->GetPropertiesMenuLabel((wxRichTextField*) this);
+
+    return wxEmptyString;
+}
+
+bool wxRichTextField::UpdateField(wxRichTextBuffer* buffer)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->UpdateField(buffer, (wxRichTextField*) this);
+
+    return false;
+}
+
+bool wxRichTextField::IsTopLevel() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->IsTopLevel((wxRichTextField*) this);
+
+    return true;
+}
+
+IMPLEMENT_CLASS(wxRichTextFieldType, wxObject)
+
+IMPLEMENT_CLASS(wxRichTextFieldTypeStandard, wxRichTextFieldType)
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxString& label, int displayStyle)
+{
+    Init();
+
+    SetName(name);
+    SetLabel(label);
+    SetDisplayStyle(displayStyle);
+}
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxBitmap& bitmap, int displayStyle)
+{
+    Init();
+
+    SetName(name);
+    SetBitmap(bitmap);
+    SetDisplayStyle(displayStyle);
+}
+
+void wxRichTextFieldTypeStandard::Init()
+{
+    m_displayStyle = wxRICHTEXT_FIELD_STYLE_RECTANGLE;
+    m_font = wxFont(6, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+    m_textColour = *wxWHITE;
+    m_borderColour = *wxBLACK;
+    m_backgroundColour = *wxBLACK;
+    m_verticalPadding = 1;
+    m_horizontalPadding = 3;
+    m_horizontalMargin = 2;
+    m_verticalMargin = 0;
+}
+
+void wxRichTextFieldTypeStandard::Copy(const wxRichTextFieldTypeStandard& field)
+{
+    wxRichTextFieldType::Copy(field);
+
+    m_label = field.m_label;
+    m_displayStyle = field.m_displayStyle;
+    m_font = field.m_font;
+    m_textColour = field.m_textColour;
+    m_borderColour = field.m_borderColour;
+    m_backgroundColour = field.m_backgroundColour;
+    m_verticalPadding = field.m_verticalPadding;
+    m_horizontalPadding = field.m_horizontalPadding;
+    m_horizontalMargin = field.m_horizontalMargin;
+    m_bitmap = field.m_bitmap;
+}
+
+bool wxRichTextFieldTypeStandard::Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int descent, int WXUNUSED(style))
+{
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+        return false; // USe default composite drawing
+    else // if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE || m_displayStyle == wxRICHTEXT_FIELD_STYLE_NOBORDER)
+    {
+        int borderSize = 1;
+
+        wxPen borderPen(m_borderColour, 1, wxSOLID);
+        wxBrush backgroundBrush(m_backgroundColour);
+        wxColour textColour(m_textColour);
+
+        if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+        {
+            wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
+            wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+            borderPen = wxPen(highlightTextColour, 1, wxSOLID);
+            backgroundBrush = wxBrush(highlightColour);
+
+            wxCheckSetBrush(dc, backgroundBrush);
+            wxCheckSetPen(dc, wxPen(highlightColour, 1, wxSOLID));
+            dc.DrawRectangle(rect);
+        }
+
+        if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+            borderSize = 0;
+
+        // objectRect is the area where the content is drawn, after margins around it have been taken into account
+        wxRect objectRect = wxRect(wxPoint(rect.x + m_horizontalMargin, rect.y + wxMax(0, rect.height - descent - obj->GetCachedSize().y)),
+            wxSize(obj->GetCachedSize().x - 2*m_horizontalMargin - borderSize, obj->GetCachedSize().y));
+
+        // clientArea is where the text is actually written
+        wxRect clientArea = objectRect;
+
+        if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE)
+        {
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawRoundedRectangle(objectRect, 4.0);
+        }
+        else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG)
+        {
+            int arrowLength = objectRect.height/2;
+            clientArea.width -= (arrowLength - m_horizontalPadding);
+
+            wxPoint pts[5];
+            pts[0].x = objectRect.x; pts[0].y = objectRect.y;
+            pts[1].x = objectRect.x + objectRect.width - arrowLength; pts[1].y = objectRect.y;
+            pts[2].x = objectRect.x + objectRect.width; pts[2].y = objectRect.y + (objectRect.height/2);
+            pts[3].x = objectRect.x + objectRect.width - arrowLength; pts[3].y = objectRect.y + objectRect.height;
+            pts[4].x = objectRect.x; pts[4].y = objectRect.y + objectRect.height;
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawPolygon(5, pts);
+        }
+        else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+        {
+            int arrowLength = objectRect.height/2;
+            clientArea.width -= (arrowLength - m_horizontalPadding);
+            clientArea.x += (arrowLength - m_horizontalPadding);
+
+            wxPoint pts[5];
+            pts[0].x = objectRect.x + objectRect.width; pts[0].y = objectRect.y;
+            pts[1].x = objectRect.x + arrowLength; pts[1].y = objectRect.y;
+            pts[2].x = objectRect.x; pts[2].y = objectRect.y + (objectRect.height/2);
+            pts[3].x = objectRect.x + arrowLength; pts[3].y = objectRect.y + objectRect.height;
+            pts[4].x = objectRect.x + objectRect.width; pts[4].y = objectRect.y + objectRect.height;
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawPolygon(5, pts);
+        }
+
+        if (m_bitmap.IsOk())
+        {
+            int x = clientArea.x + (clientArea.width - m_bitmap.GetWidth())/2;
+            int y = clientArea.y + m_verticalPadding;
+            dc.DrawBitmap(m_bitmap, x, y, true);
+
+            if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+            {
+                wxCheckSetBrush(dc, *wxBLACK_BRUSH);
+                wxCheckSetPen(dc, *wxBLACK_PEN);
+                dc.SetLogicalFunction(wxINVERT);
+                dc.DrawRectangle(wxRect(x, y, m_bitmap.GetWidth(), m_bitmap.GetHeight()));
+                dc.SetLogicalFunction(wxCOPY);
+            }
+        }
+        else
+        {
+            wxString label(m_label);
+            if (label.IsEmpty())
+                label = wxT("??");
+            int w, h, maxDescent;
+            dc.SetFont(m_font);
+            dc.GetTextExtent(m_label, & w, &h, & maxDescent);
+            dc.SetTextForeground(textColour);
+
+            int x = clientArea.x + (clientArea.width - w)/2;
+            int y = clientArea.y + (clientArea.height - (h - maxDescent))/2;
+            dc.DrawText(m_label, x, y);
+        }
+    }
+
+    return true;
+}
+
+bool wxRichTextFieldTypeStandard::Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& WXUNUSED(rect), const wxRect& WXUNUSED(parentRect), int style)
+{
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+        return false; // USe default composite layout
+
+    wxSize size = GetSize(obj, dc, context, style);
+    obj->SetCachedSize(size);
+    obj->SetMinSize(size);
+    obj->SetMaxSize(size);
+    return true;
+}
+
+bool wxRichTextFieldTypeStandard::GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, const wxPoint& position, const wxSize& parentSize, wxArrayInt* partialExtents) const
+{
+    if (IsTopLevel(obj))
+        return obj->wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, parentSize);
+    else
+    {
+        wxSize sz = GetSize(obj, dc, context, 0);
+        if (partialExtents)
+        {
+            int lastSize;
+            if (partialExtents->GetCount() > 0)
+                lastSize = (*partialExtents)[partialExtents->GetCount()-1];
+            else
+                lastSize = 0;
+            partialExtents->Add(lastSize + sz.x);
+        }
+        size = sz;
+       return true;
+    }
+}
+
+wxSize wxRichTextFieldTypeStandard::GetSize(wxRichTextField* WXUNUSED(obj), wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), int WXUNUSED(style)) const
+{
+    int borderSize = 1;
+    int w = 0, h = 0, maxDescent = 0;
+
+    wxSize sz;
+    if (m_bitmap.IsOk())
+    {
+        w = m_bitmap.GetWidth();
+        h = m_bitmap.GetHeight();
+
+        sz = wxSize(w + m_horizontalMargin*2, h + m_verticalMargin*2);
+    }
+    else
+    {
+        wxString label(m_label);
+        if (label.IsEmpty())
+            label = wxT("??");
+        dc.SetFont(m_font);
+        dc.GetTextExtent(label, & w, &h, & maxDescent);
+
+        sz = wxSize(w + m_horizontalPadding*2 + m_horizontalMargin*2, h + m_verticalPadding *2 + m_verticalMargin*2);
+    }
+
+    if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+    {
+        sz.x += borderSize*2;
+        sz.y += borderSize*2;
+    }
+
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG || m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+    {
+        // Add space for the arrow
+        sz.x += (sz.y/2 - m_horizontalPadding);
+    }
+
+    return sz;
+}
+
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell, wxRichTextBox)
 
 wxRichTextCell::wxRichTextCell(wxRichTextObject* parent):
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell, wxRichTextBox)
 
 wxRichTextCell::wxRichTextCell(wxRichTextObject* parent):
@@ -8311,6 +9282,22 @@ bool wxRichTextCell::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxR
     return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
 }
 
     return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
 }
 
+int wxRichTextCell::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+{
+    int ret = wxRichTextParagraphLayoutBox::HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
+    if (ret != wxRICHTEXT_HITTEST_NONE)
+    {
+        return ret;
+    }
+    else
+    {
+        textPosition = m_ownRange.GetEnd()-1;
+        *obj = this;
+        *contextObj = this;
+        return wxRICHTEXT_HITTEST_AFTER|wxRICHTEXT_HITTEST_OUTSIDE;
+    }
+}
+
 /// Copy
 void wxRichTextCell::Copy(const wxRichTextCell& obj)
 {
 /// Copy
 void wxRichTextCell::Copy(const wxRichTextCell& obj)
 {
@@ -8359,18 +9346,20 @@ bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
     else
         caption = _("Cell Properties");
 
     else
         caption = _("Cell Properties");
 
+    // We don't want position and floating controls for a cell.
+    wxRichTextSizePage::ShowPositionControls(false);
+    wxRichTextSizePage::ShowFloatingControls(false);
+    wxRichTextSizePage::ShowAlignmentControls(true);
+
     wxRichTextObjectPropertiesDialog cellDlg(this, wxGetTopLevelParent(parent), wxID_ANY, caption);
     cellDlg.SetAttributes(attr);
 
     wxRichTextObjectPropertiesDialog cellDlg(this, wxGetTopLevelParent(parent), wxID_ANY, caption);
     cellDlg.SetAttributes(attr);
 
-    wxRichTextSizePage* sizePage = wxDynamicCast(cellDlg.FindPage(CLASSINFO(wxRichTextSizePage)), wxRichTextSizePage);
-    if (sizePage)
-    {
-        // We don't want position and floating controls for a cell.
-        sizePage->ShowPositionControls(false);
-        sizePage->ShowFloatingControls(false);
-    }
+    bool ok = (cellDlg.ShowModal() == wxID_OK);
 
 
-    if (cellDlg.ShowModal() == wxID_OK)
+    wxRichTextSizePage::ShowPositionControls(true);
+    wxRichTextSizePage::ShowFloatingControls(true);
+
+    if (ok)
     {
         if (multipleCells)
         {
     {
         if (multipleCells)
         {
@@ -8391,6 +9380,29 @@ bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
         return false;
 }
 
+// The next 2 methods return span values. Note that the default is 1, not 0
+int wxRichTextCell::GetColspan() const
+{
+    int span = 1;
+    if (GetProperties().HasProperty(wxT("colspan")))
+    {
+        span = GetProperties().GetPropertyLong(wxT("colspan"));
+    }
+
+    return span;
+}
+
+int wxRichTextCell::GetRowspan() const
+{
+    int span = 1;
+    if (GetProperties().HasProperty(wxT("rowspan")))
+    {
+        span = GetProperties().GetPropertyLong(wxT("rowspan"));
+    }
+
+    return span;
+}
+
 WX_DEFINE_OBJARRAY(wxRichTextObjectPtrArrayArray)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextTable, wxRichTextBox)
 WX_DEFINE_OBJARRAY(wxRichTextObjectPtrArrayArray)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextTable, wxRichTextBox)
@@ -8404,11 +9416,197 @@ wxRichTextTable::wxRichTextTable(wxRichTextObject* parent): wxRichTextBox(parent
 // Draws the object.
 bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
 {
 // Draws the object.
 bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
 {
-    return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
+    wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
+
+    int colCount = GetColumnCount();
+    int rowCount = GetRowCount();
+    int col, row;
+    for (col = 0; col < colCount; col++)
+    {
+        for (row = 0; row < rowCount; row++)
+        {
+            if (row == 0 || row == (rowCount-1) || col == 0 || col == (colCount-1))
+            {
+                wxRichTextCell* cell = GetCell(row, col);
+                if (cell && cell->IsShown() && !cell->GetRange().IsOutside(range))
+                {
+                    wxRect childRect(cell->GetPosition(), cell->GetCachedSize());
+                    wxRichTextAttr attr(cell->GetAttributes());
+                    if (row != 0)
+                        attr.GetTextBoxAttr().GetBorder().GetTop().Reset();
+                    if (row != (rowCount-1))
+                        attr.GetTextBoxAttr().GetBorder().GetBottom().Reset();
+                    if (col != 0)
+                        attr.GetTextBoxAttr().GetBorder().GetLeft().Reset();
+                    if (col != (colCount-1))
+                        attr.GetTextBoxAttr().GetBorder().GetRight().Reset();
+
+                    if (attr.GetTextBoxAttr().GetBorder().IsValid())
+                    {
+                        wxRect boxRect(cell->GetPosition(), cell->GetCachedSize());
+                        wxRect marginRect = boxRect;
+                        wxRect contentRect, borderRect, paddingRect, outlineRect;
+
+                        cell->GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
+                        cell->DrawBorder(dc, GetBuffer(), attr.GetTextBoxAttr().GetBorder(), borderRect);
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
 }
 
 }
 
-WX_DECLARE_OBJARRAY(wxRect, wxRichTextRectArray);
-WX_DEFINE_OBJARRAY(wxRichTextRectArray);
+    // Helper function for Layout() that clears the space needed by a cell with rowspan > 1
+int GetRowspanDisplacement(const wxRichTextTable* table, int row, int col, int paddingX, const wxArrayInt& colWidths)
+{
+    // If one or more cells above-left of this one has rowspan > 1, the affected cells below it
+    // will have been hidden and have width 0. As a result they are ignored by the layout algorithm,
+    // and all cells to their right are effectively shifted left. As a result there's no hole for
+    // the spanning cell to fill.
+    // So search back along the current row for hidden cells. However there's also the annoying issue of a 
+    // rowspanning cell that also has colspam. So we can't rely on the rowspanning cell being directly above
+    // the first hidden one we come to. We also can't rely on a cell being hidden only by one type of span;
+    // there's nothing to stop a cell being hidden by colspan, and then again hidden from above by rowspan.
+    // The answer is to look above each hidden cell in turn, which I think covers all bases.
+    int deltaX = 0;
+    for (int prevcol = 0; prevcol < col; ++prevcol)
+    {
+        if (!table->GetCell(row, prevcol)->IsShown())
+        {
+            // We've found a hidden cell. If it's hidden because of colspan to its left, it's
+            // already been taken into account; but not if there's a rowspanning cell above
+            for (int prevrow = row-1; prevrow >= 0; --prevrow)
+            {
+                wxRichTextCell* cell = table->GetCell(prevrow, prevcol);
+                if (cell && cell->IsShown())
+                {
+                    int rowSpan = cell->GetRowspan();
+                    if (rowSpan > 1 && rowSpan > (row-prevrow))
+                    {
+                        // There is a rowspanning cell above above the hidden one, so we need
+                        // to right-shift the index cell by this column's width. Furthermore, 
+                        // if the cell also colspans, we need to shift by all affected columns
+                        for (int colSpan = 0; colSpan < cell->GetColspan(); ++colSpan)
+                            deltaX += (colWidths[prevcol+colSpan] + paddingX);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    return deltaX;
+}
+
+    // Helper function for Layout() that expands any cell with rowspan > 1
+void ExpandCellsWithRowspan(const wxRichTextTable* table, int paddingY, int& bottomY, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& availableSpace, int style)
+{
+    // This is called when the table's cell layout is otherwise complete.
+    // For any cell with rowspan > 1, expand downwards into the row(s) below.
+    
+    // Start by finding the current 'y' of the top of each row, plus the bottom of the available area for cells.
+    // Deduce this from the top of a visible cell in the row below. (If none are visible, the row will be invisible anyway and can be ignored.)
+    const int rowCount = table->GetRowCount();
+    const int colCount = table->GetColumnCount();
+    wxArrayInt rowTops;
+    rowTops.Add(0, rowCount+1);
+    int row;
+    for (row = 0; row < rowCount; ++row)
+    {
+        for (int column = 0; column < colCount; ++column)
+        {
+            wxRichTextCell* cell = table->GetCell(row, column);
+            if (cell && cell->IsShown())
+            {
+                rowTops[row] = cell->GetPosition().y;
+                break;
+            }
+        }
+    }
+    rowTops[rowCount] = bottomY + paddingY;  // The table bottom, which was passed to us
+    
+    bool needsRelay = false;
+
+    for (row = 0; row < rowCount-1; ++row) // -1 as the bottom row can't rowspan
+    {
+        for (int col = 0; col < colCount; ++col)
+        {
+            wxRichTextCell* cell = table->GetCell(row, col);
+            if (cell && cell->IsShown())
+            {
+                int span = cell->GetRowspan();
+                if (span > 1)
+                {
+                    span = wxMin(span, rowCount-row); // Don't try to span below the table!
+                    if (span < 2)
+                        continue;
+                    
+                    int availableHeight = rowTops[row+span] - rowTops[row] - paddingY;
+                    wxSize newSize = wxSize(cell->GetCachedSize().GetWidth(), availableHeight);
+                    wxRect availableCellSpace = wxRect(cell->GetPosition(), newSize);
+                    cell->Invalidate(wxRICHTEXT_ALL);
+                    cell->Layout(dc, context, availableCellSpace, availableSpace, style);
+                    // Ensure there's room in the span to display its contents, else it'll overwrite lower rows
+                    int overhang = cell->GetCachedSize().GetHeight() - availableHeight;
+                    cell->SetCachedSize(newSize);
+
+                    if (overhang > 0)
+                    {
+                        // There are 3 things to get right:
+                        // 1) The easiest is the rows below the span: they need to be downshifted by the overhang, and so does the table bottom itself
+                        // 2) The rows within the span, including the one holding this cell, need to be deepened by their share of the overhang
+                        //    e.g. if rowspan == 3, each row should increase in depth by 1/3rd of the overhang.
+                        // 3) The cell with the rowspan shouldn't be touched in 2); its height will be set to the whole span later.
+                        int deltaY = overhang / span;
+                        int spare  = overhang % span;
+                        
+                        // Each row in the span needs to by deepened by its share of the overhang (give the first row any spare).
+                        // This is achieved by increasing the value stored in the following row's rowTops
+                        for (int spannedRows = 0; spannedRows < span; ++spannedRows)
+                        {
+                            rowTops[row+spannedRows+1] += ((deltaY * (spannedRows+1))  + (spannedRows == 0 ? spare:0));
+                        }
+                        
+                        // Any rows below the span need shifting down
+                        for (int rowsBelow = row + span+1; rowsBelow <= rowCount; ++rowsBelow)
+                        {
+                            rowTops[rowsBelow] += overhang;
+                        }                        
+
+                        needsRelay = true;
+                    }
+                }
+            }
+        }
+    }
+   
+    if (!needsRelay)
+        return;
+
+    // There were overflowing rowspanning cells, so layout yet again to make the increased row depths show
+    for (row = 0; row < rowCount; ++row)
+    {
+        for (int col = 0; col < colCount; ++col)
+        {
+            wxRichTextCell* cell = table->GetCell(row, col);
+            if (cell && cell->IsShown())
+            {
+                wxPoint position(cell->GetPosition().x, rowTops[row]);
+
+                // GetRowspan() will usually return 1, but may be greater
+                wxSize size(cell->GetCachedSize().GetWidth(), rowTops[row + cell->GetRowspan()] - rowTops[row] - paddingY);
+
+                wxRect availableCellSpace = wxRect(position, size);
+                cell->Invalidate(wxRICHTEXT_ALL);
+                cell->Layout(dc, context, availableCellSpace, availableSpace, style);
+                cell->SetCachedSize(size);
+            }
+        }
+        
+        bottomY = rowTops[rowCount] - paddingY;
+    }
+}
 
 // Lays the object out. rect is the space available for layout. Often it will
 // be the specified overall space for this object, if trying to constrain
 
 // Lays the object out. rect is the space available for layout. Often it will
 // be the specified overall space for this object, if trying to constrain
@@ -8419,7 +9617,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 {
     SetPosition(rect.GetPosition());
 
 {
     SetPosition(rect.GetPosition());
 
-    // TODO: the meaty bit. Calculate sizes of all cells and rows. Try to use
+    // The meaty bit. Calculate sizes of all cells and rows. Try to use
     // minimum size if within alloted size, then divide up remaining size
     // between rows/cols.
 
     // minimum size if within alloted size, then divide up remaining size
     // between rows/cols.
 
@@ -8433,12 +9631,13 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     wxRichTextAttr attr(GetAttributes());
     context.ApplyVirtualAttributes(attr, this);
 
     wxRichTextAttr attr(GetAttributes());
     context.ApplyVirtualAttributes(attr, this);
 
+    bool tableHasPercentWidth = (attr.GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE);
     // If we have no fixed table size, and assuming we're not pushed for
     // space, then we don't have to try to stretch the table to fit the contents.
     // If we have no fixed table size, and assuming we're not pushed for
     // space, then we don't have to try to stretch the table to fit the contents.
-    bool stretchToFitTableWidth = false;
-
+    bool stretchToFitTableWidth = tableHasPercentWidth;
+    
     int tableWidth = rect.width;
     int tableWidth = rect.width;
-    if (attr.GetTextBoxAttr().GetWidth().IsValid())
+    if (attr.GetTextBoxAttr().GetWidth().IsValid() && !tableHasPercentWidth)
     {
         tableWidth = converter.GetPixels(attr.GetTextBoxAttr().GetWidth());
 
     {
         tableWidth = converter.GetPixels(attr.GetTextBoxAttr().GetWidth());
 
@@ -8484,9 +9683,14 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
     wxArrayInt absoluteColWidths;
     absoluteColWidths.Add(0, m_colCount);
 
     wxArrayInt absoluteColWidths;
     absoluteColWidths.Add(0, m_colCount);
-    // wxArrayInt absoluteColWidthsSpanning(m_colCount);
+
     wxArrayInt percentageColWidths;
     percentageColWidths.Add(0, m_colCount);
     wxArrayInt percentageColWidths;
     percentageColWidths.Add(0, m_colCount);
+
+    // The required width of a column calculated from the content, in case we don't specify any widths
+    wxArrayInt maxUnspecifiedColumnWidths;
+    maxUnspecifiedColumnWidths.Add(0, m_colCount);
+
     // wxArrayInt percentageColWidthsSpanning(m_colCount);
     // These are only relevant when the first column contains spanning information.
     // wxArrayInt columnSpans(m_colCount); // Each contains 1 for non-spanning cell, > 1 for spanning cell.
     // wxArrayInt percentageColWidthsSpanning(m_colCount);
     // These are only relevant when the first column contains spanning information.
     // wxArrayInt columnSpans(m_colCount); // Each contains 1 for non-spanning cell, > 1 for spanning cell.
@@ -8535,12 +9739,9 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     {
         for (i = 0; i < m_colCount; i++)
         {
     {
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
-            int colSpan = 1, rowSpan = 1;
-            if (cell->GetProperties().HasProperty(wxT("colspan")))
-                colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-            if (cell->GetProperties().HasProperty(wxT("rowspan")))
-                rowSpan = cell->GetProperties().GetPropertyLong(wxT("rowspan"));
+            wxRichTextCell* cell = GetCell(j, i);
+            int colSpan = cell->GetColspan();
+            int rowSpan = cell->GetRowspan();
             if (colSpan > 1 || rowSpan > 1)
             {
                 rectArray.Add(wxRect(i, j, colSpan, rowSpan));
             if (colSpan > 1 || rowSpan > 1)
             {
                 rectArray.Add(wxRect(i, j, colSpan, rowSpan));
@@ -8552,18 +9753,16 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     {
         for (i = 0; i < m_colCount; i++)
         {
     {
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
+            wxRichTextCell* cell = GetCell(j, i);
             if (rectArray.GetCount() == 0)
             {
                 cell->Show(true);
             }
             else
             {
             if (rectArray.GetCount() == 0)
             {
                 cell->Show(true);
             }
             else
             {
-                int colSpan = 1, rowSpan = 1;
-                if (cell->GetProperties().HasProperty(wxT("colspan")))
-                    colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-                if (cell->GetProperties().HasProperty(wxT("rowspan")))
-                    rowSpan = cell->GetProperties().GetPropertyLong(wxT("rowspan"));
+                int colSpan = cell->GetColspan();
+                int rowSpan = cell->GetRowspan();
+
                 if (colSpan > 1 || rowSpan > 1)
                 {
                     // Assume all spanning cells are shown
                 if (colSpan > 1 || rowSpan > 1)
                 {
                     // Assume all spanning cells are shown
@@ -8586,7 +9785,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         }
     }
 
         }
     }
 
-    // TODO: find the first spanned cell in each row that spans the most columns and doesn't
+    // Find the first spanned cell in each row that spans the most columns and doesn't
     // overlap with a spanned cell starting at a previous column position.
     // This means we need to keep an array of rects so we can check. However
     // it does also mean that some spans simply may not be taken into account
     // overlap with a spanned cell starting at a previous column position.
     // This means we need to keep an array of rects so we can check. However
     // it does also mean that some spans simply may not be taken into account
@@ -8626,12 +9825,10 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
         for (i = 0; i < m_colCount; i++)
         {
 
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
+            wxRichTextCell* cell = GetCell(j, i);
             if (cell->IsShown())
             {
             if (cell->IsShown())
             {
-                int colSpan = 1;
-                if (cell->GetProperties().HasProperty(wxT("colspan")))
-                    colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
+                int colSpan = cell->GetColspan();
 
                 // Lay out cell to find min/max widths
                 cell->Invalidate(wxRICHTEXT_ALL);
 
                 // Lay out cell to find min/max widths
                 cell->Invalidate(wxRICHTEXT_ALL);
@@ -8673,6 +9870,8 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
                         if (cell->GetMinSize().x > 0 && absoluteCellWidth !=1 && cell->GetMinSize().x > absoluteCellWidth)
                             absoluteCellWidth = cell->GetMinSize().x;
                     }
                         if (cell->GetMinSize().x > 0 && absoluteCellWidth !=1 && cell->GetMinSize().x > absoluteCellWidth)
                             absoluteCellWidth = cell->GetMinSize().x;
                     }
+                    else
+                        maxUnspecifiedColumnWidths[i] = wxMax(cell->GetMaxSize().x, maxUnspecifiedColumnWidths[i]);
 
                     if (absoluteCellWidth != -1)
                     {
 
                     if (absoluteCellWidth != -1)
                     {
@@ -8751,13 +9950,10 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
         for (i = 0; i < m_colCount; i++)
         {
 
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
+            wxRichTextCell* cell = GetCell(j, i);
             if (cell->IsShown())
             {
             if (cell->IsShown())
             {
-                int colSpan = 1;
-                if (cell->GetProperties().HasProperty(wxT("colspan")))
-                    colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-
+                int colSpan = cell->GetColspan();
                 if (colSpan > 1)
                 {
                     int spans = wxMin(colSpan, m_colCount - i);
                 if (colSpan > 1)
                 {
                     int spans = wxMin(colSpan, m_colCount - i);
@@ -8783,6 +9979,9 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
                             // then we simply stop constraining the columns; instead, we'll just fit the spanning
                             // cells to the columns later.
                             cellWidth = cell->GetMinSize().x;
                             // then we simply stop constraining the columns; instead, we'll just fit the spanning
                             // cells to the columns later.
                             cellWidth = cell->GetMinSize().x;
+
+                            maxUnspecifiedColumnWidths[i] = wxMax(cell->GetMaxSize().x, maxUnspecifiedColumnWidths[i]);
+
                             if (cell->GetMaxSize().x > cellWidth)
                                 cellWidth = cell->GetMaxSize().x;
                         }
                             if (cell->GetMaxSize().x > cellWidth)
                                 cellWidth = cell->GetMaxSize().x;
                         }
@@ -8833,6 +10032,14 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         }
     }
 
         }
     }
 
+    // (3.1) if a column has zero width, make it the maximum unspecified width (i.e. using
+    // the cell's contents to calculate the width)
+    for (i = 0; i < m_colCount; i++)
+    {
+        if (colWidths[i] == 0)
+            colWidths[i] = maxUnspecifiedColumnWidths[i];
+    }
+
     // (4) Next, share any remaining space out between columns that have not yet been calculated.
     // TODO: take into account min widths of columns within the span
     int tableWidthMinusPadding = internalTableWidth - (m_colCount-1)*paddingX;
     // (4) Next, share any remaining space out between columns that have not yet been calculated.
     // TODO: take into account min widths of columns within the span
     int tableWidthMinusPadding = internalTableWidth - (m_colCount-1)*paddingX;
@@ -8840,7 +10047,6 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     int stretchColCount = 0;
     for (i = 0; i < m_colCount; i++)
     {
     int stretchColCount = 0;
     for (i = 0; i < m_colCount; i++)
     {
-        // TODO: we need to take into account min widths.
         // Subtract min width from width left, then
         // add the colShare to the min width
         if (colWidths[i] > 0) // absolute or proportional width has been specified
         // Subtract min width from width left, then
         // add the colShare to the min width
         if (colWidths[i] > 0) // absolute or proportional width has been specified
@@ -8897,16 +10103,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         }
     }
 
         }
     }
 
-    // TODO: if spanned cells have no specified or max width, make them the
-    // as big as the columns they span. Do this for all spanned cells in all
-    // rows, of course. Size any spanned cells left over at the end - even if they
-    // have width > 0, make sure they're limited to the appropriate column edge.
-
-
 /*
 /*
-    Sort out confusion between content width
-    and overall width later. For now, assume we specify overall width.
-
     So, now we've laid out the table to fit into the given space
     and have used specified widths and minimum widths.
 
     So, now we've laid out the table to fit into the given space
     and have used specified widths and minimum widths.
 
@@ -8946,19 +10143,16 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
                 if (colWidths[i] > 0) // absolute or proportional width has been specified
                 {
 
                 if (colWidths[i] > 0) // absolute or proportional width has been specified
                 {
-                    int colSpan = 1;
-                    if (cell->GetProperties().HasProperty(wxT("colspan")))
-                        colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-
+                    int colSpan = cell->GetColspan();
                     wxRect availableCellSpace;
 
                     wxRect availableCellSpace;
 
-                    // TODO: take into acount spans
+                    // Take into account spans
                     if (colSpan > 1)
                     {
                         // Calculate the size of this spanning cell from its constituent columns
                     if (colSpan > 1)
                     {
                         // Calculate the size of this spanning cell from its constituent columns
-                        int xx = x;
+                        int xx = 0;
                         int spans = wxMin(colSpan, m_colCount - i);
                         int spans = wxMin(colSpan, m_colCount - i);
-                        for (k = i; k < spans; k++)
+                        for (k = i; k < (i+spans); k++)
                         {
                             if (k != i)
                                 xx += paddingX;
                         {
                             if (k != i)
                                 xx += paddingX;
@@ -8972,6 +10166,10 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
                     // Store actual width so we can force cell to be the appropriate width on the final loop
                     actualWidths[i] = availableCellSpace.GetWidth();
 
                     // Store actual width so we can force cell to be the appropriate width on the final loop
                     actualWidths[i] = availableCellSpace.GetWidth();
 
+                    // We now need to shift right by the width of any rowspanning cells above-left of us
+                    int deltaX = GetRowspanDisplacement(this, j, i, paddingX, colWidths);
+                    availableCellSpace.SetX(availableCellSpace.GetX() + deltaX);
+
                     // Lay out cell
                     cell->Invalidate(wxRICHTEXT_ALL);
                     cell->Layout(dc, context, availableCellSpace, availableSpace, style);
                     // Lay out cell
                     cell->Invalidate(wxRICHTEXT_ALL);
                     cell->Layout(dc, context, availableCellSpace, availableSpace, style);
@@ -8979,7 +10177,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
                     // TODO: use GetCachedSize().x to compute 'natural' size
 
                     x += (availableCellSpace.GetWidth() + paddingX);
                     // TODO: use GetCachedSize().x to compute 'natural' size
 
                     x += (availableCellSpace.GetWidth() + paddingX);
-                    if (cell->GetCachedSize().y > maxCellHeight)
+                    if ((cell->GetCachedSize().y > maxCellHeight) && (cell->GetRowspan() < 2))
                         maxCellHeight = cell->GetCachedSize().y;
                 }
             }
                         maxCellHeight = cell->GetCachedSize().y;
                 }
             }
@@ -9009,6 +10207,9 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         if (j < (m_rowCount-1))
             y += paddingY;
     }
         if (j < (m_rowCount-1))
             y += paddingY;
     }
+    
+    // Finally we need to expand any cell with rowspan > 1. We couldn't earlier; lower rows' heights weren't known
+    ExpandCellsWithRowspan(this, paddingY, y, dc, context, availableSpace, style);
 
     // We need to add back the margins etc.
     {
 
     // We need to add back the margins etc.
     {
@@ -9028,18 +10229,6 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         SetMinSize(GetCachedSize());
     }
 
         SetMinSize(GetCachedSize());
     }
 
-    // TODO: currently we use either a fixed table width or the parent's size.
-    // We also want to be able to calculate the table width from its content,
-    // whether using fixed column widths or cell content min/max width.
-    // Probably need a boolean flag to say whether we need to stretch cells
-    // to fit the table width, or to simply use min/max cell widths. The
-    // trouble with this is that if cell widths are not specified, they
-    // will be tiny; we could use arbitrary defaults but this seems unsatisfactory.
-    // Anyway, ignoring that problem, we probably need to factor layout into a function
-    // that can can calculate the maximum unconstrained layout in case table size is
-    // not specified. Then LayoutToBestSize() can choose to use either parent size to
-    // constrain Layout(), or the previously-calculated max size to constraint layout.
-
     return true;
 }
 
     return true;
 }
 
@@ -9129,9 +10318,9 @@ void wxRichTextTable::CalculateRange(long start, long& end)
 }
 
 // Gets the range size.
 }
 
 // Gets the range size.
-bool wxRichTextTable::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+bool wxRichTextTable::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, const wxPoint& position, const wxSize& parentSize, wxArrayInt* partialExtents) const
 {
 {
-    return wxRichTextBox::GetRangeSize(range, size, descent, dc, context, flags, position, partialExtents);
+    return wxRichTextBox::GetRangeSize(range, size, descent, dc, context, flags, position, parentSize, partialExtents);
 }
 
 // Deletes content in the given range.
 }
 
 // Deletes content in the given range.
@@ -9177,12 +10366,17 @@ void wxRichTextTable::ClearTable()
 {
     m_cells.Clear();
     DeleteChildren();
 {
     m_cells.Clear();
     DeleteChildren();
+    m_rowCount = 0;
+    m_colCount = 0;
 }
 
 bool wxRichTextTable::CreateTable(int rows, int cols)
 {
     ClearTable();
 
 }
 
 bool wxRichTextTable::CreateTable(int rows, int cols)
 {
     ClearTable();
 
+    wxRichTextAttr cellattr;
+    cellattr.SetTextColour(GetBasicStyle().GetTextColour());
+
     m_rowCount = rows;
     m_colCount = cols;
 
     m_rowCount = rows;
     m_colCount = cols;
 
@@ -9195,6 +10389,8 @@ bool wxRichTextTable::CreateTable(int rows, int cols)
         for (j = 0; j < cols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
         for (j = 0; j < cols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
+            cell->GetAttributes() = cellattr;
+
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
 
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
 
@@ -9329,12 +10525,67 @@ bool wxRichTextTable::SetCellStyle(const wxRichTextSelection& selection, const w
     return true;
 }
 
     return true;
 }
 
+wxPosition wxRichTextTable::GetFocusedCell() const
+{
+    wxPosition position(-1, -1);
+    const wxRichTextObject* focus = GetBuffer()->GetRichTextCtrl()->GetFocusObject();
+
+    for (int row = 0; row < GetRowCount(); ++row)
+    {
+        for (int col = 0; col < GetColumnCount(); ++col)
+        {
+            if (GetCell(row, col) == focus)
+            {
+              position.SetRow(row);
+              position.SetCol(col);
+              return position;
+            }
+        }
+    }
+
+    return position;
+}
+
+int wxRichTextTable::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+{
+    for (int row = 0; row < GetRowCount(); ++row)
+    {
+        for (int col = 0; col < GetColumnCount(); ++col)
+        {
+            wxRichTextCell* cell = GetCell(row, col);
+            if (cell->wxRichTextObject::HitTest(dc, context, pt, textPosition, obj, contextObj, flags) != wxRICHTEXT_HITTEST_NONE)
+            {
+                return cell->HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
+            }
+        }
+    }
+
+    return wxRICHTEXT_HITTEST_NONE;
+}
+
 bool wxRichTextTable::DeleteRows(int startRow, int noRows)
 {
 bool wxRichTextTable::DeleteRows(int startRow, int noRows)
 {
-    wxASSERT((startRow + noRows) < m_rowCount);
-    if ((startRow + noRows) >= m_rowCount)
+    wxASSERT((startRow + noRows) <= m_rowCount);
+    if ((startRow + noRows) > m_rowCount)
         return false;
 
         return false;
 
+    wxCHECK_MSG(noRows != m_rowCount, false, "Trying to delete all the cells in a table");
+
+    wxRichTextBuffer* buffer = GetBuffer();
+    wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
+
+    wxRichTextAction* action = NULL;
+    wxRichTextTable* clone = NULL;
+    if (!rtc->SuppressingUndo())
+    {
+        // Create a clone containing the current state of the table. It will be used to Undo the action
+        clone = wxStaticCast(this->Clone(), wxRichTextTable);
+        clone->SetParent(GetParent());
+        action = new wxRichTextAction(NULL, _("Delete Row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
+        action->SetObject(this);
+        action->SetPosition(GetRange().GetStart());
+    }
+
     int i, j;
     for (i = startRow; i < (startRow+noRows); i++)
     {
     int i, j;
     for (i = startRow; i < (startRow+noRows); i++)
     {
@@ -9352,25 +10603,50 @@ bool wxRichTextTable::DeleteRows(int startRow, int noRows)
 
     m_rowCount = m_rowCount - noRows;
 
 
     m_rowCount = m_rowCount - noRows;
 
+    if (!rtc->SuppressingUndo())
+    {
+        buffer->SubmitAction(action);
+        // Finally store the original-state clone; doing so earlier would cause various failures
+        action->StoreObject(clone);
+    }
+
     return true;
 }
 
 bool wxRichTextTable::DeleteColumns(int startCol, int noCols)
 {
     return true;
 }
 
 bool wxRichTextTable::DeleteColumns(int startCol, int noCols)
 {
-    wxASSERT((startCol + noCols) < m_colCount);
-    if ((startCol + noCols) >= m_colCount)
+    wxASSERT((startCol + noCols) <= m_colCount);
+    if ((startCol + noCols) > m_colCount)
         return false;
 
         return false;
 
+    wxCHECK_MSG(noCols != m_colCount, false, "Trying to delete all the cells in a table");
+
+    wxRichTextBuffer* buffer = GetBuffer();
+    wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
+
+    wxRichTextAction* action = NULL;
+    wxRichTextTable* clone = NULL;
+    if (!rtc->SuppressingUndo())
+    {
+        // Create a clone containing the current state of the table. It will be used to Undo the action
+        clone = wxStaticCast(this->Clone(), wxRichTextTable);
+        clone->SetParent(GetParent());
+        action = new wxRichTextAction(NULL, _("Delete Column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
+        action->SetObject(this);
+        action->SetPosition(GetRange().GetStart());
+    }
+
     bool deleteRows = (noCols == m_colCount);
 
     int i, j;
     for (i = 0; i < m_rowCount; i++)
     {
         wxRichTextObjectPtrArray& colArray = m_cells[deleteRows ? 0 : i];
     bool deleteRows = (noCols == m_colCount);
 
     int i, j;
     for (i = 0; i < m_rowCount; i++)
     {
         wxRichTextObjectPtrArray& colArray = m_cells[deleteRows ? 0 : i];
-        for (j = startCol; j < (startCol+noCols); j++)
+        for (j = 0; j < noCols; j++) 
         {
         {
-            wxRichTextObject* cell = colArray[j];
+            wxRichTextObject* cell = colArray[startCol];
             RemoveChild(cell, true);
             RemoveChild(cell, true);
+            colArray.RemoveAt(startCol);
         }
 
         if (deleteRows)
         }
 
         if (deleteRows)
@@ -9381,6 +10657,13 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols)
         m_rowCount = 0;
     m_colCount = m_colCount - noCols;
 
         m_rowCount = 0;
     m_colCount = m_colCount - noCols;
 
+    if (!rtc->SuppressingUndo())
+    {
+        buffer->SubmitAction(action);
+        // Finally store the original-state clone; doing so earlier would cause various failures
+        action->StoreObject(clone);
+    }
+
     return true;
 }
 
     return true;
 }
 
@@ -9390,6 +10673,24 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at
     if (startRow > m_rowCount)
         return false;
 
     if (startRow > m_rowCount)
         return false;
 
+    wxRichTextBuffer* buffer = GetBuffer();
+    wxRichTextAction* action = NULL;
+    wxRichTextTable* clone = NULL;
+    
+    if (!buffer->GetRichTextCtrl()->SuppressingUndo())
+    {
+        // Create a clone containing the current state of the table. It will be used to Undo the action
+        clone = wxStaticCast(this->Clone(), wxRichTextTable);
+        clone->SetParent(GetParent());
+        action = new wxRichTextAction(NULL, _("Add Row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
+        action->SetObject(this);
+        action->SetPosition(GetRange().GetStart());
+    }
+
+    wxRichTextAttr cellattr = attr;
+    if (!cellattr.GetTextColour().IsOk())
+        cellattr.SetTextColour(buffer->GetBasicStyle().GetTextColour());
+
     int i, j;
     for (i = 0; i < noRows; i++)
     {
     int i, j;
     for (i = 0; i < noRows; i++)
     {
@@ -9409,14 +10710,23 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at
         for (j = 0; j < m_colCount; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
         for (j = 0; j < m_colCount; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
-            cell->GetAttributes() = attr;
+            cell->GetAttributes() = cellattr;
 
             AppendChild(cell);
 
             AppendChild(cell);
+            cell->AddParagraph(wxEmptyString);
             colArray.Add(cell);
         }
     }
 
     m_rowCount = m_rowCount + noRows;
             colArray.Add(cell);
         }
     }
 
     m_rowCount = m_rowCount + noRows;
+
+    if (!buffer->GetRichTextCtrl()->SuppressingUndo())
+    {
+        buffer->SubmitAction(action);
+        // Finally store the original-state clone; doing so earlier would cause various failures
+        action->StoreObject(clone);
+    }
+
     return true;
 }
 
     return true;
 }
 
@@ -9426,6 +10736,24 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr&
     if (startCol > m_colCount)
         return false;
 
     if (startCol > m_colCount)
         return false;
 
+    wxRichTextBuffer* buffer = GetBuffer();
+    wxRichTextAction* action = NULL;
+    wxRichTextTable* clone = NULL;
+
+    if (!buffer->GetRichTextCtrl()->SuppressingUndo())
+    {
+        // Create a clone containing the current state of the table. It will be used to Undo the action
+        clone = wxStaticCast(this->Clone(), wxRichTextTable);
+        clone->SetParent(GetParent());
+        action = new wxRichTextAction(NULL, _("Add Column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
+        action->SetObject(this);
+        action->SetPosition(GetRange().GetStart());
+    }
+
+    wxRichTextAttr cellattr = attr;
+    if (!cellattr.GetTextColour().IsOk())
+        cellattr.SetTextColour(buffer->GetBasicStyle().GetTextColour());
+
     int i, j;
     for (i = 0; i < m_rowCount; i++)
     {
     int i, j;
     for (i = 0; i < m_rowCount; i++)
     {
@@ -9433,9 +10761,10 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr&
         for (j = 0; j < noCols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
         for (j = 0; j < noCols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
-            cell->GetAttributes() = attr;
+            cell->GetAttributes() = cellattr;
 
             AppendChild(cell);
 
             AppendChild(cell);
+            cell->AddParagraph(wxEmptyString);
 
             if (startCol == m_colCount)
                 colArray.Add(cell);
 
             if (startCol == m_colCount)
                 colArray.Add(cell);
@@ -9446,6 +10775,13 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr&
 
     m_colCount = m_colCount + noCols;
 
 
     m_colCount = m_colCount + noCols;
 
+    if (!buffer->GetRichTextCtrl()->SuppressingUndo())
+    {
+        buffer->SubmitAction(action);
+        // Finally store the original-state clone; doing so earlier would cause various failures
+        action->StoreObject(clone);
+    }
+
     return true;
 }
 
     return true;
 }
 
@@ -9464,6 +10800,90 @@ bool wxRichTextTable::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
         return false;
 }
 
+bool wxRichTextTableBlock::ComputeBlockForSelection(wxRichTextTable* table, wxRichTextCtrl* ctrl, bool requireCellSelection)
+{
+    if (!ctrl)
+        return false;
+
+    ColStart() = 0;
+    ColEnd() = table->GetColumnCount()-1;
+    RowStart() = 0;
+    RowEnd() = table->GetRowCount()-1;
+
+    wxRichTextSelection selection = ctrl->GetSelection();
+    if (selection.IsValid() && selection.GetContainer() == table)
+    {
+        // Start with an invalid block and increase.
+        wxRichTextTableBlock selBlock(-1, -1, -1, -1);
+        wxRichTextRangeArray ranges = selection.GetRanges();
+        int row, col;
+        for (row = 0; row < table->GetRowCount(); row++)
+        {
+            for (col = 0; col < table->GetColumnCount(); col++)
+            {
+                if (selection.WithinSelection(table->GetCell(row, col)->GetRange().GetStart()))
+                {
+                    if (selBlock.ColStart() == -1)
+                        selBlock.ColStart() = col;
+                    if (selBlock.ColEnd() == -1)
+                        selBlock.ColEnd() = col;
+                    if (col < selBlock.ColStart())
+                        selBlock.ColStart() = col;
+                    if (col > selBlock.ColEnd())
+                        selBlock.ColEnd() = col;
+
+                    if (selBlock.RowStart() == -1)
+                        selBlock.RowStart() = row;
+                    if (selBlock.RowEnd() == -1)
+                        selBlock.RowEnd() = row;
+                    if (row < selBlock.RowStart())
+                        selBlock.RowStart() = row;
+                    if (row > selBlock.RowEnd())
+                        selBlock.RowEnd() = row;
+                }
+            }
+        }
+
+        if (selBlock.RowStart() != -1 && selBlock.RowEnd() != -1 && selBlock.ColStart() != -1 && selBlock.ColEnd() != -1)
+            (*this) = selBlock;
+    }
+    else
+    {
+        // See if a whole cell's contents is selected, in which case we can treat the cell as selected.
+        // wxRTC lacks the ability to select a single cell.
+        wxRichTextCell* cell = wxDynamicCast(ctrl->GetFocusObject(), wxRichTextCell);
+        if (cell && (!requireCellSelection || (ctrl->HasSelection() && ctrl->GetSelectionRange() == cell->GetOwnRange())))
+        {
+            int row, col;
+            if (table->GetCellRowColumnPosition(cell->GetRange().GetStart(), row, col))
+            {
+                RowStart() = row;
+                RowEnd() = row;
+                ColStart() = col;
+                ColEnd() = col;
+            }
+        }
+    }
+
+    return true;
+}
+
+// Does this block represent the whole table?
+bool wxRichTextTableBlock::IsWholeTable(wxRichTextTable* table) const
+{
+    return (ColStart() == 0 && RowStart() == 0 && ColEnd() == (table->GetColumnCount()-1) && RowEnd() == (table->GetRowCount()-1));
+}
+
+// Returns the cell focused in the table, if any
+wxRichTextCell* wxRichTextTableBlock::GetFocusedCell(wxRichTextCtrl* ctrl)
+{
+    if (!ctrl)
+        return NULL;
+
+    wxRichTextCell* cell = wxDynamicCast(ctrl->GetFocusObject(), wxRichTextCell);
+    return cell;
+}
+
 /*
  * Module to initialise and clean up handlers
  */
 /*
  * Module to initialise and clean up handlers
  */
@@ -9478,12 +10898,25 @@ public:
         wxRichTextBuffer::SetRenderer(new wxRichTextStdRenderer);
         wxRichTextBuffer::InitStandardHandlers();
         wxRichTextParagraph::InitDefaultTabs();
         wxRichTextBuffer::SetRenderer(new wxRichTextStdRenderer);
         wxRichTextBuffer::InitStandardHandlers();
         wxRichTextParagraph::InitDefaultTabs();
+
+        wxRichTextXMLHandler::RegisterNodeName(wxT("text"), wxT("wxRichTextPlainText"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("symbol"), wxT("wxRichTextPlainText"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("image"), wxT("wxRichTextImage"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("paragraph"), wxT("wxRichTextParagraph"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("paragraphlayout"), wxT("wxRichTextParagraphLayoutBox"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("textbox"), wxT("wxRichTextBox"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("cell"), wxT("wxRichTextCell"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("table"), wxT("wxRichTextTable"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("field"), wxT("wxRichTextField"));
+
         return true;
     }
     void OnExit()
     {
         wxRichTextBuffer::CleanUpHandlers();
         wxRichTextBuffer::CleanUpDrawingHandlers();
         return true;
     }
     void OnExit()
     {
         wxRichTextBuffer::CleanUpHandlers();
         wxRichTextBuffer::CleanUpDrawingHandlers();
+        wxRichTextBuffer::CleanUpFieldTypes();
+        wxRichTextXMLHandler::ClearNodeToClassMap();
         wxRichTextDecimalToRoman(-1);
         wxRichTextParagraph::ClearDefaultTabs();
         wxRichTextCtrl::ClearAvailableFontNames();
         wxRichTextDecimalToRoman(-1);
         wxRichTextParagraph::ClearDefaultTabs();
         wxRichTextCtrl::ClearAvailableFontNames();
@@ -9500,8 +10933,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichTextModule, wxModule)
 void wxRichTextModuleInit()
 {
     wxModule* module = new wxRichTextModule;
 void wxRichTextModuleInit()
 {
     wxModule* module = new wxRichTextModule;
-    module->Init();
     wxModule::RegisterModule(module);
     wxModule::RegisterModule(module);
+    wxModule::InitializeModules();
 }
 
 
 }
 
 
@@ -9614,8 +11047,8 @@ void wxRichTextAction::CalculateRefreshOptimizations(wxArrayInt& optimizationLin
     // first, but of course this means we'll be doing it twice.
     if (!m_buffer->IsDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
     {
     // first, but of course this means we'll be doing it twice.
     if (!m_buffer->IsDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
     {
-        wxSize clientSize = m_ctrl->GetClientSize();
-        wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+        wxSize clientSize = m_ctrl->GetUnscaledSize(m_ctrl->GetClientSize());
+        wxPoint firstVisiblePt = m_ctrl->GetUnscaledPoint(m_ctrl->GetFirstVisiblePoint());
         int lastY = firstVisiblePt.y + clientSize.y;
 
         wxRichTextParagraph* para = container->GetParagraphAtPosition(GetRange().GetStart());
         int lastY = firstVisiblePt.y + clientSize.y;
 
         wxRichTextParagraph* para = container->GetParagraphAtPosition(GetRange().GetStart());
@@ -9702,7 +11135,7 @@ bool wxRichTextAction::Do()
             UpdateAppearance(newCaretPosition, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
 
             wxRichTextEvent cmdEvent(
             UpdateAppearance(newCaretPosition, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
 
             wxRichTextEvent cmdEvent(
-                wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
+                wxEVT_RICHTEXT_CONTENT_INSERTED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9735,7 +11168,7 @@ bool wxRichTextAction::Do()
             UpdateAppearance(caretPos, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
 
             wxRichTextEvent cmdEvent(
             UpdateAppearance(caretPos, true /* send update event */, & optimizationLineCharPositions, & optimizationLineYPositions, true /* do */);
 
             wxRichTextEvent cmdEvent(
-                wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
+                wxEVT_RICHTEXT_CONTENT_DELETED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9751,14 +11184,20 @@ bool wxRichTextAction::Do()
         {
             ApplyParagraphs(GetNewParagraphs());
 
         {
             ApplyParagraphs(GetNewParagraphs());
 
-            // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
-            // Layout() would stop prematurely at the top level.
-            container->InvalidateHierarchy(GetRange());
-
+            // Invalidate the whole buffer if there were floating objects
+            if (wxRichTextBuffer::GetFloatingLayoutMode() && container->GetFloatingObjectCount() > 0)
+                m_buffer->InvalidateHierarchy(wxRICHTEXT_ALL);
+            else
+            {
+                // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
+                // Layout() would stop prematurely at the top level.
+                container->InvalidateHierarchy(GetRange());
+            }
+
             UpdateAppearance(GetPosition());
 
             wxRichTextEvent cmdEvent(
             UpdateAppearance(GetPosition());
 
             wxRichTextEvent cmdEvent(
-                m_cmdId == wxRICHTEXT_CHANGE_STYLE ? wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED : wxEVT_COMMAND_RICHTEXT_PROPERTIES_CHANGED,
+                m_cmdId == wxRICHTEXT_CHANGE_STYLE ? wxEVT_RICHTEXT_STYLE_CHANGED : wxEVT_RICHTEXT_PROPERTIES_CHANGED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9781,12 +11220,16 @@ bool wxRichTextAction::Do()
 
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
 
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
-            container->InvalidateHierarchy(GetRange());
+            // Invalidate the whole buffer if there were floating objects
+            if (wxRichTextBuffer::GetFloatingLayoutMode() && container->GetFloatingObjectCount() > 0)
+                m_buffer->InvalidateHierarchy(wxRICHTEXT_ALL);
+            else
+                container->InvalidateHierarchy(GetRange());
 
             UpdateAppearance(GetPosition());
 
             wxRichTextEvent cmdEvent(
 
             UpdateAppearance(GetPosition());
 
             wxRichTextEvent cmdEvent(
-                wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED,
+                wxEVT_RICHTEXT_STYLE_CHANGED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9800,10 +11243,21 @@ bool wxRichTextAction::Do()
     case wxRICHTEXT_CHANGE_OBJECT:
         {
             wxRichTextObject* obj = m_objectAddress.GetObject(m_buffer);
     case wxRICHTEXT_CHANGE_OBJECT:
         {
             wxRichTextObject* obj = m_objectAddress.GetObject(m_buffer);
-            // wxRichTextObject* obj = container->GetChildAtPosition(GetRange().GetStart());
-            if (obj && m_object)
+            if (obj && m_object && m_ctrl)
             {
             {
-                wxRichTextObjectList::compatibility_iterator node = container->GetChildren().Find(obj);
+                // The plan is to swap the current object with the stored, previous-state, clone
+                // We can't get 'node' from the containing buffer (as it doesn't directly store objects)
+                // so use the parent paragraph
+                wxRichTextParagraph* para = wxDynamicCast(obj->GetParent(), wxRichTextParagraph);
+                wxCHECK_MSG(para, false, "Invalid parent paragraph");
+
+                // The stored object, m_object, may have a stale parent paragraph. This would cause
+                // a crash during layout, so use obj's parent para, which should be the correct one.
+                // (An alternative would be to return the parent too from m_objectAddress.GetObject(),
+                // or to set obj's parent there before returning)
+                m_object->SetParent(para);
+
+                wxRichTextObjectList::compatibility_iterator node = para->GetChildren().Find(obj);
                 if (node)
                 {
                     wxRichTextObject* obj = node->GetData();
                 if (node)
                 {
                     wxRichTextObject* obj = node->GetData();
@@ -9812,11 +11266,21 @@ bool wxRichTextAction::Do()
                 }
             }
 
                 }
             }
 
+            // We can't rely on the current focus-object remaining valid, if it's e.g. a table's cell.
+            // And we can't cope with this in the calling code: a user may later click in the cell
+            // before deciding to Undo() or Redo(). So play safe and set focus to the buffer.
+            if (m_ctrl)
+                m_ctrl->SetFocusObject(m_buffer, false);
+            
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
-            container->InvalidateHierarchy(GetRange());
+            // Invalidate the whole buffer if there were floating objects
+            if (wxRichTextBuffer::GetFloatingLayoutMode() && container->GetFloatingObjectCount() > 0)
+                m_buffer->InvalidateHierarchy(wxRICHTEXT_ALL);
+            else
+                container->InvalidateHierarchy(GetRange());
 
 
-            UpdateAppearance(GetPosition());
+            UpdateAppearance(GetPosition(), true);
 
             // TODO: send new kind of modification event
 
 
             // TODO: send new kind of modification event
 
@@ -9851,6 +11315,7 @@ bool wxRichTextAction::Undo()
 
             container->DeleteRange(GetRange());
             container->UpdateRanges();
 
             container->DeleteRange(GetRange());
             container->UpdateRanges();
+
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
@@ -9860,7 +11325,7 @@ bool wxRichTextAction::Undo()
             UpdateAppearance(newCaretPosition, true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
 
             wxRichTextEvent cmdEvent(
             UpdateAppearance(newCaretPosition, true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
 
             wxRichTextEvent cmdEvent(
-                wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
+                wxEVT_RICHTEXT_CONTENT_DELETED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9882,6 +11347,7 @@ bool wxRichTextAction::Undo()
 
             container->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
             container->UpdateRanges();
 
             container->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
             container->UpdateRanges();
+
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(GetRange());
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(GetRange());
@@ -9889,7 +11355,7 @@ bool wxRichTextAction::Undo()
             UpdateAppearance(GetPosition(), true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
 
             wxRichTextEvent cmdEvent(
             UpdateAppearance(GetPosition(), true, /* send update event */ & optimizationLineCharPositions, & optimizationLineYPositions, false /* undo */);
 
             wxRichTextEvent cmdEvent(
-                wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED,
+                wxEVT_RICHTEXT_CONTENT_INSERTED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9911,7 +11377,7 @@ bool wxRichTextAction::Undo()
             UpdateAppearance(GetPosition());
 
             wxRichTextEvent cmdEvent(
             UpdateAppearance(GetPosition());
 
             wxRichTextEvent cmdEvent(
-                m_cmdId == wxRICHTEXT_CHANGE_STYLE ? wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED : wxEVT_COMMAND_RICHTEXT_PROPERTIES_CHANGED,
+                m_cmdId == wxRICHTEXT_CHANGE_STYLE ? wxEVT_RICHTEXT_STYLE_CHANGED : wxEVT_RICHTEXT_PROPERTIES_CHANGED,
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
                 m_ctrl ? m_ctrl->GetId() : -1);
             cmdEvent.SetEventObject(m_ctrl ? (wxObject*) m_ctrl : (wxObject*) m_buffer);
             cmdEvent.SetRange(GetRange());
@@ -9955,7 +11421,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
 
             // Refresh everything if there were floating objects or the container changed size
             // (we can't yet optimize in these cases, since more complex interaction with other content occurs)
 
             // Refresh everything if there were floating objects or the container changed size
             // (we can't yet optimize in these cases, since more complex interaction with other content occurs)
-            if (container->GetFloatingObjectCount() > 0 || (container->GetParent() && containerRect != container->GetRect()))
+            if ((wxRichTextBuffer::GetFloatingLayoutMode() && container->GetFloatingObjectCount() > 0) || (container->GetParent() && containerRect != container->GetRect()))
             {
                 m_ctrl->Refresh(false);
             }
             {
                 m_ctrl->Refresh(false);
             }
@@ -9967,8 +11433,8 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
             {
                 size_t i;
 
             {
                 size_t i;
 
-                wxSize clientSize = m_ctrl->GetClientSize();
-                wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+                wxSize clientSize = m_ctrl->GetUnscaledSize(m_ctrl->GetClientSize());
+                wxPoint firstVisiblePt = m_ctrl->GetUnscaledPoint(m_ctrl->GetFirstVisiblePoint());
 
                 // Start/end positions
                 int firstY = 0;
 
                 // Start/end positions
                 int firstY = 0;
@@ -9986,13 +11452,16 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                 // 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.
                 // 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.
+                long pos = GetRange().GetStart();
 
 
-                wxRichTextParagraph* para = container->GetParagraphAtPosition(GetPosition());
+                wxRichTextParagraph* para = container->GetParagraphAtPosition(pos, false /* is not caret pos */);
                 // Since we support floating layout, we should redraw the whole para instead of just
                 // the first line touching the invalid range.
                 if (para)
                 {
                 // Since we support floating layout, we should redraw the whole para instead of just
                 // the first line touching the invalid range.
                 if (para)
                 {
-                    firstY = para->GetPosition().y;
+                    // In case something was drawn above the paragraph,
+                    // such as a line break, allow a little extra.
+                    firstY = para->GetPosition().y - 4;
                 }
 
                 wxRichTextObjectList::compatibility_iterator node = container->GetChildren().Find(para);
                 }
 
                 wxRichTextObjectList::compatibility_iterator node = container->GetChildren().Find(para);
@@ -10040,7 +11509,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                                     // Stop, we're now the same as we were
                                     foundEnd = true;
 
                                     // Stop, we're now the same as we were
                                     foundEnd = true;
 
-                                    lastY = pt.y;
+                                    lastY = pt.y + line->GetSize().y;
 
                                     node2 = wxRichTextLineList::compatibility_iterator();
                                     node = wxRichTextObjectList::compatibility_iterator();
 
                                     node2 = wxRichTextLineList::compatibility_iterator();
                                     node = wxRichTextObjectList::compatibility_iterator();
@@ -10063,7 +11532,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                     lastY = firstVisiblePt.y + clientSize.y;
 
                 // Convert to device coordinates
                     lastY = firstVisiblePt.y + clientSize.y;
 
                 // Convert to device coordinates
-                wxRect rect(m_ctrl->GetPhysicalPoint(wxPoint(firstVisiblePt.x, firstY)), wxSize(clientSize.x, lastY - firstY));
+                wxRect rect(m_ctrl->GetPhysicalPoint(m_ctrl->GetScaledPoint(wxPoint(firstVisiblePt.x, firstY))), m_ctrl->GetScaledSize(wxSize(clientSize.x, lastY - firstY)));
                 m_ctrl->RefreshRect(rect);
             }
             else
                 m_ctrl->RefreshRect(rect);
             }
             else
@@ -10165,13 +11634,17 @@ wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichT
         SetAttributes(*charStyle);
 }
 
         SetAttributes(*charStyle);
 }
 
+wxRichTextImage::~wxRichTextImage()
+{
+}
+
 void wxRichTextImage::Init()
 {
     m_originalImageSize = wxSize(-1, -1);
 }
 
 /// Create a cached image at the required size
 void wxRichTextImage::Init()
 {
     m_originalImageSize = wxSize(-1, -1);
 }
 
 /// Create a cached image at the required size
-bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
+bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache, const wxSize& parentSize)
 {
     if (!m_imageBlock.IsOk())
         return false;
 {
     if (!m_imageBlock.IsOk())
         return false;
@@ -10181,7 +11654,7 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
     // the image so long as the new cached bitmap size hasn't changed.
 
     wxImage image;
     // the image so long as the new cached bitmap size hasn't changed.
 
     wxImage image;
-    if (resetCache || m_originalImageSize == wxSize(-1, -1))
+    if (resetCache || m_originalImageSize.GetWidth() <= 0 || m_originalImageSize.GetHeight() <= 0)
     {
         m_imageCache = wxNullBitmap;
 
     {
         m_imageCache = wxNullBitmap;
 
@@ -10201,29 +11674,36 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
     int maxWidth = -1;
     int maxHeight = -1;
 
     int maxWidth = -1;
     int maxHeight = -1;
 
-    wxRichTextBuffer* buffer = GetBuffer();
-    if (buffer)
+    wxSize sz = parentSize;
+    if (sz == wxDefaultSize)
     {
     {
-        wxSize sz;
-        if (buffer->GetRichTextCtrl())
-        {
-            // Subtract borders
-            sz = buffer->GetRichTextCtrl()->GetClientSize();
+        if (GetParent() && GetParent()->GetParent())
+            sz = GetParent()->GetParent()->GetCachedSize();
+    }
 
 
+    if (sz != wxDefaultSize)
+    {
+        wxRichTextBuffer* buffer = GetBuffer();
+        if (buffer)
+        {
+            // Find the actual space available when margin is taken into account
             wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
             marginRect = wxRect(0, 0, sz.x, sz.y);
             wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
             marginRect = wxRect(0, 0, sz.x, sz.y);
-            buffer->GetBoxRects(dc, buffer, buffer->GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+            if (GetParent() && GetParent()->GetParent())
+            {
+                buffer->GetBoxRects(dc, buffer, GetParent()->GetParent()->GetAttributes(), marginRect, borderRect, contentRect, paddingRect, outlineRect);
+                sz = contentRect.GetSize();
+            }
 
 
-            sz = contentRect.GetSize();
+            // Use a minimum size to stop images becoming very small
+            parentWidth = wxMax(100, sz.GetWidth());
+            parentHeight = wxMax(100, sz.GetHeight());
 
 
-            // Start with a maximum width of the control size, even if not specified by the content,
-            // to minimize the amount of picture overlapping the right-hand side
-            maxWidth = sz.x;
+            if (buffer->GetRichTextCtrl())
+                // Start with a maximum width of the control size, even if not specified by the content,
+                // to minimize the amount of picture overlapping the right-hand side
+                maxWidth = parentWidth;
         }
         }
-        else
-            sz = buffer->GetCachedSize();
-        parentWidth = sz.GetWidth();
-        parentHeight = sz.GetHeight();
     }
 
     if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0)
     }
 
     if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0)
@@ -10297,6 +11777,10 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
             width = (int) (float(m_originalImageSize.GetWidth()) * (float(height)/float(m_originalImageSize.GetHeight())));
     }
 
             width = (int) (float(m_originalImageSize.GetWidth()) * (float(height)/float(m_originalImageSize.GetHeight())));
     }
 
+    // Prevent the use of zero size
+    width = wxMax(1, width);
+    height = wxMax(1, height);
+
     if (m_imageCache.IsOk() && m_imageCache.GetWidth() == width && m_imageCache.GetHeight() == height)
     {
         // Do nothing, we didn't need to change the image cache
     if (m_imageCache.IsOk() && m_imageCache.GetWidth() == width && m_imageCache.GetHeight() == height)
     {
         // Do nothing, we didn't need to change the image cache
@@ -10334,7 +11818,7 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
 }
 
 /// Draw the item
 }
 
 /// Draw the item
-bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int WXUNUSED(descent), int WXUNUSED(style))
+bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int WXUNUSED(descent), int WXUNUSED(style))
 {
     if (!IsShown())
         return true;
 {
     if (!IsShown())
         return true;
@@ -10349,12 +11833,6 @@ bool wxRichTextImage::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wx
 
     DrawBoxAttributes(dc, GetBuffer(), attr, wxRect(rect.GetPosition(), GetCachedSize()));
 
 
     DrawBoxAttributes(dc, GetBuffer(), attr, wxRect(rect.GetPosition(), GetCachedSize()));
 
-#if 0
-    int y = rect.y + (rect.height - m_imageCache.GetHeight());
-
-    dc.DrawBitmap(m_imageCache, rect.x, y, true);
-#endif
-
     wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
     wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
     marginRect = rect; // outer rectangle, will calculate contentRect
     wxSize imageSize(m_imageCache.GetWidth(), m_imageCache.GetHeight());
     wxRect marginRect, borderRect, contentRect, paddingRect, outlineRect;
     marginRect = rect; // outer rectangle, will calculate contentRect
@@ -10401,12 +11879,12 @@ bool wxRichTextImage::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
 
 /// 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& dc, wxRichTextDrawingContext& context, int WXUNUSED(flags), wxPoint WXUNUSED(position), wxArrayInt* partialExtents) const
+bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& dc, wxRichTextDrawingContext& context, int WXUNUSED(flags), const wxPoint& WXUNUSED(position), const wxSize& parentSize, wxArrayInt* partialExtents) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
 
 {
     if (!range.IsWithin(GetRange()))
         return false;
 
-    if (!((wxRichTextImage*)this)->LoadImageCache(dc))
+    if (!((wxRichTextImage*)this)->LoadImageCache(dc, false, parentSize))
     {
         size.x = 0; size.y = 0;
         if (partialExtents)
     {
         size.x = 0; size.y = 0;
         if (partialExtents)
@@ -10483,12 +11961,6 @@ bool wxTextAttrEq(const wxRichTextAttr& attr1, const wxRichTextAttr& attr2)
     return (attr1 == attr2);
 }
 
     return (attr1 == attr2);
 }
 
-// Partial equality test taking flags into account
-bool wxTextAttrEqPartial(const wxRichTextAttr& attr1, const wxRichTextAttr& attr2)
-{
-    return attr1.EqPartial(attr2);
-}
-
 /// Compare tabs
 bool wxRichTextTabsEq(const wxArrayInt& tabs1, const wxArrayInt& tabs2)
 {
 /// Compare tabs
 bool wxRichTextTabsEq(const wxArrayInt& tabs1, const wxArrayInt& tabs2)
 {
@@ -10980,7 +12452,7 @@ wxString wxRichTextImageBlock::GetExtension() const
  * The data object for a wxRichTextBuffer
  */
 
  * The data object for a wxRichTextBuffer
  */
 
-const wxChar *wxRichTextBufferDataObject::ms_richTextBufferFormatId = wxT("wxShape");
+const wxChar *wxRichTextBufferDataObject::ms_richTextBufferFormatId = wxT("wxRichText");
 
 wxRichTextBufferDataObject::wxRichTextBufferDataObject(wxRichTextBuffer* richTextBuffer)
 {
 
 wxRichTextBufferDataObject::wxRichTextBufferDataObject(wxRichTextBuffer* richTextBuffer)
 {
@@ -11103,22 +12575,48 @@ class wxRichTextFontTableData: public wxObjectRefData
 public:
     wxRichTextFontTableData() {}
 
 public:
     wxRichTextFontTableData() {}
 
-    wxFont FindFont(const wxRichTextAttr& fontSpec);
+    wxFont FindFont(const wxRichTextAttr& fontSpec, double fontScale);
 
     wxRichTextFontTableHashMap  m_hashMap;
 };
 
 
     wxRichTextFontTableHashMap  m_hashMap;
 };
 
-wxFont wxRichTextFontTableData::FindFont(const wxRichTextAttr& fontSpec)
+wxFont wxRichTextFontTableData::FindFont(const wxRichTextAttr& fontSpec, double fontScale)
 {
     wxString facename(fontSpec.GetFontFaceName());
 {
     wxString facename(fontSpec.GetFontFaceName());
-    wxString spec(wxString::Format(wxT("%d-%d-%d-%d-%s-%d"), fontSpec.GetFontSize(), fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), (int) fontSpec.GetFontUnderlined(), facename.c_str(), (int) fontSpec.GetFontEncoding()));
-    wxRichTextFontTableHashMap::iterator entry = m_hashMap.find(spec);
 
 
+    int fontSize = fontSpec.GetFontSize();
+    if (fontScale != 1.0)
+        fontSize = (int) ((double(fontSize) * fontScale) + 0.5);
+
+    wxString units;
+    if (fontSpec.HasFontPixelSize() && !fontSpec.HasFontPointSize())
+        units = wxT("px");
+    else
+        units = wxT("pt");
+    wxString spec = wxString::Format(wxT("%d-%s-%d-%d-%d-%d-%s-%d"),
+        fontSize, units.c_str(), fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), (int) fontSpec.GetFontUnderlined(), (int) fontSpec.GetFontStrikethrough(),
+        facename.c_str(), (int) fontSpec.GetFontEncoding());
+
+    wxRichTextFontTableHashMap::iterator entry = m_hashMap.find(spec);
     if ( entry == m_hashMap.end() )
     {
     if ( entry == m_hashMap.end() )
     {
-        wxFont font(fontSpec.GetFontSize(), wxDEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename.c_str());
-        m_hashMap[spec] = font;
-        return font;
+        if (fontSpec.HasFontPixelSize() && !fontSpec.HasFontPointSize())
+        {
+            wxFont font(wxSize(0, fontSize), wxFONTFAMILY_DEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename);
+            if (fontSpec.HasFontStrikethrough() && fontSpec.GetFontStrikethrough())
+                font.SetStrikethrough(true);
+            m_hashMap[spec] = font;
+            return font;
+        }
+        else
+        {
+            wxFont font(fontSize, wxFONTFAMILY_DEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename.c_str());
+            if (fontSpec.HasFontStrikethrough() && fontSpec.GetFontStrikethrough())
+                font.SetStrikethrough(true);
+
+            m_hashMap[spec] = font;
+            return font;
+        }
     }
     else
     {
     }
     else
     {
@@ -11131,6 +12629,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichTextFontTable, wxObject)
 wxRichTextFontTable::wxRichTextFontTable()
 {
     m_refData = new wxRichTextFontTableData;
 wxRichTextFontTable::wxRichTextFontTable()
 {
     m_refData = new wxRichTextFontTableData;
+    m_fontScale = 1.0;
 }
 
 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
 }
 
 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
@@ -11152,13 +12651,14 @@ bool wxRichTextFontTable::operator == (const wxRichTextFontTable& table) const
 void wxRichTextFontTable::operator= (const wxRichTextFontTable& table)
 {
     Ref(table);
 void wxRichTextFontTable::operator= (const wxRichTextFontTable& table)
 {
     Ref(table);
+    m_fontScale = table.m_fontScale;
 }
 
 wxFont wxRichTextFontTable::FindFont(const wxRichTextAttr& fontSpec)
 {
     wxRichTextFontTableData* data = (wxRichTextFontTableData*) m_refData;
     if (data)
 }
 
 wxFont wxRichTextFontTable::FindFont(const wxRichTextAttr& fontSpec)
 {
     wxRichTextFontTableData* data = (wxRichTextFontTableData*) m_refData;
     if (data)
-        return data->FindFont(fontSpec);
+        return data->FindFont(fontSpec, m_fontScale);
     else
         return wxFont();
 }
     else
         return wxFont();
 }
@@ -11170,8 +12670,14 @@ void wxRichTextFontTable::Clear()
         data->m_hashMap.clear();
 }
 
         data->m_hashMap.clear();
 }
 
-// wxTextBoxAttr
+void wxRichTextFontTable::SetFontScale(double fontScale)
+{
+    if (fontScale != m_fontScale)
+        Clear();
+    m_fontScale = fontScale;
+}
 
 
+// wxTextBoxAttr
 
 void wxTextBoxAttr::Reset()
 {
 
 void wxTextBoxAttr::Reset()
 {
@@ -11220,8 +12726,17 @@ bool wxTextBoxAttr::operator== (const wxTextBoxAttr& attr) const
 }
 
 // Partial equality test
 }
 
 // Partial equality test
-bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr) const
+bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr, bool weakTest) const
 {
 {
+    if (!weakTest &&
+            ((!HasFloatMode() && attr.HasFloatMode()) ||
+             (!HasClearMode() && attr.HasClearMode()) ||
+             (!HasCollapseBorders() && attr.HasCollapseBorders()) ||
+             (!HasVerticalAlignment() && attr.HasVerticalAlignment()) ||
+             (!HasBoxStyleName() && attr.HasBoxStyleName())))
+    {
+        return false;
+    }
     if (attr.HasFloatMode() && HasFloatMode() && (GetFloatMode() != attr.GetFloatMode()))
         return false;
 
     if (attr.HasFloatMode() && HasFloatMode() && (GetFloatMode() != attr.GetFloatMode()))
         return false;
 
@@ -11239,36 +12754,36 @@ bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr) const
 
     // Position
 
 
     // Position
 
-    if (!m_position.EqPartial(attr.m_position))
+    if (!m_position.EqPartial(attr.m_position, weakTest))
         return false;
 
     // Size
 
         return false;
 
     // Size
 
-    if (!m_size.EqPartial(attr.m_size))
+    if (!m_size.EqPartial(attr.m_size, weakTest))
         return false;
         return false;
-    if (!m_minSize.EqPartial(attr.m_minSize))
+    if (!m_minSize.EqPartial(attr.m_minSize, weakTest))
         return false;
         return false;
-    if (!m_maxSize.EqPartial(attr.m_maxSize))
+    if (!m_maxSize.EqPartial(attr.m_maxSize, weakTest))
         return false;
 
     // Margins
 
         return false;
 
     // Margins
 
-    if (!m_margins.EqPartial(attr.m_margins))
+    if (!m_margins.EqPartial(attr.m_margins, weakTest))
         return false;
 
     // Padding
 
         return false;
 
     // Padding
 
-    if (!m_padding.EqPartial(attr.m_padding))
+    if (!m_padding.EqPartial(attr.m_padding, weakTest))
         return false;
 
     // Border
 
         return false;
 
     // Border
 
-    if (!GetBorder().EqPartial(attr.GetBorder()))
+    if (!GetBorder().EqPartial(attr.GetBorder(), weakTest))
         return false;
 
     // Outline
 
         return false;
 
     // Outline
 
-    if (!GetOutline().EqPartial(attr.GetOutline()))
+    if (!GetOutline().EqPartial(attr.GetOutline(), weakTest))
         return false;
 
     return true;
         return false;
 
     return true;
@@ -11493,13 +13008,13 @@ bool wxRichTextAttr::operator==(const wxRichTextAttr& attr) const
     return (m_textBoxAttr == attr.m_textBoxAttr);
 }
 
     return (m_textBoxAttr == attr.m_textBoxAttr);
 }
 
-// Partial equality test taking comparison object into account
-bool wxRichTextAttr::EqPartial(const wxRichTextAttr& attr) const
+// Partial equality test
+bool wxRichTextAttr::EqPartial(const wxRichTextAttr& attr, bool weakTest) const
 {
 {
-    if (!(wxTextAttr::EqPartial(attr)))
+    if (!(wxTextAttr::EqPartial(attr, weakTest)))
         return false;
 
         return false;
 
-    return m_textBoxAttr.EqPartial(attr.m_textBoxAttr);
+    return m_textBoxAttr.EqPartial(attr.m_textBoxAttr, weakTest);
 }
 
 // Merges the given attributes. If compareWith
 }
 
 // Merges the given attributes. If compareWith
@@ -11530,15 +13045,23 @@ void wxRichTextAttr::CollectCommonAttributes(const wxRichTextAttr& attr, wxRichT
 }
 
 // Partial equality test
 }
 
 // Partial equality test
-bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border) const
+bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border, bool weakTest) const
 {
 {
-    if (border.HasStyle() && !HasStyle() && (border.GetStyle() != GetStyle()))
+    if (!weakTest &&
+        ((!HasStyle() && border.HasStyle()) ||
+         (!HasColour() && border.HasColour()) ||
+         (!HasWidth() && border.HasWidth())))
+    {
+        return false;
+    }
+
+    if (border.HasStyle() && HasStyle() && (border.GetStyle() != GetStyle()))
         return false;
 
         return false;
 
-    if (border.HasColour() && !HasColour() && (border.GetColourLong() != GetColourLong()))
+    if (border.HasColour() && HasColour() && (border.GetColourLong() != GetColourLong()))
         return false;
 
         return false;
 
-    if (border.HasWidth() && !HasWidth() && !(border.GetWidth() == GetWidth()))
+    if (border.HasWidth() && HasWidth() && !(border.GetWidth() == GetWidth()))
         return false;
 
     return true;
         return false;
 
     return true;
@@ -11625,10 +13148,10 @@ void wxTextAttrBorder::CollectCommonAttributes(const wxTextAttrBorder& attr, wxT
 }
 
 // Partial equality test
 }
 
 // Partial equality test
-bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders) const
+bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders, bool weakTest) const
 {
 {
-    return m_left.EqPartial(borders.m_left) && m_right.EqPartial(borders.m_right) &&
-            m_top.EqPartial(borders.m_top) && m_bottom.EqPartial(borders.m_bottom);
+    return m_left.EqPartial(borders.m_left, weakTest) && m_right.EqPartial(borders.m_right, weakTest) &&
+            m_top.EqPartial(borders.m_top, weakTest) && m_bottom.EqPartial(borders.m_bottom, weakTest);
 }
 
 // Apply border to 'this', but not if the same as compareWith
 }
 
 // Apply border to 'this', but not if the same as compareWith
@@ -11697,8 +13220,11 @@ void wxTextAttrBorders::SetWidth(const wxTextAttrDimension& width)
 }
 
 // Partial equality test
 }
 
 // Partial equality test
-bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension& dim) const
+bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension& dim, bool weakTest) const
 {
 {
+    if (!weakTest && !IsValid() && dim.IsValid())
+        return false;
+
     if (dim.IsValid() && IsValid() && !((*this) == dim))
         return false;
     else
     if (dim.IsValid() && IsValid() && !((*this) == dim))
         return false;
     else
@@ -11795,18 +13321,18 @@ int wxTextAttrDimensionConverter::GetTenthsMM(const wxTextAttrDimension& dim) co
 }
 
 // Partial equality test
 }
 
 // Partial equality test
-bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims) const
+bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims, bool weakTest) const
 {
 {
-    if (!m_left.EqPartial(dims.m_left))
+    if (!m_left.EqPartial(dims.m_left, weakTest))
         return false;
 
         return false;
 
-    if (!m_right.EqPartial(dims.m_right))
+    if (!m_right.EqPartial(dims.m_right, weakTest))
         return false;
 
         return false;
 
-    if (!m_top.EqPartial(dims.m_top))
+    if (!m_top.EqPartial(dims.m_top, weakTest))
         return false;
 
         return false;
 
-    if (!m_bottom.EqPartial(dims.m_bottom))
+    if (!m_bottom.EqPartial(dims.m_bottom, weakTest))
         return false;
 
     return true;
         return false;
 
     return true;
@@ -11849,12 +13375,12 @@ void wxTextAttrDimensions::CollectCommonAttributes(const wxTextAttrDimensions& a
 }
 
 // Partial equality test
 }
 
 // Partial equality test
-bool wxTextAttrSize::EqPartial(const wxTextAttrSize& size) const
+bool wxTextAttrSize::EqPartial(const wxTextAttrSize& size, bool weakTest) const
 {
 {
-    if (!m_width.EqPartial(size.m_width))
+    if (!m_width.EqPartial(size.m_width, weakTest))
         return false;
 
         return false;
 
-    if (!m_height.EqPartial(size.m_height))
+    if (!m_height.EqPartial(size.m_height, weakTest))
         return false;
 
     return true;
         return false;
 
     return true;
@@ -11897,100 +13423,177 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
 
     long forbiddenFlags = clashingAttr.GetFlags()|absentAttr.GetFlags();
 
 
     long forbiddenFlags = clashingAttr.GetFlags()|absentAttr.GetFlags();
 
-    if (attr.HasFont())
+    // If different font size units are being used, this is a clash.
+    if (((attr.GetFlags() & wxTEXT_ATTR_FONT_SIZE) | (currentStyle.GetFlags() & wxTEXT_ATTR_FONT_SIZE)) == wxTEXT_ATTR_FONT_SIZE)
     {
     {
-        if (attr.HasFontSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_SIZE))
+        currentStyle.SetFontSize(0);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_SIZE);
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_SIZE);
+    }
+    else
+    {
+        if (attr.HasFontPointSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_POINT_SIZE))
         {
         {
-            if (currentStyle.HasFontSize())
+            if (currentStyle.HasFontPointSize())
             {
                 if (currentStyle.GetFontSize() != attr.GetFontSize())
                 {
                     // Clash of attr - mark as such
             {
                 if (currentStyle.GetFontSize() != attr.GetFontSize())
                 {
                     // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_SIZE);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_SIZE);
+                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
                 }
             }
             else
                 currentStyle.SetFontSize(attr.GetFontSize());
         }
                 }
             }
             else
                 currentStyle.SetFontSize(attr.GetFontSize());
         }
+        else if (!attr.HasFontPointSize() && currentStyle.HasFontPointSize())
+        {
+            clashingAttr.AddFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+            currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+        }
 
 
-        if (attr.HasFontItalic() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_ITALIC))
+        if (attr.HasFontPixelSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_PIXEL_SIZE))
         {
         {
-            if (currentStyle.HasFontItalic())
+            if (currentStyle.HasFontPixelSize())
             {
             {
-                if (currentStyle.GetFontStyle() != attr.GetFontStyle())
+                if (currentStyle.GetFontSize() != attr.GetFontSize())
                 {
                     // Clash of attr - mark as such
                 {
                     // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_ITALIC);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_ITALIC);
+                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
+                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
                 }
             }
             else
                 }
             }
             else
-                currentStyle.SetFontStyle(attr.GetFontStyle());
+                currentStyle.SetFontPixelSize(attr.GetFontSize());
+        }
+        else if (!attr.HasFontPixelSize() && currentStyle.HasFontPixelSize())
+        {
+            clashingAttr.AddFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
+            currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
         }
         }
+    }
 
 
-        if (attr.HasFontFamily() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_FAMILY))
+    if (attr.HasFontItalic() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_ITALIC))
+    {
+        if (currentStyle.HasFontItalic())
         {
         {
-            if (currentStyle.HasFontFamily())
+            if (currentStyle.GetFontStyle() != attr.GetFontStyle())
             {
             {
-                if (currentStyle.GetFontFamily() != attr.GetFontFamily())
-                {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FAMILY);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FAMILY);
-                }
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_ITALIC);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_ITALIC);
+            }
+        }
+        else
+            currentStyle.SetFontStyle(attr.GetFontStyle());
+    }
+    else if (!attr.HasFontItalic() && currentStyle.HasFontItalic())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_ITALIC);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_ITALIC);
+    }
+
+    if (attr.HasFontFamily() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_FAMILY))
+    {
+        if (currentStyle.HasFontFamily())
+        {
+            if (currentStyle.GetFontFamily() != attr.GetFontFamily())
+            {
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FAMILY);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FAMILY);
             }
             }
-            else
-                currentStyle.SetFontFamily(attr.GetFontFamily());
         }
         }
+        else
+            currentStyle.SetFontFamily(attr.GetFontFamily());
+    }
+    else if (!attr.HasFontFamily() && currentStyle.HasFontFamily())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FAMILY);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FAMILY);
+    }
 
 
-        if (attr.HasFontWeight() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_WEIGHT))
+    if (attr.HasFontWeight() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_WEIGHT))
+    {
+        if (currentStyle.HasFontWeight())
         {
         {
-            if (currentStyle.HasFontWeight())
+            if (currentStyle.GetFontWeight() != attr.GetFontWeight())
             {
             {
-                if (currentStyle.GetFontWeight() != attr.GetFontWeight())
-                {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_WEIGHT);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_WEIGHT);
-                }
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_WEIGHT);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_WEIGHT);
             }
             }
-            else
-                currentStyle.SetFontWeight(attr.GetFontWeight());
         }
         }
+        else
+            currentStyle.SetFontWeight(attr.GetFontWeight());
+    }
+    else if (!attr.HasFontWeight() && currentStyle.HasFontWeight())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_WEIGHT);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_WEIGHT);
+    }
 
 
-        if (attr.HasFontFaceName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_FACE))
+    if (attr.HasFontFaceName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_FACE))
+    {
+        if (currentStyle.HasFontFaceName())
         {
         {
-            if (currentStyle.HasFontFaceName())
+            wxString faceName1(currentStyle.GetFontFaceName());
+            wxString faceName2(attr.GetFontFaceName());
+
+            if (faceName1 != faceName2)
             {
             {
-                wxString faceName1(currentStyle.GetFontFaceName());
-                wxString faceName2(attr.GetFontFaceName());
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FACE);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FACE);
+            }
+        }
+        else
+            currentStyle.SetFontFaceName(attr.GetFontFaceName());
+    }
+    else if (!attr.HasFontFaceName() && currentStyle.HasFontFaceName())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FACE);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FACE);
+    }
 
 
-                if (faceName1 != faceName2)
-                {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FACE);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FACE);
-                }
+    if (attr.HasFontUnderlined() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_UNDERLINE))
+    {
+        if (currentStyle.HasFontUnderlined())
+        {
+            if (currentStyle.GetFontUnderlined() != attr.GetFontUnderlined())
+            {
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_UNDERLINE);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_UNDERLINE);
             }
             }
-            else
-                currentStyle.SetFontFaceName(attr.GetFontFaceName());
         }
         }
+        else
+            currentStyle.SetFontUnderlined(attr.GetFontUnderlined());
+    }
+    else if (!attr.HasFontUnderlined() && currentStyle.HasFontUnderlined())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_UNDERLINE);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_UNDERLINE);
+    }
 
 
-        if (attr.HasFontUnderlined() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_UNDERLINE))
+    if (attr.HasFontStrikethrough() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_STRIKETHROUGH))
+    {
+        if (currentStyle.HasFontStrikethrough())
         {
         {
-            if (currentStyle.HasFontUnderlined())
+            if (currentStyle.GetFontStrikethrough() != attr.GetFontStrikethrough())
             {
             {
-                if (currentStyle.GetFontUnderlined() != attr.GetFontUnderlined())
-                {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_UNDERLINE);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_UNDERLINE);
-                }
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
             }
             }
-            else
-                currentStyle.SetFontUnderlined(attr.GetFontUnderlined());
         }
         }
+        else
+            currentStyle.SetFontStrikethrough(attr.GetFontStrikethrough());
+    }
+    else if (!attr.HasFontStrikethrough() && currentStyle.HasFontStrikethrough())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
     }
 
     if (attr.HasTextColour() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_TEXT_COLOUR))
     }
 
     if (attr.HasTextColour() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_TEXT_COLOUR))
@@ -12007,6 +13610,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetTextColour(attr.GetTextColour());
     }
         else
             currentStyle.SetTextColour(attr.GetTextColour());
     }
+    else if (!attr.HasTextColour() && currentStyle.HasTextColour())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_TEXT_COLOUR);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_TEXT_COLOUR);
+    }
 
     if (attr.HasBackgroundColour() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BACKGROUND_COLOUR))
     {
 
     if (attr.HasBackgroundColour() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BACKGROUND_COLOUR))
     {
@@ -12022,6 +13630,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetBackgroundColour(attr.GetBackgroundColour());
     }
         else
             currentStyle.SetBackgroundColour(attr.GetBackgroundColour());
     }
+    else if (!attr.HasBackgroundColour() && currentStyle.HasBackgroundColour())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_BACKGROUND_COLOUR);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_BACKGROUND_COLOUR);
+    }
 
     if (attr.HasAlignment() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_ALIGNMENT))
     {
 
     if (attr.HasAlignment() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_ALIGNMENT))
     {
@@ -12037,6 +13650,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetAlignment(attr.GetAlignment());
     }
         else
             currentStyle.SetAlignment(attr.GetAlignment());
     }
+    else if (!attr.HasAlignment() && currentStyle.HasAlignment())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_ALIGNMENT);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_ALIGNMENT);
+    }
 
     if (attr.HasTabs() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_TABS))
     {
 
     if (attr.HasTabs() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_TABS))
     {
@@ -12052,6 +13670,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetTabs(attr.GetTabs());
     }
         else
             currentStyle.SetTabs(attr.GetTabs());
     }
+    else if (!attr.HasTabs() && currentStyle.HasTabs())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_TABS);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_TABS);
+    }
 
     if (attr.HasLeftIndent() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_LEFT_INDENT))
     {
 
     if (attr.HasLeftIndent() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_LEFT_INDENT))
     {
@@ -12067,6 +13690,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent());
     }
         else
             currentStyle.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent());
     }
+    else if (!attr.HasLeftIndent() && currentStyle.HasLeftIndent())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_LEFT_INDENT);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_LEFT_INDENT);
+    }
 
     if (attr.HasRightIndent() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_RIGHT_INDENT))
     {
 
     if (attr.HasRightIndent() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_RIGHT_INDENT))
     {
@@ -12082,6 +13710,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetRightIndent(attr.GetRightIndent());
     }
         else
             currentStyle.SetRightIndent(attr.GetRightIndent());
     }
+    else if (!attr.HasRightIndent() && currentStyle.HasRightIndent())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_RIGHT_INDENT);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_RIGHT_INDENT);
+    }
 
     if (attr.HasParagraphSpacingAfter() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_PARA_SPACING_AFTER))
     {
 
     if (attr.HasParagraphSpacingAfter() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_PARA_SPACING_AFTER))
     {
@@ -12097,6 +13730,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter());
     }
         else
             currentStyle.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter());
     }
+    else if (!attr.HasParagraphSpacingAfter() && currentStyle.HasParagraphSpacingAfter())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_PARA_SPACING_AFTER);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_PARA_SPACING_AFTER);
+    }
 
     if (attr.HasParagraphSpacingBefore() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_PARA_SPACING_BEFORE))
     {
 
     if (attr.HasParagraphSpacingBefore() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_PARA_SPACING_BEFORE))
     {
@@ -12112,6 +13750,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetParagraphSpacingBefore(attr.GetParagraphSpacingBefore());
     }
         else
             currentStyle.SetParagraphSpacingBefore(attr.GetParagraphSpacingBefore());
     }
+    else if (!attr.HasParagraphSpacingBefore() && currentStyle.HasParagraphSpacingBefore())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_PARA_SPACING_BEFORE);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_PARA_SPACING_BEFORE);
+    }
 
     if (attr.HasLineSpacing() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_LINE_SPACING))
     {
 
     if (attr.HasLineSpacing() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_LINE_SPACING))
     {
@@ -12127,6 +13770,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetLineSpacing(attr.GetLineSpacing());
     }
         else
             currentStyle.SetLineSpacing(attr.GetLineSpacing());
     }
+    else if (!attr.HasLineSpacing() && currentStyle.HasLineSpacing())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_LINE_SPACING);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_LINE_SPACING);
+    }
 
     if (attr.HasCharacterStyleName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_CHARACTER_STYLE_NAME))
     {
 
     if (attr.HasCharacterStyleName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_CHARACTER_STYLE_NAME))
     {
@@ -12142,6 +13790,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetCharacterStyleName(attr.GetCharacterStyleName());
     }
         else
             currentStyle.SetCharacterStyleName(attr.GetCharacterStyleName());
     }
+    else if (!attr.HasCharacterStyleName() && currentStyle.HasCharacterStyleName())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_CHARACTER_STYLE_NAME);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_CHARACTER_STYLE_NAME);
+    }
 
     if (attr.HasParagraphStyleName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_PARAGRAPH_STYLE_NAME))
     {
 
     if (attr.HasParagraphStyleName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_PARAGRAPH_STYLE_NAME))
     {
@@ -12157,6 +13810,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetParagraphStyleName(attr.GetParagraphStyleName());
     }
         else
             currentStyle.SetParagraphStyleName(attr.GetParagraphStyleName());
     }
+    else if (!attr.HasParagraphStyleName() && currentStyle.HasParagraphStyleName())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_PARAGRAPH_STYLE_NAME);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_PARAGRAPH_STYLE_NAME);
+    }
 
     if (attr.HasListStyleName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_LIST_STYLE_NAME))
     {
 
     if (attr.HasListStyleName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_LIST_STYLE_NAME))
     {
@@ -12172,6 +13830,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetListStyleName(attr.GetListStyleName());
     }
         else
             currentStyle.SetListStyleName(attr.GetListStyleName());
     }
+    else if (!attr.HasListStyleName() && currentStyle.HasListStyleName())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_LIST_STYLE_NAME);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_LIST_STYLE_NAME);
+    }
 
     if (attr.HasBulletStyle() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_STYLE))
     {
 
     if (attr.HasBulletStyle() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_STYLE))
     {
@@ -12187,6 +13850,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetBulletStyle(attr.GetBulletStyle());
     }
         else
             currentStyle.SetBulletStyle(attr.GetBulletStyle());
     }
+    else if (!attr.HasBulletStyle() && currentStyle.HasBulletStyle())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_BULLET_STYLE);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_BULLET_STYLE);
+    }
 
     if (attr.HasBulletNumber() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_NUMBER))
     {
 
     if (attr.HasBulletNumber() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_NUMBER))
     {
@@ -12202,6 +13870,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetBulletNumber(attr.GetBulletNumber());
     }
         else
             currentStyle.SetBulletNumber(attr.GetBulletNumber());
     }
+    else if (!attr.HasBulletNumber() && currentStyle.HasBulletNumber())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_BULLET_NUMBER);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_BULLET_NUMBER);
+    }
 
     if (attr.HasBulletText() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_TEXT))
     {
 
     if (attr.HasBulletText() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_TEXT))
     {
@@ -12220,6 +13893,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             currentStyle.SetBulletFont(attr.GetBulletFont());
         }
     }
             currentStyle.SetBulletFont(attr.GetBulletFont());
         }
     }
+    else if (!attr.HasBulletText() && currentStyle.HasBulletText())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_BULLET_TEXT);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_BULLET_TEXT);
+    }
 
     if (attr.HasBulletName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_NAME))
     {
 
     if (attr.HasBulletName() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_BULLET_NAME))
     {
@@ -12237,6 +13915,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             currentStyle.SetBulletName(attr.GetBulletName());
         }
     }
             currentStyle.SetBulletName(attr.GetBulletName());
         }
     }
+    else if (!attr.HasBulletName() && currentStyle.HasBulletName())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_BULLET_NAME);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_BULLET_NAME);
+    }
 
     if (attr.HasURL() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_URL))
     {
 
     if (attr.HasURL() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_URL))
     {
@@ -12254,6 +13937,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             currentStyle.SetURL(attr.GetURL());
         }
     }
             currentStyle.SetURL(attr.GetURL());
         }
     }
+    else if (!attr.HasURL() && currentStyle.HasURL())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_URL);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_URL);
+    }
 
     if (attr.HasTextEffects() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_EFFECTS))
     {
 
     if (attr.HasTextEffects() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_EFFECTS))
     {
@@ -12293,6 +13981,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         if (currentStyle.GetTextEffectFlags() == 0)
             currentStyle.RemoveFlag(wxTEXT_ATTR_EFFECTS);
     }
         if (currentStyle.GetTextEffectFlags() == 0)
             currentStyle.RemoveFlag(wxTEXT_ATTR_EFFECTS);
     }
+    else if (!attr.HasTextEffects() && currentStyle.HasTextEffects())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_EFFECTS);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_EFFECTS);
+    }
 
     if (attr.HasOutlineLevel() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_OUTLINE_LEVEL))
     {
 
     if (attr.HasOutlineLevel() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_OUTLINE_LEVEL))
     {
@@ -12308,9 +14001,16 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         else
             currentStyle.SetOutlineLevel(attr.GetOutlineLevel());
     }
         else
             currentStyle.SetOutlineLevel(attr.GetOutlineLevel());
     }
+    else if (!attr.HasOutlineLevel() && currentStyle.HasOutlineLevel())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_OUTLINE_LEVEL);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_OUTLINE_LEVEL);
+    }
 }
 
 WX_DEFINE_OBJARRAY(wxRichTextVariantArray);
 }
 
 WX_DEFINE_OBJARRAY(wxRichTextVariantArray);
+WX_DEFINE_OBJARRAY(wxRichTextAttrArray);
+WX_DEFINE_OBJARRAY(wxRichTextRectArray);
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties, wxObject)
 
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties, wxObject)
 
@@ -12625,8 +14325,19 @@ bool wxRichTextSelection::WithinSelection(const wxRichTextRange& range, const wx
 IMPLEMENT_CLASS(wxRichTextDrawingHandler, wxObject)
 IMPLEMENT_CLASS(wxRichTextDrawingContext, wxObject)
 
 IMPLEMENT_CLASS(wxRichTextDrawingHandler, wxObject)
 IMPLEMENT_CLASS(wxRichTextDrawingContext, wxObject)
 
+wxRichTextDrawingContext::wxRichTextDrawingContext(wxRichTextBuffer* buffer)
+{
+    Init();
+    m_buffer = buffer;
+    if (m_buffer && m_buffer->GetRichTextCtrl())
+        EnableVirtualAttributes(m_buffer->GetRichTextCtrl()->GetVirtualAttributesEnabled());
+}
+
 bool wxRichTextDrawingContext::HasVirtualAttributes(wxRichTextObject* obj) const
 {
 bool wxRichTextDrawingContext::HasVirtualAttributes(wxRichTextObject* obj) const
 {
+    if (!GetVirtualAttributesEnabled())
+        return false;
+
     wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
     while (node)
     {
     wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
     while (node)
     {
@@ -12642,6 +14353,9 @@ bool wxRichTextDrawingContext::HasVirtualAttributes(wxRichTextObject* obj) const
 wxRichTextAttr wxRichTextDrawingContext::GetVirtualAttributes(wxRichTextObject* obj) const
 {
     wxRichTextAttr attr;
 wxRichTextAttr wxRichTextDrawingContext::GetVirtualAttributes(wxRichTextObject* obj) const
 {
     wxRichTextAttr attr;
+    if (!GetVirtualAttributesEnabled())
+        return attr;
+
     // We apply all handlers, so we can may combine several different attributes
     wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
     while (node)
     // We apply all handlers, so we can may combine several different attributes
     wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
     while (node)
@@ -12661,6 +14375,9 @@ wxRichTextAttr wxRichTextDrawingContext::GetVirtualAttributes(wxRichTextObject*
 
 bool wxRichTextDrawingContext::ApplyVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const
 {
 
 bool wxRichTextDrawingContext::ApplyVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const
 {
+    if (!GetVirtualAttributesEnabled())
+        return false;
+
     if (HasVirtualAttributes(obj))
     {
         wxRichTextAttr a(GetVirtualAttributes(obj));
     if (HasVirtualAttributes(obj))
     {
         wxRichTextAttr a(GetVirtualAttributes(obj));
@@ -12671,6 +14388,75 @@ bool wxRichTextDrawingContext::ApplyVirtualAttributes(wxRichTextAttr& attr, wxRi
         return false;
 }
 
         return false;
 }
 
+int wxRichTextDrawingContext::GetVirtualSubobjectAttributesCount(wxRichTextObject* obj) const
+{
+    if (!GetVirtualAttributesEnabled())
+        return 0;
+
+    wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
+    while (node)
+    {
+        wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+        int count = handler->GetVirtualSubobjectAttributesCount(obj);
+        if (count > 0)
+            return count;
+
+        node = node->GetNext();
+    }
+    return 0;
+}
+
+int wxRichTextDrawingContext::GetVirtualSubobjectAttributes(wxRichTextObject* obj, wxArrayInt& positions, wxRichTextAttrArray& attributes) const
+{
+    if (!GetVirtualAttributesEnabled())
+        return 0;
+
+    wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
+    while (node)
+    {
+        wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+        if (handler->GetVirtualSubobjectAttributes(obj, positions, attributes))
+            return positions.GetCount();
+
+        node = node->GetNext();
+    }
+    return 0;
+}
+
+bool wxRichTextDrawingContext::HasVirtualText(const wxRichTextPlainText* obj) const
+{
+    if (!GetVirtualAttributesEnabled())
+        return false;
+
+    wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
+    while (node)
+    {
+        wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+        if (handler->HasVirtualText(obj))
+            return true;
+
+        node = node->GetNext();
+    }
+    return false;
+}
+
+bool wxRichTextDrawingContext::GetVirtualText(const wxRichTextPlainText* obj, wxString& text) const
+{
+    if (!GetVirtualAttributesEnabled())
+        return false;
+
+    wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
+    while (node)
+    {
+        wxRichTextDrawingHandler *handler = (wxRichTextDrawingHandler*)node->GetData();
+        if (handler->GetVirtualText(obj, text))
+            return true;
+
+        node = node->GetNext();
+    }
+    return false;
+}
+
 /// Adds a handler to the end
 void wxRichTextBuffer::AddDrawingHandler(wxRichTextDrawingHandler *handler)
 {
 /// Adds a handler to the end
 void wxRichTextBuffer::AddDrawingHandler(wxRichTextDrawingHandler *handler)
 {
@@ -12724,5 +14510,45 @@ void wxRichTextBuffer::CleanUpDrawingHandlers()
     sm_drawingHandlers.Clear();
 }
 
     sm_drawingHandlers.Clear();
 }
 
+void wxRichTextBuffer::AddFieldType(wxRichTextFieldType *fieldType)
+{
+    sm_fieldTypes[fieldType->GetName()] = fieldType;
+}
+
+bool wxRichTextBuffer::RemoveFieldType(const wxString& name)
+{
+    wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+    if (it == sm_fieldTypes.end())
+        return false;
+    else
+    {
+        wxRichTextFieldType* fieldType = it->second;
+        sm_fieldTypes.erase(it);
+        delete fieldType;
+        return true;
+    }
+}
+
+wxRichTextFieldType *wxRichTextBuffer::FindFieldType(const wxString& name)
+{
+    wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+    if (it == sm_fieldTypes.end())
+        return NULL;
+    else
+        return it->second;
+}
+
+void wxRichTextBuffer::CleanUpFieldTypes()
+{
+    wxRichTextFieldTypeHashMap::iterator it;
+    for( it = sm_fieldTypes.begin(); it != sm_fieldTypes.end(); ++it )
+    {
+        wxRichTextFieldType* fieldType = it->second;
+        delete fieldType;
+    }
+
+    sm_fieldTypes.clear();
+}
+
 #endif
     // wxUSE_RICHTEXT
 #endif
     // wxUSE_RICHTEXT