]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
String formatting fixes
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index c4086d5dce1db065182c8d543fa04d546209e8d4..ff4505b10ccfc2a64b80bbc6023208c7308add68 100644 (file)
@@ -42,6 +42,7 @@
 #include "wx/richtext/richtextstyles.h"
 #include "wx/richtext/richtextimagedlg.h"
 #include "wx/richtext/richtextsizepage.h"
+#include "wx/richtext/richtextxml.h"
 
 #include "wx/listimpl.cpp"
 #include "wx/arrimpl.cpp"
@@ -464,21 +465,6 @@ int wxRichTextFloatCollector::HitTest(wxDC& dc, wxRichTextDrawingContext& contex
 // Helpers for efficiency
 inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
 {
-    // JACS: did I do this some time ago when testing? Should we re-enable it?
-#if 0
-    const wxFont& font1 = dc.GetFont();
-    if (font1.IsOk() && font.IsOk())
-    {
-        if (font1.GetPointSize() == font.GetPointSize() &&
-            font1.GetFamily() == font.GetFamily() &&
-            font1.GetStyle() == font.GetStyle() &&
-            font1.GetWeight() == font.GetWeight() &&
-            font1.GetUnderlined() == font.GetUnderlined() &&
-            font1.GetFamily() == font.GetFamily() &&
-            font1.GetFaceName() == font.GetFaceName())
-            return;
-    }
-#endif
     dc.SetFont(font);
 }
 
@@ -629,7 +615,7 @@ int wxRichTextObject::ConvertTenthsMMToPixels(wxDC& dc, int units) const
     // Unscale
     double scale = 1.0;
     if (GetBuffer())
-        scale = GetBuffer()->GetScale();
+        scale = GetBuffer()->GetScale() / GetBuffer()->GetDimensionScale();
     int p = ConvertTenthsMMToPixels(dc.GetPPI().x, units, scale);
 
     return p;
@@ -1022,7 +1008,7 @@ void wxRichTextObject::Dump(wxTextOutputStream& stream)
 wxRichTextBuffer* wxRichTextObject::GetBuffer() const
 {
     const wxRichTextObject* obj = this;
-    while (obj && !obj->IsKindOf(CLASSINFO(wxRichTextBuffer)))
+    while (obj && !wxDynamicCast(obj, wxRichTextBuffer))
         obj = obj->GetParent();
     return wxDynamicCast(obj, wxRichTextBuffer);
 }
@@ -1869,6 +1855,10 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
         availableSpace = GetAvailableContentArea(dc, context, rect);
     }
 
+    // Fix the width if we're at the top level
+    if (!GetParent())
+        attr.GetTextBoxAttr().GetWidth().SetValue(rect.GetWidth(), wxTEXT_ATTR_UNITS_PIXELS);
+
     int leftMargin, rightMargin, topMargin, bottomMargin;
     wxRichTextObject::GetTotalMargin(dc, GetBuffer(), attr, leftMargin, rightMargin,
             topMargin, bottomMargin);
@@ -2047,6 +2037,12 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, wxRichTextDrawingContext& co
         maxWidth = wxMax(maxWidth, w);
         maxMaxWidth = wxMax(maxMaxWidth, w);
     }
+    else
+    {
+        // TODO: Make sure the layout box's position reflects
+        // the position of the children, but without
+        // breaking layout of a box within a paragraph.
+    }
 
     // TODO: (also in para layout) should set the
     // object's size to an absolute one if specified,
