]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
Small fixes after wxHtmlTagHandler::GetParser() addition.
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 6ccb090e8aa92fe99812fbb2327f66e844a658d8..1a6186778fb4eb69460db7737a46689942ea6c5b 100644 (file)
@@ -602,7 +602,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 (!IsFloating())
+        if (!IsFloating() || !wxRichTextBuffer::GetFloatingLayoutMode())
             SetCachedSize(wxDefaultSize);
         SetMaxSize(wxDefaultSize);
         SetMinSize(wxDefaultSize);
@@ -806,7 +806,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());
-        wxColour col(attr.GetTop().GetColour());
+        wxColour col(attr.GetBottom().GetColour());
 
         // If pen width is > 1, resorts to a solid rectangle.
         if (borderBottom == 1)
@@ -1076,7 +1076,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 (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)
@@ -1399,7 +1400,7 @@ wxRichTextObject* wxRichTextCompositeObject::GetChildAtPosition(long pos) const
 }
 
 /// 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)
@@ -1409,24 +1410,84 @@ bool wxRichTextCompositeObject::Defragment(const wxRichTextRange& range)
         {
             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
-                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();
@@ -1471,7 +1532,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.
-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;
@@ -1492,7 +1553,7 @@ bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSiz
         if (!child->GetRange().IsOutside(range))
         {
             // Floating objects have a zero size within the paragraph.
-            if (child->IsFloating())
+            if (child->IsFloating() && wxRichTextBuffer::GetFloatingLayoutMode())
             {
                 if (partialExtents)
                 {
@@ -1527,7 +1588,7 @@ bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange& range, wxSiz
                     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;
@@ -1581,10 +1642,17 @@ void wxRichTextCompositeObject::Invalidate(const wxRichTextRange& invalidRange)
         }
         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
-                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);
@@ -1733,7 +1801,7 @@ int wxRichTextParagraphLayoutBox::HitTest(wxDC& dc, wxRichTextDrawingContext& co
         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)
@@ -1748,7 +1816,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)
 {
-    if (m_floatCollector)
+    if (wxRichTextBuffer::GetFloatingLayoutMode() && m_floatCollector)
         m_floatCollector->Draw(dc, context, range, selection, rect, descent, style);
 }
 
@@ -1782,7 +1850,9 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, wxRichTextDrawingContext& cont
         theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
     DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags);
 
-    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)
     {
@@ -1916,7 +1986,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.
-    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;
@@ -2020,7 +2091,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
         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)
@@ -2111,7 +2182,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
 }
 
 /// 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;
 
@@ -2170,7 +2241,7 @@ bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wx
         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);
 
@@ -3247,7 +3318,17 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
                             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;
+
+                            if (!url.IsEmpty())
+                                child->GetAttributes().SetURL(url);
+                        }
                         else
                         {
                             if (applyMinimal)
@@ -3389,7 +3470,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
 {
     style = wxRichTextAttr();
 
-    wxRichTextAttr clashingAttr;
+    wxRichTextAttr clashingAttrPara, clashingAttrChar;
     wxRichTextAttr absentAttrPara, absentAttrChar;
 
     wxRichTextObjectList::compatibility_iterator node = GetChildren().GetFirst();
@@ -3402,7 +3483,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
             {
                 wxRichTextAttr paraStyle = para->GetCombinedAttributes(true /* use box attributes */);
 
-                CollectStyle(style, paraStyle, clashingAttr, absentAttrPara);
+                CollectStyle(style, paraStyle, clashingAttrPara, absentAttrPara);
             }
             else
             {
@@ -3412,7 +3493,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
                 // 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();
 
@@ -3426,7 +3507,7 @@ bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange& range
                         // 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();
@@ -3784,8 +3865,21 @@ wxRichTextRange wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagrap
         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;
 }
@@ -3985,12 +4079,18 @@ bool wxRichTextParagraphLayoutBox::SetListStyle(const wxRichTextRange& range, wx
                     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())
                 {
@@ -4000,6 +4100,7 @@ bool wxRichTextParagraphLayoutBox::SetListStyle(const wxRichTextRange& range, wx
                     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);
@@ -4163,6 +4264,10 @@ bool wxRichTextParagraphLayoutBox::DoNumberList(const wxRichTextRange& range, co
                     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)
@@ -4196,7 +4301,8 @@ bool wxRichTextParagraphLayoutBox::DoNumberList(const wxRichTextRange& range, co
                     }
                     else
                     {
-                        levels[currentLevel] ++;
+                        if (!(para->GetAttributes().HasBulletStyle() && (para->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_CONTINUATION)))
+                            levels[currentLevel] ++;
                     }
 
                     newPara->GetAttributes().SetBulletNumber(levels[currentLevel]);
@@ -4275,7 +4381,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
 {
-    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();
@@ -4374,7 +4497,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
     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)
         {
@@ -4466,7 +4589,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
             {
                 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());
@@ -4539,9 +4662,15 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
     // Deal with floating objects firstly before the normal layout
     wxRichTextBuffer* buffer = GetBuffer();
     wxASSERT(buffer);
+
     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);
@@ -4558,10 +4687,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.
-    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
@@ -4599,7 +4732,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
     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)
@@ -4629,8 +4762,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 (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();
@@ -4681,7 +4814,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 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);
             }
         }
 
