diff --git a/include/wx/html/htmlcell.h b/include/wx/html/htmlcell.h
index 282b7cd964..083ebd8e63 100644
--- a/include/wx/html/htmlcell.h
+++ b/include/wx/html/htmlcell.h
@@ -445,7 +445,7 @@ protected:
class WXDLLIMPEXP_HTML wxHtmlContainerCell : public wxHtmlCell
{
public:
- wxHtmlContainerCell(wxHtmlContainerCell *parent);
+ explicit wxHtmlContainerCell(wxHtmlContainerCell *parent);
virtual ~wxHtmlContainerCell();
virtual void Layout(int w) wxOVERRIDE;
@@ -459,6 +459,11 @@ public:
// insert cell at the end of m_Cells list
void InsertCell(wxHtmlCell *cell);
+ // Detach a child cell. After calling this method, it's the caller
+ // responsibility to destroy this cell (possibly by calling InsertCell()
+ // with it to attach it elsewhere).
+ void Detach(wxHtmlCell *cell);
+
// sets horizontal/vertical alignment
void SetAlignHor(int al) {m_AlignHor = al; m_LastLayout = -1;}
int GetAlignHor() const {return m_AlignHor;}
diff --git a/include/wx/html/htmprint.h b/include/wx/html/htmprint.h
index 0c206ade6c..554413d44c 100644
--- a/include/wx/html/htmprint.h
+++ b/include/wx/html/htmprint.h
@@ -54,6 +54,11 @@ public:
// (see wxFileSystem for detailed explanation)
void SetHtmlText(const wxString& html, const wxString& basepath = wxEmptyString, bool isdir = true);
+ // Sets the HTML cell that will be rendered: this is more efficient than
+ // using text as it allows to parse it only once. Note that the cell will
+ // be modified by this call.
+ void SetHtmlCell(wxHtmlContainerCell& cell);
+
// Sets fonts to be used when displaying HTML page. (if size null then default sizes used).
void SetFonts(const wxString& normal_face, const wxString& fixed_face, const int *sizes = NULL);
@@ -79,11 +84,14 @@ public:
int GetTotalHeight() const;
private:
+ void DoSetHtmlCell(wxHtmlContainerCell* cell);
+
wxDC *m_DC;
- wxHtmlWinParser *m_Parser;
- wxFileSystem *m_FS;
+ wxFileSystem m_FS;
+ wxHtmlWinParser m_Parser;
wxHtmlContainerCell *m_Cells;
int m_Width, m_Height;
+ bool m_ownsCells;
wxDECLARE_NO_COPY_CLASS(wxHtmlDCRenderer);
};
diff --git a/interface/wx/html/htmlcell.h b/interface/wx/html/htmlcell.h
index 18b05a8a00..2f64f36556 100644
--- a/interface/wx/html/htmlcell.h
+++ b/interface/wx/html/htmlcell.h
@@ -471,7 +471,21 @@ public:
/**
Constructor. @a parent is pointer to parent container or @NULL.
*/
- wxHtmlContainerCell(wxHtmlContainerCell* parent);
+ explicit wxHtmlContainerCell(wxHtmlContainerCell* parent);
+
+ /**
+ Detach a child cell.
+
+ Detaching a cell removes it from this container and allows to reattach
+ it to another one by using InsertCell(). Alternatively, this method can
+ be used to selectively remove some elements of the HTML document tree
+ by deleting the cell after calling it.
+
+ @param cell Must be non-null and an immediate child of this cell.
+
+ @since 3.1.2
+ */
+ void Detach(wxHtmlCell* cell);
/**
Returns container's horizontal alignment.
@@ -506,6 +520,9 @@ public:
/**
Inserts a new cell into the container.
+
+ Note that the container takes ownership of the cell and will delete it
+ when it itself is destroyed.
*/
void InsertCell(wxHtmlCell* cell);
diff --git a/interface/wx/html/htmprint.h b/interface/wx/html/htmprint.h
index 8e2dfdc9db..1b4a4e861b 100644
--- a/interface/wx/html/htmprint.h
+++ b/interface/wx/html/htmprint.h
@@ -168,6 +168,19 @@ public:
const wxString& basepath = wxEmptyString,
bool isdir = true);
+ /**
+ Associate the given HTML contents to the renderer.
+
+ This is similar to SetHtmlText(), but is more efficient as the text can
+ be parsed only once, using wxHtmlParser::Parse(), and then passed to
+ wxHtmlDCRenderer multiple times or already reused for other purposes.
+
+ Note that @a cell will be modified (e.g. laid out) by this function.
+
+ @since 3.1.2
+ */
+ void SetHtmlCell(wxHtmlContainerCell& cell);
+
/**
Set size of output rectangle, in pixels. Note that you @b can't change
width of the rectangle between calls to Render() !
diff --git a/src/html/htmlcell.cpp b/src/html/htmlcell.cpp
index e4392edc35..1768178b65 100644
--- a/src/html/htmlcell.cpp
+++ b/src/html/htmlcell.cpp
@@ -1159,6 +1159,43 @@ void wxHtmlContainerCell::InsertCell(wxHtmlCell *f)
+void wxHtmlContainerCell::Detach(wxHtmlCell *cell)
+{
+ wxHtmlCell* const firstChild = GetFirstChild();
+ if ( cell == firstChild )
+ {
+ m_Cells = cell->GetNext();
+ if ( m_LastCell == cell )
+ m_LastCell = NULL;
+ }
+ else // Not the first child.
+ {
+ for ( wxHtmlCell* prev = firstChild;; )
+ {
+ wxHtmlCell* const next = prev->GetNext();
+
+ // We can't reach the end of the children list without finding this
+ // cell, normally.
+ wxCHECK_RET( next, "Detaching cell which is not our child" );
+
+ if ( cell == next )
+ {
+ prev->SetNext(cell->GetNext());
+ if ( m_LastCell == cell )
+ m_LastCell = prev;
+ break;
+ }
+
+ prev = next;
+ }
+ }
+
+ cell->SetParent(NULL);
+ cell->SetNext(NULL);
+}
+
+
+
void wxHtmlContainerCell::SetAlign(const wxHtmlTag& tag)
{
wxString alg;
diff --git a/src/html/htmprint.cpp b/src/html/htmprint.cpp
index a3acb7d007..2ed4e19256 100644
--- a/src/html/htmprint.cpp
+++ b/src/html/htmprint.cpp
@@ -70,9 +70,8 @@ wxHtmlDCRenderer::wxHtmlDCRenderer() : wxObject()
m_DC = NULL;
m_Width = m_Height = 0;
m_Cells = NULL;
- m_Parser = new wxHtmlWinParser();
- m_FS = new wxFileSystem();
- m_Parser->SetFS(m_FS);
+ m_ownsCells = false;
+ m_Parser.SetFS(&m_FS);
SetStandardFonts(DEFAULT_PRINT_FONT_SIZE);
}
@@ -80,9 +79,8 @@ wxHtmlDCRenderer::wxHtmlDCRenderer() : wxObject()
wxHtmlDCRenderer::~wxHtmlDCRenderer()
{
- if (m_Cells) delete m_Cells;
- if (m_Parser) delete m_Parser;
- if (m_FS) delete m_FS;
+ if ( m_ownsCells )
+ delete m_Cells;
}
@@ -90,7 +88,7 @@ wxHtmlDCRenderer::~wxHtmlDCRenderer()
void wxHtmlDCRenderer::SetDC(wxDC *dc, double pixel_scale, double font_scale)
{
m_DC = dc;
- m_Parser->SetDC(m_DC, pixel_scale, font_scale);
+ m_Parser.SetDC(m_DC, pixel_scale, font_scale);
}
@@ -110,19 +108,38 @@ void wxHtmlDCRenderer::SetHtmlText(const wxString& html, const wxString& basepat
wxCHECK_RET( m_DC, "SetDC() must be called before SetHtmlText()" );
wxCHECK_RET( m_Width, "SetSize() must be called before SetHtmlText()" );
- wxDELETE(m_Cells);
+ m_FS.ChangePathTo(basepath, isdir);
- m_FS->ChangePathTo(basepath, isdir);
- m_Cells = (wxHtmlContainerCell*) m_Parser->Parse(html);
+ wxHtmlContainerCell* const cell = (wxHtmlContainerCell*) m_Parser.Parse(html);
+ wxCHECK_RET( cell, "Failed to parse HTML" );
+
+ DoSetHtmlCell(cell);
+
+ m_ownsCells = true;
+}
+
+void wxHtmlDCRenderer::DoSetHtmlCell(wxHtmlContainerCell* cell)
+{
+ if ( m_ownsCells )
+ delete m_Cells;
+
+ m_Cells = cell;
m_Cells->SetIndent(0, wxHTML_INDENT_ALL, wxHTML_UNITS_PIXELS);
m_Cells->Layout(m_Width);
}
+void wxHtmlDCRenderer::SetHtmlCell(wxHtmlContainerCell& cell)
+{
+ DoSetHtmlCell(&cell);
+
+ m_ownsCells = false;
+}
+
void wxHtmlDCRenderer::SetFonts(const wxString& normal_face, const wxString& fixed_face,
const int *sizes)
{
- m_Parser->SetFonts(normal_face, fixed_face, sizes);
+ m_Parser.SetFonts(normal_face, fixed_face, sizes);
if ( m_Cells )
m_Cells->Layout(m_Width);
@@ -133,7 +150,7 @@ void wxHtmlDCRenderer::SetStandardFonts(int size,
const wxString& normal_face,
const wxString& fixed_face)
{
- m_Parser->SetStandardFonts(size, normal_face, fixed_face);
+ m_Parser.SetStandardFonts(size, normal_face, fixed_face);
if ( m_Cells )
m_Cells->Layout(m_Width);
diff --git a/tests/html/htmlparser.cpp b/tests/html/htmlparser.cpp
index 29c3cb5c1f..61042a4616 100644
--- a/tests/html/htmlparser.cpp
+++ b/tests/html/htmlparser.cpp
@@ -24,37 +24,8 @@
#include "wx/html/winpars.h"
-// ----------------------------------------------------------------------------
-// test class
-// ----------------------------------------------------------------------------
-
-class HtmlParserTestCase : public CppUnit::TestCase
-{
-public:
- HtmlParserTestCase() { }
-
-private:
- CPPUNIT_TEST_SUITE( HtmlParserTestCase );
- CPPUNIT_TEST( Invalid );
- CPPUNIT_TEST_SUITE_END();
-
- void Invalid();
-
- wxDECLARE_NO_COPY_CLASS(HtmlParserTestCase);
-};
-
-// register in the unnamed registry so that these tests are run by default
-CPPUNIT_TEST_SUITE_REGISTRATION( HtmlParserTestCase );
-
-// also include in its own registry so that these tests can be run alone
-CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( HtmlParserTestCase, "HtmlParserTestCase" );
-
-// ----------------------------------------------------------------------------
-// tests themselves
-// ----------------------------------------------------------------------------
-
// Test that parsing invalid HTML simply fails but doesn't crash for example.
-void HtmlParserTestCase::Invalid()
+TEST_CASE("wxHtmlParser::ParseInvalid", "[html][parser][error]")
{
class NullParser : public wxHtmlWinParser
{
@@ -75,4 +46,64 @@ void HtmlParserTestCase::Invalid()
p.Parse("