@@ -2367,6 +2363,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraph(const wxString& text,
     wxRichTextAttr* cStyle = & defaultCharStyle;
 
     wxRichTextParagraph* para = new wxRichTextParagraph(text, this, pStyle, cStyle);
+    para->GetAttributes().GetTextBoxAttr().Reset();
 
     AppendChild(para);
 
@@ -2408,6 +2405,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
     size_t len = text.length();
     wxString line;
     wxRichTextParagraph* para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+    para->GetAttributes().GetTextBoxAttr().Reset();
 
     AppendChild(para);
 
@@ -2425,6 +2423,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
                 plainText->SetText(line);
 
                 para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+                para->GetAttributes().GetTextBoxAttr().Reset();
 
                 AppendChild(para);
 
@@ -2474,6 +2473,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddImage(const wxImage& image, wxR
     wxRichTextAttr* cStyle = & defaultCharStyle;
 
     wxRichTextParagraph* para = new wxRichTextParagraph(this, pStyle);
+    para->GetAttributes().GetTextBoxAttr().Reset();
     AppendChild(para);
     para->AppendChild(new wxRichTextImage(image, this, cStyle));
 
@@ -3337,6 +3337,7 @@ bool wxRichTextParagraphLayoutBox::DoGetStyle(long position, wxRichTextAttr& sty
             {
                 // Start with the base style
                 style = GetAttributes();
+                style.GetTextBoxAttr().Reset();
 
                 // Apply the paragraph style
                 wxRichTextApplyStyle(style, obj->GetAttributes());
@@ -3477,12 +3478,12 @@ bool wxRichTextParagraphLayoutBox::HasCharacterAttributes(const wxRichTextRange&
                     if (childRange.GetLength() == 0 && GetRange().GetLength() == 1)
                         childRange.SetEnd(childRange.GetEnd()+1);
 
-                    if (!childRange.IsOutside(range) && child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
+                    if (!childRange.IsOutside(range) && wxDynamicCast(child, wxRichTextPlainText))
                     {
                         foundCount ++;
                         wxRichTextAttr textAttr = para->GetCombinedAttributes(child->GetAttributes());
 
-                        if (wxTextAttrEqPartial(textAttr, style))
+                        if (textAttr.EqPartial(style, false /* strong test - attributes must be valid in both objects */))
                             matchingCount ++;
                     }
 
@@ -3525,7 +3526,7 @@ bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange&
                 wxRichTextApplyStyle(textAttr, para->GetAttributes());
 
                 foundCount ++;
-                if (wxTextAttrEqPartial(textAttr, style))
+                if (textAttr.EqPartial(style, false /* strong test */))
                     matchingCount ++;
             }
         }
@@ -3542,7 +3543,6 @@ void wxRichTextParagraphLayoutBox::PrepareContent(wxRichTextParagraphLayoutBox&
         buffer->GetRichTextCtrl()->PrepareContent(container);
 }
 
-
 /// Set character or paragraph properties
 bool wxRichTextParagraphLayoutBox::SetProperties(const wxRichTextRange& range, const wxRichTextProperties& properties, int flags)
 {
@@ -3985,12 +3985,19 @@ 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);
-                    }
+                        // Now we need to do numbering
+                        if (renumber)
+                        {
+                            newPara->GetAttributes().SetBulletNumber(n);
+                        }
 
-                    n ++;
+                        n ++;
+                    }
                 }
                 else if (!newPara->GetAttributes().GetListStyleName().IsEmpty())
                 {
@@ -4163,6 +4170,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 +4207,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,6 +4287,22 @@ 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
 {
+    // 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->GetAttributes().HasFlag(wxTEXT_ATTR_BULLET_STYLE) || previousParagraph->GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
         return false;
 
@@ -4374,7 +4402,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)
         {
@@ -4611,7 +4639,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
 
         node = node->GetNext();
     }
-
 #endif
 
     // Split up lines
@@ -4724,7 +4751,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
             wxRect oldAvailableRect = availableRect;
 
             // Available width depends on the floating objects and the line height.
-            // Note: the floating objects may be placed vertically along the two side of
+            // Note: the floating objects may be placed vertically along the two sides of
             // buffer, so we may have different available line widths with different
             // [startY, endY]. So, we can't determine how wide the available
             // space is until we know the exact line height.
@@ -4740,7 +4767,6 @@ 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.
@@ -4764,7 +4790,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                 {
                     wxSize oldSize = child->GetCachedSize();
 
-                    //child->SetCachedSize(wxDefaultSize);
                     // Lays out the object first with a given amount of space, and then if no width was specified in attr,
                     // lays out the object again using the minimum size
                     child->Invalidate(wxRICHTEXT_ALL);
@@ -4772,7 +4797,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
                                 attr, child->GetAttributes(), availableRect, parentRect, style);
                     childSize = child->GetCachedSize();
                     childDescent = child->GetDescent();
-                    //child->SetPosition(availableRect.GetPosition());
 
                     if (oldSize != child->GetCachedSize())
                     {
@@ -4795,7 +4819,8 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         if (child->IsTopLevel())
         {
             // We can move it to the correct position at this point
-            child->Move(GetPosition() + wxPoint(currentWidth, currentPosition.y));
+            // TODO: probably need to add margin
+            child->Move(GetPosition() + wxPoint(currentWidth + (wxMax(leftIndent, leftIndent + leftSubIndent)), currentPosition.y));
         }
 
         // Cases:
@@ -4834,7 +4859,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);
 
@@ -4985,7 +5010,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 && !child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
+            if (!child->IsFloating() && child->GetRange().GetLength() != 0 && !wxDynamicCast(child, wxRichTextPlainText))
             {
                 if (child->GetCachedSize().x > minWidth)
                     minWidth = child->GetMinSize().x;
@@ -4999,7 +5024,6 @@ bool wxRichTextParagraph::Layout(wxDC& dc, wxRichTextDrawingContext& context, co
         SetMinSize(marginRect.GetSize());
     }
 
-
 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS
 #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING
     // Use the text extents to calculate the size of each fragment in each line
@@ -5053,6 +5077,7 @@ void wxRichTextParagraph::ApplyParagraphStyle(wxRichTextLine* line, const wxRich
         return;
 
     wxPoint pos = line->GetPosition();
+    wxPoint originalPos = pos;
     wxSize size = line->GetSize();
 
     // centering, right-justification
@@ -5068,6 +5093,22 @@ void wxRichTextParagraph::ApplyParagraphStyle(wxRichTextLine* line, const wxRich
         pos.x = pos.x + rect.GetWidth() - size.x - rightIndent;
         line->SetPosition(pos);
     }
+
+    if (pos != originalPos)
+    {
+        wxPoint inc = pos - originalPos;
+
+        wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+
+        while (node)
+        {
+            wxRichTextObject* child = node->GetData();
+            if (child->IsTopLevel() && !child->GetRange().IsOutside(line->GetAbsoluteRange()))
+                child->Move(child->GetPosition() + inc);
+
+            node = node->GetNext();
+        }
+    }
 }
 
 /// Insert text at the given position
@@ -5177,7 +5218,6 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
         wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
         while (node)
         {
-
             wxRichTextObject* child = node->GetData();
             if (!child->GetRange().IsOutside(range))
             {
@@ -5203,7 +5243,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                     rangeToUse.LimitTo(child->GetRange());
                     int childDescent = 0;
 
-                    // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size,
+                    // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we've already cached the size,
                     // but it's only going to be used after caching has taken place.
                     if ((flags & wxRICHTEXT_HEIGHT_ONLY) && child->GetCachedSize().y != 0)
                     {
@@ -5372,7 +5412,6 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                             maxLineHeight = wxMax(maxLineHeight, (maxAscent + maxDescent));
                             maxLineWidth += childSize.x;
                         }
-                        descent = wxMax(descent, childDescent);
                     }
 
                     node2 = node2->GetNext();
@@ -5511,7 +5550,11 @@ int wxRichTextParagraph::HitTest(wxDC& dc, wxRichTextDrawingContext& context, co
     while (objNode)
     {
         wxRichTextObject* child = objNode->GetData();
-        if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0))
+        // Don't recurse if we have wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS,
+        // and also, if this seems composite but actually is marked as atomic,
+        // don't recurse.
+        if (child->IsTopLevel() && ((flags & wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS) == 0) &&
+            (! (((flags & wxRICHTEXT_HITTEST_HONOUR_ATOMIC) != 0) && child->IsAtomic())))
         {
             {
                 int hitTest = child->HitTest(dc, context, pt, textPosition, obj, contextObj);
@@ -6255,19 +6298,40 @@ bool wxRichTextPlainText::Draw(wxDC& dc, wxRichTextDrawingContext& context, cons
     {
         if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT) )
         {
-            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
-            textFont.SetPointSize( static_cast<int>(size) );
-            x = rect.x;
-            y = rect.y;
+            if (textFont.IsUsingSizeInPixels())
+            {
+                double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+                x = rect.x;
+                y = rect.y;
+            }
+            else
+            {
+                double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPointSize(static_cast<int>(size));
+                x = rect.x;
+                y = rect.y;
+            }
             wxCheckSetFont(dc, textFont);
         }
         else if ( textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) )
         {
-            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
-            textFont.SetPointSize( static_cast<int>(size) );
-            x = rect.x;
-            int sub_height = static_cast<int>( static_cast<double>(charHeight) / wxSCRIPT_MUL_FACTOR);
-            y = rect.y + (rect.height - sub_height + (descent - m_descent));
+            if (textFont.IsUsingSizeInPixels())
+            {
+                double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+                x = rect.x;
+                int sub_height = static_cast<int>(static_cast<double>(charHeight) / wxSCRIPT_MUL_FACTOR);
+                y = rect.y + (rect.height - sub_height + (descent - m_descent));
+            }
+            else
+            {
+                double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPointSize(static_cast<int>(size));
+                x = rect.x;
+                int sub_height = static_cast<int>(static_cast<double>(charHeight) / wxSCRIPT_MUL_FACTOR);
+                y = rect.y + (rect.height - sub_height + (descent - m_descent));
+            }
             wxCheckSetFont(dc, textFont);
         }
         else
@@ -6506,8 +6570,8 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxRichTextAttr& attr,
 
         x += w;
     }
-    return true;
 
+    return true;
 }
 
 /// Lay the item out
@@ -6557,8 +6621,16 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
             || (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT) ) )
         {
             wxFont textFont = font;
-            double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
-            textFont.SetPointSize( static_cast<int>(size) );
+            if (textFont.IsUsingSizeInPixels())
+            {
+                double size = static_cast<double>(textFont.GetPixelSize().y) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPixelSize(wxSize(0, static_cast<int>(size)));
+            }
+            else
+            {
+                double size = static_cast<double>(textFont.GetPointSize()) / wxSCRIPT_MUL_FACTOR;
+                textFont.SetPointSize(static_cast<int>(size));
+            }
             wxCheckSetFont(dc, textFont);
             bScript = true;
         }
@@ -6781,7 +6853,7 @@ 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
 {
-    return object->GetClassInfo() == CLASSINFO(wxRichTextPlainText) &&
+    return object->GetClassInfo() == wxCLASSINFO(wxRichTextPlainText) &&
         (m_text.empty() || (wxTextAttrEq(GetAttributes(), object->GetAttributes()) && m_properties == object->GetProperties()));
 }
 
@@ -6833,11 +6905,12 @@ long wxRichTextPlainText::GetFirstLineBreakPosition(long pos)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer, wxRichTextParagraphLayoutBox)
 