@@ -4698,10 +4831,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
-            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
-            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
         }
 
@@ -4739,20 +4872,24 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 lineAscent = wxMax(childSize.y-childDescent, maxAscent);
             }
             lineHeight = wxMax(lineHeight, (lineDescent + lineAscent));
-            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.
 
-            if (floatAvailableRect.x + startOffset > availableRect.x)
+            if (wxRichTextBuffer::GetFloatingLayoutMode() && collector)
             {
-                int newX = floatAvailableRect.x + startOffset;
-                int newW = availableRect.width - (newX - availableRect.x);
-                availableRect.x = newX;
-                availableRect.width = newW;
-            }
+                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.
+
+                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;
 
@@ -4766,7 +4903,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                     // 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();
 
@@ -4775,7 +4912,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                         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
@@ -4804,9 +4941,10 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         if ((lineBreakInThisObject && (childSize.x + currentWidth <= availableRect.width))
             ||
             (childSize.x + currentWidth > availableRect.width)
+#if 0
             ||
             ((childSize.x + currentWidth <= availableRect.width) && !node->GetNext())
-
+#endif
             )
         {
             long wrapPosition = 0;
@@ -4831,7 +4969,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())
-                wrapPosition = GetRange().GetEnd()-1;
+                wrapPosition = wxMax(0, GetRange().GetEnd()-1);
 
             // wxLogDebug(wxT("Split at %ld"), wrapPosition);
 
@@ -4845,12 +4983,12 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             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
-                GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED);
+                GetRangeSize(actualRange, actualSize, childDescent, dc, context, wxRICHTEXT_UNFORMATTED, wxPoint(0,0), parentRect.GetSize());
 
             currentWidth = actualSize.x;
 
@@ -4948,6 +5086,44 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
 
     //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);
 
@@ -4982,7 +5158,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 (!child->IsFloating() && child->GetRange().GetLength() != 0 && !wxDynamicCast(child, wxRichTextPlainText))
+            if ((!child->IsFloating() || !wxRichTextBuffer::GetFloatingLayoutMode()) && child->GetRange().GetLength() != 0 && !wxDynamicCast(child, wxRichTextPlainText))
             {
                 if (child->GetCachedSize().x > minWidth)
                     minWidth = child->GetMinSize().x;
@@ -5166,7 +5342,7 @@ void wxRichTextParagraph::ClearLines()
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, 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;
@@ -5194,7 +5370,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
             if (!child->GetRange().IsOutside(range))
             {
                 // Floating objects have a zero size within the paragraph.
-                if (child->IsFloating())
+                if (child->IsFloating() && wxRichTextBuffer::GetFloatingLayoutMode())
                 {
                     if (partialExtents)
                     {
@@ -5280,7 +5456,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                             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)
                         {
@@ -5358,7 +5534,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                 {
                     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());
@@ -5367,7 +5543,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
                         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)
                             {
@@ -5573,7 +5749,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, wxRichTextDrawingContext& context, co
                 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;
@@ -6084,7 +6260,7 @@ void wxRichTextParagraph::ClearDefaultTabs()
     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)
@@ -6092,9 +6268,23 @@ void wxRichTextParagraph::LayoutFloat(wxDC& dc, wxRichTextDrawingContext& contex
         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;
-            int descent, x = 0;
+            int descent = 0;
             anchored->GetRangeSize(anchored->GetRange(), size, descent, dc, context, style);
+#endif
 
             int offsetY = 0;
             if (anchored->GetAttributes().GetTextBoxAttr().GetTop().IsValid())
@@ -6122,7 +6312,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;
 
-            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);
         }
@@ -6248,11 +6439,17 @@ bool wxRichTextPlainText::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
 
     int offset = GetRange().GetStart();
 
-    // Replace line break characters with spaces
     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(" "));
-    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();
@@ -6268,6 +6465,13 @@ bool wxRichTextPlainText::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
     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 (textFont.IsUsingSizeInPixels())
@@ -6568,7 +6772,7 @@ void wxRichTextPlainText::Copy(const wxRichTextPlainText& obj)
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, 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;
@@ -6606,6 +6810,13 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
             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;
+        }
         else
         {
             wxCheckSetFont(dc, font);
@@ -6617,12 +6828,18 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
     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);
 
