X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/66a77a748e5c8002f3f9ebd66f5457aca5aabad8..a5de860f0b8994b2d87d0a0d3c3dedf750fa7ddb:/src/html/m_layout.cpp diff --git a/src/html/m_layout.cpp b/src/html/m_layout.cpp index 749df786da..1bea340201 100644 --- a/src/html/m_layout.cpp +++ b/src/html/m_layout.cpp @@ -1,48 +1,149 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: mod_layout.cpp +// Name: src/html/m_layout.cpp // Purpose: wxHtml module for basic paragraphs/layout handling // Author: Vaclav Slavik // RCS-ID: $Id$ // Copyright: (c) 1999 Vaclav Slavik -// Licence: wxWindows Licence +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation -#endif #include "wx/wxprec.h" - -#include "wx/defs.h" -#if wxUSE_HTML -#ifdef __BORDLANDC__ -#pragma hdrstop +#ifdef __BORLANDC__ + #pragma hdrstop #endif -#ifndef WXPRECOMP -#include "wx/wx.h" -#endif +#if wxUSE_HTML && wxUSE_STREAMS +#ifndef WX_PRECOMP + #include "wx/image.h" +#endif #include "wx/html/forcelnk.h" #include "wx/html/m_templ.h" #include "wx/html/htmlwin.h" -FORCE_LINK_ME(mod_layout) +FORCE_LINK_ME(m_layout) + +#ifdef __WXWINCE__ + #include "wx/msw/wince/missing.h" // for bsearch() +#else + #include // bsearch() +#endif + +//----------------------------------------------------------------------------- +// wxHtmlPageBreakCell +//----------------------------------------------------------------------------- + +// Since html isn't a page-layout language, it doesn't support page +// page breaks directly--that requires CSS2 support. But a page-break +// facility is handy, and has been requested more than once on the +// mailing lists. This wxHtml tag handler implements just enough of +// CSS2 to support a page break by recognizing only +//
+// +// wxHtml maintains page breaks in wxHtmlPrintout::m_PageBreaks. The +// tag handler below adds appropriate offsets to that array member. +// wxHtmlDCRenderer::Render() accesses that array and makes a new page +// begin after each page-break tag. + +// The page-break handler does all its work in AdjustPagebreak(). For +// all tag handlers, that function adjusts the page-break position. +// For other tags, it determines whether the html element can fit on +// the remainder of the page; if it cannot fit, but must not be split, +// then the function moves the page break provided in the argument up, +// and returns 'true' to inform the caller that the argument was +// modified. +// +// Due to its special purpose, the page-break facility differs from +// other tags. It takes up no space, but it behaves as though there is +// never enough room to fit it on the remainder of the page--it always +// forces a page break. Therefore, unlike other elements that trigger +// a page break, it would never 'fit' on the following page either. +// Therefore it's necessary to compare each pagebreak candidate to the +// array wxHtmlPrintout::m_PageBreaks of pagebreaks already set, and +// set a new one only if it's not in that array. + +class wxHtmlPageBreakCell : public wxHtmlCell +{ +public: + wxHtmlPageBreakCell() {} + + bool AdjustPagebreak(int* pagebreak, + wxArrayInt& known_pagebreaks) const; + + void Draw(wxDC& WXUNUSED(dc), + int WXUNUSED(x), int WXUNUSED(y), + int WXUNUSED(view_y1), int WXUNUSED(view_y2), + wxHtmlRenderingInfo& WXUNUSED(info)) {} + +private: + DECLARE_NO_COPY_CLASS(wxHtmlPageBreakCell) +}; + +// Comparison routine for bsearch into an int* array of pagebreaks. +extern "C" int wxCMPFUNC_CONV wxInteger_compare(void const* i0, void const* i1) +{ + return *(int*)i0 - *(int*)i1; +} + +bool wxHtmlPageBreakCell::AdjustPagebreak(int* pagebreak, wxArrayInt& known_pagebreaks) const +{ + // When we are counting pages, 'known_pagebreaks' is non-NULL. + // That's the only time we change 'pagebreak'. Otherwise, pages + // were already counted, 'known_pagebreaks' is NULL, and we don't + // do anything except return false. + // + // We also simply return false if the 'pagebreak' argument is + // less than (vertically above) or the same as the current + // vertical position. Otherwise we'd be setting a pagebreak above + // the current cell, which is incorrect, or duplicating a + // pagebreak that has already been set. + if( known_pagebreaks.GetCount() == 0 || *pagebreak <= m_PosY) + { + return false; + } + + // m_PosY is only the vertical offset from the parent. The pagebreak + // required here is the total page offset, so m_PosY must be added + // to the parent's offset and height. + int total_height = m_PosY + GetParent()->GetPosY() + GetParent()->GetHeight(); + + // Search the array of pagebreaks to see whether we've already set + // a pagebreak here. The standard bsearch() function is appropriate + // because the array of pagebreaks through known_pagebreaks[number_of_pages] + // is known to be sorted in strictly increasing order. '1 + number_of_pages' + // is used as a bsearch() argument because the array contains a leading + // zero plus one element for each page. + int where = known_pagebreaks.Index( total_height); + // Add a pagebreak only if there isn't one already set here. + if( wxNOT_FOUND != where) + { + return false; + } + else + { + *pagebreak = m_PosY; + return true; + } +} + TAG_HANDLER_BEGIN(P, "P") + TAG_HANDLER_CONSTR(P) { } TAG_HANDLER_PROC(tag) { - if (m_WParser -> GetContainer() -> GetFirstCell() != NULL) { - m_WParser -> CloseContainer(); - m_WParser -> OpenContainer(); - } - m_WParser -> GetContainer() -> SetIndent(m_WParser -> GetCharHeight(), wxHTML_INDENT_TOP); - m_WParser -> GetContainer() -> SetAlign(tag); - return FALSE; + if (m_WParser->GetContainer()->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + } + m_WParser->GetContainer()->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP); + m_WParser->GetContainer()->SetAlign(tag); + return false; } TAG_HANDLER_END(P) @@ -50,17 +151,19 @@ TAG_HANDLER_END(P) TAG_HANDLER_BEGIN(BR, "BR") + TAG_HANDLER_CONSTR(BR) { } TAG_HANDLER_PROC(tag) { - int al = m_WParser -> GetContainer() -> GetAlignHor(); + int al = m_WParser->GetContainer()->GetAlignHor(); wxHtmlContainerCell *c; - - m_WParser -> CloseContainer(); - c = m_WParser -> OpenContainer(); - c -> SetAlignHor(al); - c -> SetAlign(tag); - return FALSE; + + m_WParser->CloseContainer(); + c = m_WParser->OpenContainer(); + c->SetAlignHor(al); + c->SetAlign(tag); + c->SetMinHeight(m_WParser->GetCharHeight()); + return false; } TAG_HANDLER_END(BR) @@ -68,34 +171,38 @@ TAG_HANDLER_END(BR) TAG_HANDLER_BEGIN(CENTER, "CENTER") + TAG_HANDLER_CONSTR(CENTER) { } TAG_HANDLER_PROC(tag) { - int old = m_WParser -> GetAlign(); - wxHtmlContainerCell *c = m_WParser -> GetContainer(); - - m_WParser -> SetAlign(wxHTML_ALIGN_CENTER); - if (c -> GetFirstCell() != NULL) { - m_WParser -> CloseContainer(); - m_WParser -> OpenContainer(); + int old = m_WParser->GetAlign(); + wxHtmlContainerCell *c = m_WParser->GetContainer(); + + m_WParser->SetAlign(wxHTML_ALIGN_CENTER); + if (c->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); } else - c -> SetAlignHor(wxHTML_ALIGN_CENTER); + c->SetAlignHor(wxHTML_ALIGN_CENTER); - if (tag.HasEnding()) { + if (tag.HasEnding()) + { ParseInner(tag); - m_WParser -> SetAlign(old); - if (c -> GetFirstCell() != NULL) { - m_WParser -> CloseContainer(); - m_WParser -> OpenContainer(); + m_WParser->SetAlign(old); + if (c->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); } else - c -> SetAlignHor(old); + c->SetAlignHor(old); - return TRUE; + return true; } - else return FALSE; + else return false; } TAG_HANDLER_END(CENTER) @@ -103,34 +210,70 @@ TAG_HANDLER_END(CENTER) TAG_HANDLER_BEGIN(DIV, "DIV") + TAG_HANDLER_CONSTR(DIV) { } TAG_HANDLER_PROC(tag) { - int old = m_WParser -> GetAlign(); - wxHtmlContainerCell *c = m_WParser -> GetContainer(); - if (c -> GetFirstCell() != NULL) { - m_WParser -> CloseContainer(); - m_WParser -> OpenContainer(); - c = m_WParser -> GetContainer(); - c -> SetAlign(tag); - m_WParser -> SetAlign(c -> GetAlignHor()); - } - else { - c -> SetAlign(tag); - m_WParser -> SetAlign(c -> GetAlignHor()); + if(tag.HasParam(wxT("STYLE"))) + { + if(tag.GetParam(wxT("STYLE")).IsSameAs(wxT("PAGE-BREAK-BEFORE:ALWAYS"), false)) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer()->InsertCell(new wxHtmlPageBreakCell); + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + return false; + } + else + { + // Treat other STYLE parameters here when they're supported. + return false; + } } + else if(tag.HasParam(wxT("ALIGN"))) + { + int old = m_WParser->GetAlign(); + wxHtmlContainerCell *c = m_WParser->GetContainer(); + if (c->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + c = m_WParser->GetContainer(); + c->SetAlign(tag); + m_WParser->SetAlign(c->GetAlignHor()); + } + else + { + c->SetAlign(tag); + m_WParser->SetAlign(c->GetAlignHor()); + } - ParseInner(tag); + ParseInner(tag); + + m_WParser->SetAlign(old); + if (c->GetFirstChild() != NULL) + { + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + } + else + c->SetAlignHor(old); - m_WParser -> SetAlign(old); - if (c -> GetFirstCell() != NULL) { - m_WParser -> CloseContainer(); - m_WParser -> OpenContainer(); + return true; } else - c -> SetAlignHor(old); - - return TRUE; + { + // Same as BR + int al = m_WParser->GetContainer()->GetAlignHor(); + wxHtmlContainerCell *c; + + m_WParser->CloseContainer(); + c = m_WParser->OpenContainer(); + c->SetAlignHor(al); + c->SetAlign(tag); + c->SetMinHeight(m_WParser->GetCharHeight()); + return false; + } } TAG_HANDLER_END(DIV) @@ -139,20 +282,30 @@ TAG_HANDLER_END(DIV) TAG_HANDLER_BEGIN(TITLE, "TITLE") + TAG_HANDLER_CONSTR(TITLE) { } TAG_HANDLER_PROC(tag) { - if (m_WParser -> GetWindow()) { - wxHtmlWindow *wfr = (wxHtmlWindow*)(m_WParser -> GetWindow()); - if (wfr) { - wxString title = ""; - wxString *src = m_WParser -> GetSource(); - - for (int i = tag.GetBeginPos(); i < tag.GetEndPos1(); i++) title += (*src)[i]; - wfr -> SetTitle(title); + wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface(); + if (winIface) + { + wxString title = m_WParser->GetSource()->Mid( + tag.GetBeginPos(), + tag.GetEndPos1()-tag.GetBeginPos()); +#if !wxUSE_UNICODE && wxUSE_WCHAR_T + const wxFontEncoding enc = m_WParser->GetInputEncoding(); + if ( enc != wxFONTENCODING_DEFAULT ) + { + // need to convert to the current one + title = wxString(title.wc_str(wxCSConv(enc)), wxConvLocal); } +#endif // !wxUSE_UNICODE + + title = m_WParser->GetEntitiesParser()->Parse(title); + + winIface->SetHTMLWindowTitle(title); } - return TRUE; + return true; } TAG_HANDLER_END(TITLE) @@ -161,36 +314,55 @@ TAG_HANDLER_END(TITLE) TAG_HANDLER_BEGIN(BODY, "BODY") + TAG_HANDLER_CONSTR(BODY) { } TAG_HANDLER_PROC(tag) { - unsigned long tmp; wxColour clr; - if (tag.HasParam(wxT("TEXT"))) { - if (tag.ScanParam(wxT("TEXT"), wxT("#%lX"), &tmp) == 1) { - clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); - m_WParser -> SetActualColor(clr); - m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(clr)); - } - } + if (tag.GetParamAsColour(wxT("TEXT"), &clr)) + { + m_WParser->SetActualColor(clr); + m_WParser->GetContainer()->InsertCell(new wxHtmlColourCell(clr)); + } - if (tag.HasParam(wxT("LINK"))) { - if (tag.ScanParam(wxT("LINK"), wxT("#%lX"), &tmp) == 1) { - clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); - m_WParser -> SetLinkColor(clr); - } + if (tag.GetParamAsColour(wxT("LINK"), &clr)) + m_WParser->SetLinkColor(clr); + + wxHtmlWindowInterface *winIface = m_WParser->GetWindowInterface(); + // the rest of this function requires a window: + if ( !winIface ) + return false; + + if (tag.HasParam(wxT("BACKGROUND"))) + { + wxFSFile *fileBgImage = m_WParser->OpenURL + ( + wxHTML_URL_IMAGE, + tag.GetParam(wxT("BACKGROUND")) + ); + if ( fileBgImage ) + { + wxInputStream *is = fileBgImage->GetStream(); + if ( is ) + { + wxImage image(*is); + if ( image.Ok() ) + winIface->SetHTMLBackgroundImage(image); + } + + delete fileBgImage; + } } - if (tag.HasParam(wxT("BGCOLOR"))) { - if (tag.ScanParam(wxT("BGCOLOR"), wxT("#%lX"), &tmp) == 1) { - clr = wxColour((tmp & 0xFF0000) >> 16 , (tmp & 0x00FF00) >> 8, (tmp & 0x0000FF)); - m_WParser -> GetContainer() -> InsertCell(new wxHtmlColourCell(clr, wxHTML_CLR_BACKGROUND)); - if (m_WParser -> GetWindow() != NULL) - m_WParser -> GetWindow() -> SetBackgroundColour(clr); - } + if (tag.GetParamAsColour(wxT("BGCOLOR"), &clr)) + { + m_WParser->GetContainer()->InsertCell( + new wxHtmlColourCell(clr, wxHTML_CLR_BACKGROUND)); + winIface->SetHTMLBackgroundColour(clr); } - return FALSE; + + return false; } TAG_HANDLER_END(BODY) @@ -198,31 +370,83 @@ TAG_HANDLER_END(BODY) TAG_HANDLER_BEGIN(BLOCKQUOTE, "BLOCKQUOTE") + TAG_HANDLER_CONSTR(BLOCKQUOTE) { } TAG_HANDLER_PROC(tag) { wxHtmlContainerCell *c; - - m_WParser -> CloseContainer(); - c = m_WParser -> OpenContainer(); - if (c -> GetAlignHor() == wxHTML_ALIGN_RIGHT) - c -> SetIndent(5 * m_WParser -> GetCharWidth(), wxHTML_INDENT_RIGHT); + + m_WParser->CloseContainer(); + c = m_WParser->OpenContainer(); + + if (c->GetAlignHor() == wxHTML_ALIGN_RIGHT) + c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_RIGHT); else - c -> SetIndent(5 * m_WParser -> GetCharWidth(), wxHTML_INDENT_LEFT); - c -> SetIndent(m_WParser -> GetCharHeight(), wxHTML_INDENT_TOP); - m_WParser -> OpenContainer(); + c->SetIndent(5 * m_WParser->GetCharWidth(), wxHTML_INDENT_LEFT); + + c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_TOP); + m_WParser->OpenContainer(); ParseInner(tag); - c = m_WParser -> CloseContainer(); - c -> SetIndent(m_WParser -> GetCharHeight(), wxHTML_INDENT_BOTTOM); - m_WParser -> CloseContainer(); - m_WParser -> OpenContainer(); - return TRUE; + c = m_WParser->CloseContainer(); + c->SetIndent(m_WParser->GetCharHeight(), wxHTML_INDENT_BOTTOM); + m_WParser->CloseContainer(); + m_WParser->OpenContainer(); + return true; } TAG_HANDLER_END(BLOCKQUOTE) +TAG_HANDLER_BEGIN(SUBSUP, "SUB,SUP") + + TAG_HANDLER_PROC(tag) + { + bool issub = (tag.GetName() == wxT("SUB")); + wxHtmlScriptMode oldmode = m_WParser->GetScriptMode(); + int oldbase = m_WParser->GetScriptBaseline(); + int oldsize = m_WParser->GetFontSize(); + + wxHtmlContainerCell *cont = m_WParser->GetContainer(); + wxHtmlCell *c = cont->GetLastChild(); + + m_WParser->SetScriptMode(issub ? wxHTML_SCRIPT_SUB : wxHTML_SCRIPT_SUP); + m_WParser->SetScriptBaseline( + oldbase + c ? c->GetScriptBaseline() : 0); + + // select smaller font + m_WParser->SetFontSize(m_WParser->GetFontSize()-2); + cont->InsertCell(new wxHtmlFontCell(m_WParser->CreateCurrentFont())); + + ParseInner(tag); + + // restore font size + m_WParser->SetFontSize(oldsize); + m_WParser->GetContainer()->InsertCell( + new wxHtmlFontCell(m_WParser->CreateCurrentFont())); + + // restore base and alignment + m_WParser->SetScriptBaseline(oldbase); + m_WParser->SetScriptMode(oldmode); + + return true; + } + +TAG_HANDLER_END(SUBSUP) + + +// Tag handler for tags that we have to ignore, otherwise non-text data +// would show up as text: +TAG_HANDLER_BEGIN(DoNothing, "SCRIPT") + TAG_HANDLER_CONSTR(DoNothing) { } + + TAG_HANDLER_PROC(WXUNUSED(tag)) + { + return true; + } +TAG_HANDLER_END(DoNothing) + + @@ -235,6 +459,8 @@ TAGS_MODULE_BEGIN(Layout) TAGS_MODULE_ADD(TITLE) TAGS_MODULE_ADD(BODY) TAGS_MODULE_ADD(BLOCKQUOTE) + TAGS_MODULE_ADD(SUBSUP) + TAGS_MODULE_ADD(DoNothing) TAGS_MODULE_END(Layout)