-wxList                  wxRichTextBuffer::sm_handlers;
-wxList                  wxRichTextBuffer::sm_drawingHandlers;
-wxRichTextRenderer*     wxRichTextBuffer::sm_renderer = NULL;
-int                     wxRichTextBuffer::sm_bulletRightMargin = 20;
-float                   wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
+wxList                      wxRichTextBuffer::sm_handlers;
+wxList                      wxRichTextBuffer::sm_drawingHandlers;
+wxRichTextFieldTypeHashMap  wxRichTextBuffer::sm_fieldTypes;
+wxRichTextRenderer*         wxRichTextBuffer::sm_renderer = NULL;
+int                         wxRichTextBuffer::sm_bulletRightMargin = 20;
+float                       wxRichTextBuffer::sm_bulletProportion = (float) 0.3;
 
 /// Initialisation
 void wxRichTextBuffer::Init()
@@ -6850,6 +6923,8 @@ void wxRichTextBuffer::Init()
     m_suppressUndo = 0;
     m_handlerFlags = 0;
     m_scale = 1.0;
+    m_dimensionScale = 1.0;
+    m_fontScale = 1.0;
     SetMargins(4);
 }
 
@@ -6885,6 +6960,8 @@ void wxRichTextBuffer::Copy(const wxRichTextBuffer& obj)
     m_batchedCommand = NULL;
     m_suppressUndo = obj.m_suppressUndo;
     m_invalidRange = obj.m_invalidRange;
+    m_dimensionScale = obj.m_dimensionScale;
+    m_fontScale = obj.m_fontScale;
 }
 
 /// Push style sheet to top of stack
@@ -7005,6 +7082,8 @@ bool wxRichTextParagraphLayoutBox::InsertNewlineWithUndo(wxRichTextBuffer* buffe
     }
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
 
     wxRichTextParagraph* newPara = new wxRichTextParagraph(wxEmptyString, this, & attr);
     action->GetNewParagraphs().AppendChild(newPara);
