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("