-    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;
@@ -6823,15 +7040,44 @@ wxString wxRichTextPlainText::GetTextForRange(const wxRichTextRange& range) cons
 }
 
 /// 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() == wxCLASSINFO(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.
-bool wxRichTextPlainText::Merge(wxRichTextObject* object)
+bool wxRichTextPlainText::Merge(wxRichTextObject* object, wxRichTextDrawingContext& WXUNUSED(context))
 {
     wxRichTextPlainText* textObject = wxDynamicCast(object, wxRichTextPlainText);
     wxASSERT( textObject != NULL );
@@ -6846,6 +7092,214 @@ bool wxRichTextPlainText::Merge(wxRichTextObject* object)
         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)
 {
@@ -6883,6 +7337,7 @@ 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()
@@ -8451,13 +8906,13 @@ bool wxRichTextField::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     return wxRichTextParagraphLayoutBox::Layout(dc, context, rect, parentRect, style);
 }
 
-bool wxRichTextField::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+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, partialExtents);
+        return fieldType->GetRangeSize((wxRichTextField*) this, range, size, descent, dc, context, flags, position, parentSize, partialExtents);
 
-    return wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, partialExtents);
+    return wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, parentSize, partialExtents);
 }
 
 /// Calculate range
@@ -8693,10 +9148,10 @@ bool wxRichTextFieldTypeStandard::Layout(wxRichTextField* obj, wxDC& dc, wxRichT
     return true;
 }
 
-bool wxRichTextFieldTypeStandard::GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+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);
+        return obj->wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, parentSize);
     else
     {
         wxSize sz = GetSize(obj, dc, context, 0);
@@ -9584,9 +10039,9 @@ void wxRichTextTable::CalculateRange(long start, long& end)
 }
 
 // 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.
@@ -10219,9 +10674,15 @@ bool wxRichTextAction::Do()
         {
             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());
 
@@ -10249,7 +10710,11 @@ 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.
-            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());
 
@@ -10282,7 +10747,11 @@ 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.
-            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());
 
@@ -10425,7 +10894,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)
-            if (container->GetFloatingObjectCount() > 0 || (container->GetParent() && containerRect != container->GetRect()))
+            if ((wxRichTextBuffer::GetFloatingLayoutMode() && container->GetFloatingObjectCount() > 0) || (container->GetParent() && containerRect != container->GetRect()))
             {
                 m_ctrl->Refresh(false);
             }
@@ -10635,13 +11104,17 @@ wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock& imageBlock, wxRichT
         SetAttributes(*charStyle);
 }
 
+wxRichTextImage::~wxRichTextImage()
+{
+}
+
 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;
@@ -10651,7 +11124,7 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
     // 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;
 
@@ -10671,29 +11144,36 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
     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);
-            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)
@@ -10767,6 +11247,10 @@ bool wxRichTextImage::LoadImageCache(wxDC& dc, bool resetCache)
             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
@@ -10865,12 +11349,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.
-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 (!((wxRichTextImage*)this)->LoadImageCache(dc))
+    if (!((wxRichTextImage*)this)->LoadImageCache(dc, false, parentSize))
     {
         size.x = 0; size.y = 0;
         if (partialExtents)
@@ -11438,7 +11922,7 @@ wxString wxRichTextImageBlock::GetExtension() const
  * The data object for a wxRichTextBuffer
  */
 
-const wxChar *wxRichTextBufferDataObject::ms_richTextBufferFormatId = wxT("wxShape");
+const wxChar *wxRichTextBufferDataObject::ms_richTextBufferFormatId = wxT("wxRichText");
 
 wxRichTextBufferDataObject::wxRichTextBufferDataObject(wxRichTextBuffer* richTextBuffer)
 {
@@ -12409,7 +12893,14 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
 
     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)
+    {
+        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))
         {
@@ -12425,6 +12916,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             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.HasFontPixelSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_PIXEL_SIZE))
         {
@@ -12440,99 +12936,134 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             else
                 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.HasFontItalic() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_ITALIC))