@@ -7032,13 +7111,13 @@ bool wxRichTextParagraphLayoutBox::InsertNewlineWithUndo(wxRichTextBuffer* buffe
 
     action->SetPosition(pos);
 
-    // Use the default character style
     // Use the default character style
     if (!buffer->GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
     {
         // Check whether the default style merely reflects the paragraph/basic style,
         // in which case don't apply it.
         wxRichTextAttr defaultStyle(buffer->GetDefaultStyle());
+        defaultStyle.GetTextBoxAttr().Reset();
         wxRichTextAttr toApply;
         if (para)
         {
@@ -7088,6 +7167,9 @@ bool wxRichTextParagraphLayoutBox::InsertImageWithUndo(wxRichTextBuffer* buffer,
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
 
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
+
     wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
     if (p)
         newPara->SetAttributes(*p);
@@ -7132,6 +7214,9 @@ wxRichTextObject* wxRichTextParagraphLayoutBox::InsertObjectWithUndo(wxRichTextB
 
     wxRichTextAttr attr(buffer->GetDefaultStyle());
 
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
+
     wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
     if (p)
         newPara->SetAttributes(*p);
@@ -7153,6 +7238,50 @@ wxRichTextObject* wxRichTextParagraphLayoutBox::InsertObjectWithUndo(wxRichTextB
     return obj;
 }
 
+wxRichTextField* wxRichTextParagraphLayoutBox::InsertFieldWithUndo(wxRichTextBuffer* buffer, long pos, const wxString& fieldType,
+                                                        const wxRichTextProperties& properties,
+                                                        wxRichTextCtrl* ctrl, int flags,
+                                                        const wxRichTextAttr& textAttr)
+{
+    wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Field"), wxRICHTEXT_INSERT, buffer, this, ctrl, false);
+
+    wxRichTextAttr* p = NULL;
+    wxRichTextAttr paraAttr;
+    if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
+    {
+        paraAttr = GetStyleForNewParagraph(buffer, pos);
+        if (!paraAttr.IsDefault())
+            p = & paraAttr;
+    }
+
+    wxRichTextAttr attr(buffer->GetDefaultStyle());
+
+    // Don't include box attributes such as margins
+    attr.GetTextBoxAttr().Reset();
+
+    wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
+    if (p)
+        newPara->SetAttributes(*p);
+
+    wxRichTextField* fieldObject = new wxRichTextField();
+    fieldObject->wxRichTextObject::SetProperties(properties);
+    fieldObject->SetFieldType(fieldType);
+    fieldObject->SetAttributes(textAttr);
+    newPara->AppendChild(fieldObject);
+    action->GetNewParagraphs().AppendChild(newPara);
+    action->GetNewParagraphs().UpdateRanges();
+    action->GetNewParagraphs().SetPartialParagraph(true);
+    action->SetPosition(pos);
+
+    // Set the range we'll need to delete in Undo
+    action->SetRange(wxRichTextRange(pos, pos));
+
+    buffer->SubmitAction(action);
+
+    wxRichTextField* obj = wxDynamicCast(GetLeafObjectAtPosition(pos), wxRichTextField);
+    return obj;
+}
+
 /// Get the style that is appropriate for a new paragraph at this position.
 /// If the previous paragraph has a paragraph style name, look up the next-paragraph
 /// style.
@@ -7349,9 +7478,10 @@ bool wxRichTextBuffer::EndSuppressUndo()
 bool wxRichTextBuffer::BeginStyle(const wxRichTextAttr& style)
 {
     wxRichTextAttr newStyle(GetDefaultStyle());
+    newStyle.GetTextBoxAttr().Reset();
 
     // Save the old default style
-    m_attributeStack.Append((wxObject*) new wxRichTextAttr(GetDefaultStyle()));
+    m_attributeStack.Append((wxObject*) new wxRichTextAttr(newStyle));
 
     wxRichTextApplyStyle(newStyle, style);
     newStyle.SetFlags(style.GetFlags()|newStyle.GetFlags());
@@ -8099,6 +8229,17 @@ int wxRichTextBuffer::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const
     }
 }
 
+void wxRichTextBuffer::SetFontScale(double fontScale)
+{
+    m_fontScale = fontScale;
+    m_fontTable.SetFontScale(fontScale);
+}
+
+void wxRichTextBuffer::SetDimensionScale(double dimScale)
+{
+    m_dimensionScale = dimScale;
+}
+
 bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph* paragraph, wxDC& dc, const wxRichTextAttr& bulletAttr, const wxRect& rect)
 {
     if (bulletAttr.GetTextColour().IsOk())
@@ -8187,7 +8328,10 @@ bool wxRichTextStdRenderer::DrawTextBullet(wxRichTextParagraph* paragraph, wxDC&
         if ((attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL) && !attr.GetBulletFont().IsEmpty() && attr.HasFont())
         {
             wxRichTextAttr fontAttr;
-            fontAttr.SetFontSize(attr.GetFontSize());
+            if (attr.HasFontPixelSize())
+                fontAttr.SetFontPixelSize(attr.GetFontSize());
+            else
+                fontAttr.SetFontPointSize(attr.GetFontSize());
             fontAttr.SetFontStyle(attr.GetFontStyle());
             fontAttr.SetFontWeight(attr.GetFontWeight());
             fontAttr.SetFontUnderlined(attr.GetFontUnderlined());
@@ -8298,6 +8442,345 @@ bool wxRichTextBox::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
+/*!
+ * wxRichTextField
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextField, wxRichTextParagraphLayoutBox)
+
+wxRichTextField::wxRichTextField(const wxString& fieldType, wxRichTextObject* parent):
+    wxRichTextParagraphLayoutBox(parent)
+{
+    SetFieldType(fieldType);
+}
+
+/// Draw the item
+bool wxRichTextField::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
+{
+    if (!IsShown())
+        return true;
+
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType && fieldType->Draw(this, dc, context, range, selection, rect, descent, style))
+        return true;
+
+    // Fallback; but don't draw guidelines.
+    style &= ~wxRICHTEXT_DRAW_GUIDELINES;
+    return wxRichTextParagraphLayoutBox::Draw(dc, context, range, selection, rect, descent, style);
+}
+
+bool wxRichTextField::Layout(wxDC& dc, wxRichTextDrawingContext& context, const wxRect& rect, const wxRect& parentRect, int style)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType && fieldType->Layout(this, dc, context, rect, parentRect, style))
+        return true;
+
+    // Fallback
+    return wxRichTextParagraphLayoutBox::Layout(dc, context, rect, parentRect, style);
+}
+
+bool wxRichTextField::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->GetRangeSize((wxRichTextField*) this, range, size, descent, dc, context, flags, position, partialExtents);
+
+    return wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position, partialExtents);
+}
+
+/// Calculate range
+void wxRichTextField::CalculateRange(long start, long& end)
+{
+    if (IsTopLevel())
+        wxRichTextParagraphLayoutBox::CalculateRange(start, end);
+    else
+        wxRichTextObject::CalculateRange(start, end);
+}
+
+/// Copy
+void wxRichTextField::Copy(const wxRichTextField& obj)
+{
+    wxRichTextParagraphLayoutBox::Copy(obj);
+
+    UpdateField(GetBuffer());
+}
+
+// Edit properties via a GUI
+bool wxRichTextField::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->EditProperties(this, parent, buffer);
+
+    return false;
+}
+
+bool wxRichTextField::CanEditProperties() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->CanEditProperties((wxRichTextField*) this);
+
+    return false;
+}
+
+wxString wxRichTextField::GetPropertiesMenuLabel() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->GetPropertiesMenuLabel((wxRichTextField*) this);
+
+    return wxEmptyString;
+}
+
+bool wxRichTextField::UpdateField(wxRichTextBuffer* buffer)
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->UpdateField(buffer, (wxRichTextField*) this);
+
+    return false;
+}
+
+bool wxRichTextField::IsTopLevel() const
+{
+    wxRichTextFieldType* fieldType = wxRichTextBuffer::FindFieldType(GetFieldType());
+    if (fieldType)
+        return fieldType->IsTopLevel((wxRichTextField*) this);
+
+    return true;
+}
+
+IMPLEMENT_CLASS(wxRichTextFieldType, wxObject)
+
+IMPLEMENT_CLASS(wxRichTextFieldTypeStandard, wxRichTextFieldType)
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxString& label, int displayStyle)
+{
+    Init();
+
+    SetName(name);
+    SetLabel(label);
+    SetDisplayStyle(displayStyle);
+}
+
+wxRichTextFieldTypeStandard::wxRichTextFieldTypeStandard(const wxString& name, const wxBitmap& bitmap, int displayStyle)
+{
+    Init();
+
+    SetName(name);
+    SetBitmap(bitmap);
+    SetDisplayStyle(displayStyle);
+}
+
+void wxRichTextFieldTypeStandard::Init()
+{
+    m_displayStyle = wxRICHTEXT_FIELD_STYLE_RECTANGLE;
+    m_font = wxFont(6, wxFONTFAMILY_SWISS, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+    m_textColour = *wxWHITE;
+    m_borderColour = *wxBLACK;
+    m_backgroundColour = *wxBLACK;
+    m_verticalPadding = 1;
+    m_horizontalPadding = 3;
+    m_horizontalMargin = 2;
+    m_verticalMargin = 0;
+}
+
+void wxRichTextFieldTypeStandard::Copy(const wxRichTextFieldTypeStandard& field)
+{
+    wxRichTextFieldType::Copy(field);
+
+    m_label = field.m_label;
+    m_displayStyle = field.m_displayStyle;
+    m_font = field.m_font;
+    m_textColour = field.m_textColour;
+    m_borderColour = field.m_borderColour;
+    m_backgroundColour = field.m_backgroundColour;
+    m_verticalPadding = field.m_verticalPadding;
+    m_horizontalPadding = field.m_horizontalPadding;
+    m_horizontalMargin = field.m_horizontalMargin;
+    m_bitmap = field.m_bitmap;
+}
+
+bool wxRichTextFieldTypeStandard::Draw(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), const wxRichTextRange& WXUNUSED(range), const wxRichTextSelection& selection, const wxRect& rect, int descent, int WXUNUSED(style))
+{
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+        return false; // USe default composite drawing
+    else // if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE || m_displayStyle == wxRICHTEXT_FIELD_STYLE_NOBORDER)
+    {
+        int borderSize = 1;
+
+        wxPen borderPen(m_borderColour, 1, wxSOLID);
+        wxBrush backgroundBrush(m_backgroundColour);
+        wxColour textColour(m_textColour);
+
+        if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+        {
+            wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
+            wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+            borderPen = wxPen(highlightTextColour, 1, wxSOLID);
+            backgroundBrush = wxBrush(highlightColour);
+
+            wxCheckSetBrush(dc, backgroundBrush);
+            wxCheckSetPen(dc, wxPen(highlightColour, 1, wxSOLID));
+            dc.DrawRectangle(rect);
+        }
+
+        if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+            borderSize = 0;
+
+        // objectRect is the area where the content is drawn, after margins around it have been taken into account
+        wxRect objectRect = wxRect(wxPoint(rect.x + m_horizontalMargin, rect.y + wxMax(0, rect.height - descent - obj->GetCachedSize().y)),
+            wxSize(obj->GetCachedSize().x - 2*m_horizontalMargin - borderSize, obj->GetCachedSize().y));
+
+        // clientArea is where the text is actually written
+        wxRect clientArea = objectRect;
+
+        if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_RECTANGLE)
+        {
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawRoundedRectangle(objectRect, 4.0);
+        }
+        else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG)
+        {
+            int arrowLength = objectRect.height/2;
+            clientArea.width -= (arrowLength - m_horizontalPadding);
+
+            wxPoint pts[5];
+            pts[0].x = objectRect.x; pts[0].y = objectRect.y;
+            pts[1].x = objectRect.x + objectRect.width - arrowLength; pts[1].y = objectRect.y;
+            pts[2].x = objectRect.x + objectRect.width; pts[2].y = objectRect.y + (objectRect.height/2);
+            pts[3].x = objectRect.x + objectRect.width - arrowLength; pts[3].y = objectRect.y + objectRect.height;
+            pts[4].x = objectRect.x; pts[4].y = objectRect.y + objectRect.height;
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawPolygon(5, pts);
+        }
+        else if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+        {
+            int arrowLength = objectRect.height/2;
+            clientArea.width -= (arrowLength - m_horizontalPadding);
+            clientArea.x += (arrowLength - m_horizontalPadding);
+
+            wxPoint pts[5];
+            pts[0].x = objectRect.x + objectRect.width; pts[0].y = objectRect.y;
+            pts[1].x = objectRect.x + arrowLength; pts[1].y = objectRect.y;
+            pts[2].x = objectRect.x; pts[2].y = objectRect.y + (objectRect.height/2);
+            pts[3].x = objectRect.x + arrowLength; pts[3].y = objectRect.y + objectRect.height;
+            pts[4].x = objectRect.x + objectRect.width; pts[4].y = objectRect.y + objectRect.height;
+            dc.SetPen(borderPen);
+            dc.SetBrush(backgroundBrush);
+            dc.DrawPolygon(5, pts);
+        }
+
+        if (m_bitmap.IsOk())
+        {
+            int x = clientArea.x + (clientArea.width - m_bitmap.GetWidth())/2;
+            int y = clientArea.y + m_verticalPadding;
+            dc.DrawBitmap(m_bitmap, x, y, true);
+
+            if (selection.WithinSelection(obj->GetRange().GetStart(), obj))
+            {
+                wxCheckSetBrush(dc, *wxBLACK_BRUSH);
+                wxCheckSetPen(dc, *wxBLACK_PEN);
+                dc.SetLogicalFunction(wxINVERT);
+                dc.DrawRectangle(wxRect(x, y, m_bitmap.GetWidth(), m_bitmap.GetHeight()));
+                dc.SetLogicalFunction(wxCOPY);
+            }
+        }
+        else
+        {
+            wxString label(m_label);
+            if (label.IsEmpty())
+                label = wxT("??");
+            int w, h, maxDescent;
+            dc.SetFont(m_font);
+            dc.GetTextExtent(m_label, & w, &h, & maxDescent);
+            dc.SetTextForeground(textColour);
+
+            int x = clientArea.x + (clientArea.width - w)/2;
+            int y = clientArea.y + (clientArea.height - (h - maxDescent))/2;
+            dc.DrawText(m_label, x, y);
+        }
+    }
+
+    return true;
+}
+
+bool wxRichTextFieldTypeStandard::Layout(wxRichTextField* obj, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& WXUNUSED(rect), const wxRect& WXUNUSED(parentRect), int style)
+{
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_COMPOSITE)
+        return false; // USe default composite layout
+
+    wxSize size = GetSize(obj, dc, context, style);
+    obj->SetCachedSize(size);
+    obj->SetMinSize(size);
+    obj->SetMaxSize(size);
+    return true;
+}
+
+bool wxRichTextFieldTypeStandard::GetRangeSize(wxRichTextField* obj, const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, wxRichTextDrawingContext& context, int flags, wxPoint position, wxArrayInt* partialExtents) const
+{
+    if (IsTopLevel(obj))
+        return obj->wxRichTextParagraphLayoutBox::GetRangeSize(range, size, descent, dc, context, flags, position);
+    else
+    {
+        wxSize sz = GetSize(obj, dc, context, 0);
+        if (partialExtents)
+        {
+            int lastSize;
+            if (partialExtents->GetCount() > 0)
+                lastSize = (*partialExtents)[partialExtents->GetCount()-1];
+            else
+                lastSize = 0;
+            partialExtents->Add(lastSize + sz.x);
+        }
+        size = sz;
+       return true;
+    }
+}
+
+wxSize wxRichTextFieldTypeStandard::GetSize(wxRichTextField* WXUNUSED(obj), wxDC& dc, wxRichTextDrawingContext& WXUNUSED(context), int WXUNUSED(style)) const
+{
+    int borderSize = 1;
+    int w = 0, h = 0, maxDescent = 0;
+
+    wxSize sz;
+    if (m_bitmap.IsOk())
+    {
+        w = m_bitmap.GetWidth();
+        h = m_bitmap.GetHeight();
+
+        sz = wxSize(w + m_horizontalMargin*2, h + m_verticalMargin*2);
+    }
+    else
+    {
+        wxString label(m_label);
+        if (label.IsEmpty())
+            label = wxT("??");
+        dc.SetFont(m_font);
+        dc.GetTextExtent(label, & w, &h, & maxDescent);
+
+        sz = wxSize(w + m_horizontalPadding*2 + m_horizontalMargin*2, h + m_verticalPadding *2 + m_verticalMargin*2);
+    }
+
+    if (m_displayStyle != wxRICHTEXT_FIELD_STYLE_NO_BORDER)
+    {
+        sz.x += borderSize*2;
+        sz.y += borderSize*2;
+    }
+
+    if (m_displayStyle == wxRICHTEXT_FIELD_STYLE_START_TAG || m_displayStyle == wxRICHTEXT_FIELD_STYLE_END_TAG)
+    {
+        // Add space for the arrow
+        sz.x += (sz.y/2 - m_horizontalPadding);
+    }
+
+    return sz;
+}
+
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell, wxRichTextBox)
 
 wxRichTextCell::wxRichTextCell(wxRichTextObject* parent):
@@ -8362,7 +8845,7 @@ bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
     wxRichTextObjectPropertiesDialog cellDlg(this, wxGetTopLevelParent(parent), wxID_ANY, caption);
     cellDlg.SetAttributes(attr);
 
-    wxRichTextSizePage* sizePage = wxDynamicCast(cellDlg.FindPage(CLASSINFO(wxRichTextSizePage)), wxRichTextSizePage);
+    wxRichTextSizePage* sizePage = wxDynamicCast(cellDlg.FindPage(wxCLASSINFO(wxRichTextSizePage)), wxRichTextSizePage);
     if (sizePage)
     {
         // We don't want position and floating controls for a cell.
@@ -8484,7 +8967,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
     wxArrayInt absoluteColWidths;
     absoluteColWidths.Add(0, m_colCount);
-    // wxArrayInt absoluteColWidthsSpanning(m_colCount);
+
     wxArrayInt percentageColWidths;
     percentageColWidths.Add(0, m_colCount);
     // wxArrayInt percentageColWidthsSpanning(m_colCount);
@@ -9478,12 +9961,25 @@ public:
         wxRichTextBuffer::SetRenderer(new wxRichTextStdRenderer);
         wxRichTextBuffer::InitStandardHandlers();
         wxRichTextParagraph::InitDefaultTabs();
+
+        wxRichTextXMLHandler::RegisterNodeName(wxT("text"), wxT("wxRichTextPlainText"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("symbol"), wxT("wxRichTextPlainText"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("image"), wxT("wxRichTextImage"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("paragraph"), wxT("wxRichTextParagraph"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("paragraphlayout"), wxT("wxRichTextParagraphLayoutBox"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("textbox"), wxT("wxRichTextBox"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("cell"), wxT("wxRichTextCell"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("table"), wxT("wxRichTextTable"));
+        wxRichTextXMLHandler::RegisterNodeName(wxT("field"), wxT("wxRichTextField"));
+
         return true;
     }
     void OnExit()
     {
         wxRichTextBuffer::CleanUpHandlers();
         wxRichTextBuffer::CleanUpDrawingHandlers();
+        wxRichTextBuffer::CleanUpFieldTypes();
+        wxRichTextXMLHandler::ClearNodeToClassMap();
         wxRichTextDecimalToRoman(-1);
         wxRichTextParagraph::ClearDefaultTabs();
         wxRichTextCtrl::ClearAvailableFontNames();
@@ -9614,8 +10110,8 @@ void wxRichTextAction::CalculateRefreshOptimizations(wxArrayInt& optimizationLin
     // first, but of course this means we'll be doing it twice.
     if (!m_buffer->IsDirty() && m_ctrl) // can only do optimisation if the buffer is already laid out correctly
     {
-        wxSize clientSize = m_ctrl->GetClientSize();
-        wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+        wxSize clientSize = m_ctrl->GetUnscaledSize(m_ctrl->GetClientSize());
+        wxPoint firstVisiblePt = m_ctrl->GetUnscaledPoint(m_ctrl->GetFirstVisiblePoint());
         int lastY = firstVisiblePt.y + clientSize.y;
 
         wxRichTextParagraph* para = container->GetParagraphAtPosition(GetRange().GetStart());
@@ -9851,6 +10347,7 @@ bool wxRichTextAction::Undo()
 
             container->DeleteRange(GetRange());
             container->UpdateRanges();
+
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
@@ -9882,6 +10379,7 @@ bool wxRichTextAction::Undo()
 
             container->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
             container->UpdateRanges();
+
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             container->InvalidateHierarchy(GetRange());
@@ -9967,8 +10465,8 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
             {
                 size_t i;
 
-                wxSize clientSize = m_ctrl->GetClientSize();
-                wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
+                wxSize clientSize = m_ctrl->GetUnscaledSize(m_ctrl->GetClientSize());
+                wxPoint firstVisiblePt = m_ctrl->GetUnscaledPoint(m_ctrl->GetFirstVisiblePoint());
 
                 // Start/end positions
                 int firstY = 0;
@@ -10063,7 +10561,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
                     lastY = firstVisiblePt.y + clientSize.y;
 
                 // Convert to device coordinates
-                wxRect rect(m_ctrl->GetPhysicalPoint(wxPoint(firstVisiblePt.x, firstY)), wxSize(clientSize.x, lastY - firstY));
+                wxRect rect(m_ctrl->GetPhysicalPoint(m_ctrl->GetScaledPoint(wxPoint(firstVisiblePt.x, firstY))), m_ctrl->GetScaledSize(wxSize(clientSize.x, lastY - firstY)));
                 m_ctrl->RefreshRect(rect);
             }
             else
@@ -10477,12 +10975,6 @@ bool wxTextAttrEq(const wxRichTextAttr& attr1, const wxRichTextAttr& attr2)
     return (attr1 == attr2);
 }
 
-// Partial equality test taking flags into account
-bool wxTextAttrEqPartial(const wxRichTextAttr& attr1, const wxRichTextAttr& attr2)
-{
-    return attr1.EqPartial(attr2);
-}
-
 /// Compare tabs
 bool wxRichTextTabsEq(const wxArrayInt& tabs1, const wxArrayInt& tabs2)
 {
@@ -11097,22 +11589,48 @@ class wxRichTextFontTableData: public wxObjectRefData
 public:
     wxRichTextFontTableData() {}
 
-    wxFont FindFont(const wxRichTextAttr& fontSpec);
+    wxFont FindFont(const wxRichTextAttr& fontSpec, double fontScale);
 
     wxRichTextFontTableHashMap  m_hashMap;
 };
 
-wxFont wxRichTextFontTableData::FindFont(const wxRichTextAttr& fontSpec)
+wxFont wxRichTextFontTableData::FindFont(const wxRichTextAttr& fontSpec, double fontScale)
 {
     wxString facename(fontSpec.GetFontFaceName());
-    wxString spec(wxString::Format(wxT("%d-%d-%d-%d-%s-%d"), fontSpec.GetFontSize(), fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), (int) fontSpec.GetFontUnderlined(), facename.c_str(), (int) fontSpec.GetFontEncoding()));
-    wxRichTextFontTableHashMap::iterator entry = m_hashMap.find(spec);
 
+    int fontSize = fontSpec.GetFontSize();
+    if (fontScale != 1.0)
+        fontSize = (int) ((double(fontSize) * fontScale) + 0.5);
+
+    wxString units;
+    if (fontSpec.HasFontPixelSize() && !fontSpec.HasFontPointSize())
+        units = wxT("px");
+    else
+        units = wxT("pt");
+    wxString spec = wxString::Format(wxT("%d-%s-%d-%d-%d-%d-%s-%d"),
+        fontSize, units.c_str(), fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), (int) fontSpec.GetFontUnderlined(), (int) fontSpec.GetFontStrikethrough(),
+        facename.c_str(), (int) fontSpec.GetFontEncoding());
+
+    wxRichTextFontTableHashMap::iterator entry = m_hashMap.find(spec);
     if ( entry == m_hashMap.end() )
     {
-        wxFont font(fontSpec.GetFontSize(), wxDEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename.c_str());
-        m_hashMap[spec] = font;
-        return font;
+        if (fontSpec.HasFontPixelSize() && !fontSpec.HasFontPointSize())
+        {
+            wxFont font(wxSize(0, fontSize), wxFONTFAMILY_DEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename);
+            if (fontSpec.HasFontStrikethrough() && fontSpec.GetFontStrikethrough())
+                font.SetStrikethrough(true);
+            m_hashMap[spec] = font;
+            return font;
+        }
+        else
+        {
+            wxFont font(fontSize, wxFONTFAMILY_DEFAULT, fontSpec.GetFontStyle(), fontSpec.GetFontWeight(), fontSpec.GetFontUnderlined(), facename.c_str());
+            if (fontSpec.HasFontStrikethrough() && fontSpec.GetFontStrikethrough())
+                font.SetStrikethrough(true);
+
+            m_hashMap[spec] = font;
+            return font;
+        }
     }
     else
     {
@@ -11125,6 +11643,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichTextFontTable, wxObject)
 wxRichTextFontTable::wxRichTextFontTable()
 {
     m_refData = new wxRichTextFontTableData;
+    m_fontScale = 1.0;
 }
 
 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)
@@ -11146,13 +11665,14 @@ bool wxRichTextFontTable::operator == (const wxRichTextFontTable& table) const
 void wxRichTextFontTable::operator= (const wxRichTextFontTable& table)
 {
     Ref(table);
+    m_fontScale = table.m_fontScale;
 }
 
 wxFont wxRichTextFontTable::FindFont(const wxRichTextAttr& fontSpec)
 {
     wxRichTextFontTableData* data = (wxRichTextFontTableData*) m_refData;
     if (data)
-        return data->FindFont(fontSpec);
+        return data->FindFont(fontSpec, m_fontScale);
     else
         return wxFont();
 }
@@ -11164,8 +11684,14 @@ void wxRichTextFontTable::Clear()
         data->m_hashMap.clear();
 }
 
-// wxTextBoxAttr
+void wxRichTextFontTable::SetFontScale(double fontScale)
+{
+    if (fontScale != m_fontScale)
+        Clear();
+    m_fontScale = fontScale;
+}
 
+// wxTextBoxAttr
 
 void wxTextBoxAttr::Reset()
 {
@@ -11214,8 +11740,17 @@ bool wxTextBoxAttr::operator== (const wxTextBoxAttr& attr) const
 }
 
 // Partial equality test
-bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr) const
+bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr, bool weakTest) const
 {
+    if (!weakTest &&
+            ((!HasFloatMode() && attr.HasFloatMode()) ||
+             (!HasClearMode() && attr.HasClearMode()) ||
+             (!HasCollapseBorders() && attr.HasCollapseBorders()) ||
+             (!HasVerticalAlignment() && attr.HasVerticalAlignment()) ||
+             (!HasBoxStyleName() && attr.HasBoxStyleName())))
+    {
+        return false;
+    }
     if (attr.HasFloatMode() && HasFloatMode() && (GetFloatMode() != attr.GetFloatMode()))
         return false;
 
@@ -11233,36 +11768,36 @@ bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr& attr) const
 
     // Position
 
-    if (!m_position.EqPartial(attr.m_position))
+    if (!m_position.EqPartial(attr.m_position, weakTest))
         return false;
 
     // Size
 
-    if (!m_size.EqPartial(attr.m_size))
+    if (!m_size.EqPartial(attr.m_size, weakTest))
         return false;
-    if (!m_minSize.EqPartial(attr.m_minSize))
+    if (!m_minSize.EqPartial(attr.m_minSize, weakTest))
         return false;
-    if (!m_maxSize.EqPartial(attr.m_maxSize))
+    if (!m_maxSize.EqPartial(attr.m_maxSize, weakTest))
         return false;
 
     // Margins
 
-    if (!m_margins.EqPartial(attr.m_margins))
+    if (!m_margins.EqPartial(attr.m_margins, weakTest))
         return false;
 
     // Padding
 
-    if (!m_padding.EqPartial(attr.m_padding))
+    if (!m_padding.EqPartial(attr.m_padding, weakTest))
         return false;
 
     // Border
 
-    if (!GetBorder().EqPartial(attr.GetBorder()))
+    if (!GetBorder().EqPartial(attr.GetBorder(), weakTest))
         return false;
 
     // Outline
 
-    if (!GetOutline().EqPartial(attr.GetOutline()))
+    if (!GetOutline().EqPartial(attr.GetOutline(), weakTest))
         return false;
 
     return true;
@@ -11487,13 +12022,13 @@ bool wxRichTextAttr::operator==(const wxRichTextAttr& attr) const
     return (m_textBoxAttr == attr.m_textBoxAttr);
 }
 
-// Partial equality test taking comparison object into account
-bool wxRichTextAttr::EqPartial(const wxRichTextAttr& attr) const
+// Partial equality test
+bool wxRichTextAttr::EqPartial(const wxRichTextAttr& attr, bool weakTest) const
 {
-    if (!(wxTextAttr::EqPartial(attr)))
+    if (!(wxTextAttr::EqPartial(attr, weakTest)))
         return false;
 
-    return m_textBoxAttr.EqPartial(attr.m_textBoxAttr);
+    return m_textBoxAttr.EqPartial(attr.m_textBoxAttr, weakTest);
 }
 
 // Merges the given attributes. If compareWith
@@ -11524,15 +12059,23 @@ void wxRichTextAttr::CollectCommonAttributes(const wxRichTextAttr& attr, wxRichT
 }
 
 // Partial equality test
-bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border) const
+bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder& border, bool weakTest) const
 {
-    if (border.HasStyle() && !HasStyle() && (border.GetStyle() != GetStyle()))
+    if (!weakTest &&
+        ((!HasStyle() && border.HasStyle()) ||
+         (!HasColour() && border.HasColour()) ||
+         (!HasWidth() && border.HasWidth())))
+    {
+        return false;
+    }
+
+    if (border.HasStyle() && HasStyle() && (border.GetStyle() != GetStyle()))
         return false;
 
-    if (border.HasColour() && !HasColour() && (border.GetColourLong() != GetColourLong()))
+    if (border.HasColour() && HasColour() && (border.GetColourLong() != GetColourLong()))
         return false;
 
-    if (border.HasWidth() && !HasWidth() && !(border.GetWidth() == GetWidth()))
+    if (border.HasWidth() && HasWidth() && !(border.GetWidth() == GetWidth()))
         return false;
 
     return true;
@@ -11619,10 +12162,10 @@ void wxTextAttrBorder::CollectCommonAttributes(const wxTextAttrBorder& attr, wxT
 }
 
 // Partial equality test
-bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders) const
+bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders& borders, bool weakTest) const
 {
-    return m_left.EqPartial(borders.m_left) && m_right.EqPartial(borders.m_right) &&
-            m_top.EqPartial(borders.m_top) && m_bottom.EqPartial(borders.m_bottom);
+    return m_left.EqPartial(borders.m_left, weakTest) && m_right.EqPartial(borders.m_right, weakTest) &&
+            m_top.EqPartial(borders.m_top, weakTest) && m_bottom.EqPartial(borders.m_bottom, weakTest);
 }
 
 // Apply border to 'this', but not if the same as compareWith
@@ -11691,8 +12234,11 @@ void wxTextAttrBorders::SetWidth(const wxTextAttrDimension& width)
 }
 
 // Partial equality test
-bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension& dim) const
+bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension& dim, bool weakTest) const
 {
+    if (!weakTest && !IsValid() && dim.IsValid())
+        return false;
+
     if (dim.IsValid() && IsValid() && !((*this) == dim))
         return false;
     else
@@ -11789,18 +12335,18 @@ int wxTextAttrDimensionConverter::GetTenthsMM(const wxTextAttrDimension& dim) co
 }
 
 // Partial equality test
-bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims) const
+bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions& dims, bool weakTest) const
 {
-    if (!m_left.EqPartial(dims.m_left))
+    if (!m_left.EqPartial(dims.m_left, weakTest))
         return false;
 
-    if (!m_right.EqPartial(dims.m_right))
+    if (!m_right.EqPartial(dims.m_right, weakTest))
         return false;
 
-    if (!m_top.EqPartial(dims.m_top))
+    if (!m_top.EqPartial(dims.m_top, weakTest))
         return false;
 
-    if (!m_bottom.EqPartial(dims.m_bottom))
+    if (!m_bottom.EqPartial(dims.m_bottom, weakTest))
         return false;
 
     return true;
@@ -11843,12 +12389,12 @@ void wxTextAttrDimensions::CollectCommonAttributes(const wxTextAttrDimensions& a
 }
 
 // Partial equality test
-bool wxTextAttrSize::EqPartial(const wxTextAttrSize& size) const
+bool wxTextAttrSize::EqPartial(const wxTextAttrSize& size, bool weakTest) const
 {
-    if (!m_width.EqPartial(size.m_width))
+    if (!m_width.EqPartial(size.m_width, weakTest))
         return false;
 
-    if (!m_height.EqPartial(size.m_height))
+    if (!m_height.EqPartial(size.m_height, weakTest))
         return false;
 
     return true;
@@ -11893,19 +12439,44 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
 
     if (attr.HasFont())
     {
-        if (attr.HasFontSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_SIZE))
+        // If different font size units are being used, this is a clash.
+        if (((attr.GetFlags() & wxTEXT_ATTR_FONT_SIZE) | (currentStyle.GetFlags() & wxTEXT_ATTR_FONT_SIZE)) == wxTEXT_ATTR_FONT_SIZE)
         {
-            if (currentStyle.HasFontSize())
+            currentStyle.SetFontSize(0);
+            currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_SIZE);
+            clashingAttr.AddFlag(wxTEXT_ATTR_FONT_SIZE);
+        }
+        else
+        {
+            if (attr.HasFontPointSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_POINT_SIZE))
             {
-                if (currentStyle.GetFontSize() != attr.GetFontSize())
+                if (currentStyle.HasFontPointSize())
                 {
-                    // Clash of attr - mark as such
-                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_SIZE);
-                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_SIZE);
+                    if (currentStyle.GetFontSize() != attr.GetFontSize())
+                    {
+                        // Clash of attr - mark as such
+                        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+                        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_POINT_SIZE);
+                    }
                 }
+                else
+                    currentStyle.SetFontSize(attr.GetFontSize());
+            }
+
+            if (attr.HasFontPixelSize() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_PIXEL_SIZE))
+            {
+                if (currentStyle.HasFontPixelSize())
+                {
+                    if (currentStyle.GetFontSize() != attr.GetFontSize())
+                    {
+                        // Clash of attr - mark as such
+                        clashingAttr.AddFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
+                        currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_PIXEL_SIZE);
+                    }
+                }
+                else
+                    currentStyle.SetFontPixelSize(attr.GetFontSize());
             }
-            else
-                currentStyle.SetFontSize(attr.GetFontSize());
         }
 
         if (attr.HasFontItalic() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_ITALIC))
@@ -11985,6 +12556,21 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
             else
                 currentStyle.SetFontUnderlined(attr.GetFontUnderlined());
         }
+
+        if (attr.HasFontStrikethrough() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_FONT_STRIKETHROUGH))
+        {
+            if (currentStyle.HasFontStrikethrough())
+            {
+                if (currentStyle.GetFontStrikethrough() != attr.GetFontStrikethrough())
+                {
+                    // Clash of attr - mark as such
+                    clashingAttr.AddFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+                    currentStyle.RemoveFlag(wxTEXT_ATTR_FONT_STRIKETHROUGH);
+                }
+            }
+            else
+                currentStyle.SetFontStrikethrough(attr.GetFontStrikethrough());
+        }
     }
 
     if (attr.HasTextColour() && !wxHasStyle(forbiddenFlags, wxTEXT_ATTR_TEXT_COLOUR))
@@ -12718,5 +13304,45 @@ void wxRichTextBuffer::CleanUpDrawingHandlers()
     sm_drawingHandlers.Clear();
 }
 
+void wxRichTextBuffer::AddFieldType(wxRichTextFieldType *fieldType)
+{
+    sm_fieldTypes[fieldType->GetName()] = fieldType;
+}
+
+bool wxRichTextBuffer::RemoveFieldType(const wxString& name)
+{
+    wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+    if (it == sm_fieldTypes.end())
+        return false;
+    else
+    {
+        wxRichTextFieldType* fieldType = it->second;
+        sm_fieldTypes.erase(it);
+        delete fieldType;
+        return true;
+    }
+}
+
+wxRichTextFieldType *wxRichTextBuffer::FindFieldType(const wxString& name)
+{
+    wxRichTextFieldTypeHashMap::iterator it = sm_fieldTypes.find(name);
+    if (it == sm_fieldTypes.end())
+        return NULL;
+    else
+        return it->second;
+}
+
+void wxRichTextBuffer::CleanUpFieldTypes()
+{
+    wxRichTextFieldTypeHashMap::iterator it;
+    for( it = sm_fieldTypes.begin(); it != sm_fieldTypes.end(); ++it )
+    {
+        wxRichTextFieldType* fieldType = it->second;
+        delete fieldType;
+    }
+
+    sm_fieldTypes.clear();
+}
+
 #endif
     // wxUSE_RICHTEXT