+    if (attr.HasFontItalic() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_ITALIC))
+    {
+        if (currentStyle.HasFontItalic())
         {
-            if (currentStyle.HasFontItalic())
+            if (currentStyle.GetFontStyle() != attr.GetFontStyle())
             {
-                if (currentStyle.GetFontStyle() != attr.GetFontStyle())
-                {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_ITALIC);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_ITALIC);
-                }
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_ITALIC);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_ITALIC);
             }
-            else
-                currentStyle.SetFontStyle(attr.GetFontStyle());
         }
+        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 (attr.HasFontFamily() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_FAMILY))
+    {
+        if (currentStyle.HasFontFamily())
         {
-            if (currentStyle.HasFontFamily())
+            if (currentStyle.GetFontFamily() != attr.GetFontFamily())
             {
-                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_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());
+            wxString faceName1(currentStyle.GetFontFaceName());
+            wxString faceName2(attr.GetFontFaceName());
 
-                if (faceName1 != faceName2)
-                {
-                    // Clash of attr - mark as such
-                    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);
             }
-            else
-                currentStyle.SetFontFaceName(attr.GetFontFaceName());
         }
+        else
+            currentStyle.SetFontFaceName(attr.GetFontFaceName());
+    }
+    else if (!attr.HasFontFaceName() && currentStyle.HasFontFaceName())
+    {
+        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_FACE);
+        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_FACE);
+    }
 
-        if (attr.HasFontUnderlined() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_UNDERLINE))
+    if (attr.HasFontUnderlined() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_UNDERLINE))
+    {
+        if (currentStyle.HasFontUnderlined())
         {
-            if (currentStyle.HasFontUnderlined())
+            if (currentStyle.GetFontUnderlined() != attr.GetFontUnderlined())
             {
-                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_UNDERLINE);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_UNDERLINE);
             }
-            else
-                currentStyle.SetFontUnderlined(attr.GetFontUnderlined());
         }
+        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.HasFontStrikethrough() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_STRIKETHROUGH))
+    if (attr.HasFontStrikethrough() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_STRIKETHROUGH))
+    {
+        if (currentStyle.HasFontStrikethrough())
         {
-            if (currentStyle.HasFontStrikethrough())
+            if (currentStyle.GetFontStrikethrough() != attr.GetFontStrikethrough())
             {
-                if (currentStyle.GetFontStrikethrough() != attr.GetFontStrikethrough())
-                {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
-                }
+                // Clash of attr - mark as such
+                clashingAttr.AddFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+                currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
             }
-            else
-                currentStyle.SetFontStrikethrough(attr.GetFontStrikethrough());
         }
+        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))
@@ -12549,6 +13080,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12564,6 +13100,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12579,6 +13120,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12594,6 +13140,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12609,6 +13160,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12624,6 +13180,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12639,6 +13200,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12654,6 +13220,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12669,6 +13240,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12684,6 +13260,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12699,6 +13280,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12714,6 +13300,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12729,6 +13320,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12744,6 +13340,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12762,6 +13363,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             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))
     {
@@ -12779,6 +13385,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             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))
     {
@@ -12796,6 +13407,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             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))
     {
@@ -12835,6 +13451,11 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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))
     {
@@ -12850,10 +13471,18 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
         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);
 
+// JACS 2013-01-27
+WX_DEFINE_OBJARRAY(wxRichTextAttrArray);
+
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties, wxObject)
 
 bool wxRichTextProperties::operator==(const wxRichTextProperties& props) const
@@ -13167,8 +13796,19 @@ bool wxRichTextSelection::WithinSelection(const wxRichTextRange& range, const wx
 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
 {
+    if (!GetVirtualAttributesEnabled())
+        return false;
+
     wxList::compatibility_iterator node = m_buffer->GetDrawingHandlers().GetFirst();
     while (node)
     {
@@ -13184,6 +13824,9 @@ bool wxRichTextDrawingContext::HasVirtualAttributes(wxRichTextObject* obj) const
 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)
@@ -13203,6 +13846,9 @@ wxRichTextAttr wxRichTextDrawingContext::GetVirtualAttributes(wxRichTextObject*
 
 bool wxRichTextDrawingContext::ApplyVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const
 {
+    if (!GetVirtualAttributesEnabled())
+        return false;
+
     if (HasVirtualAttributes(obj))
     {
         wxRichTextAttr a(GetVirtualAttributes(obj));
@@ -13213,6 +13859,75 @@ bool wxRichTextDrawingContext::ApplyVirtualAttributes(wxRichTextAttr& attr, wxRi
         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)
 {