From 6cc4e6b81a9f2a0275d7fa0c6171658b24a2af8a Mon Sep 17 00:00:00 2001
From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= <vslavik@fastmail.fm>
Date: Sun, 27 Jan 2002 19:03:10 +0000
Subject: [PATCH] new wxHtmlWindow::OnOpeningURL API

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13854 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/htparser.tex |  34 +++++++++
 docs/latex/wx/htwindow.tex |  34 +++++++--
 docs/latex/wx/htwinprs.tex |   8 ---
 include/wx/html/htmlpars.h |  12 +++-
 include/wx/html/htmlwin.h  |  58 +++++++++------
 include/wx/html/winpars.h  |   2 +-
 src/html/htmlpars.cpp      |   6 ++
 src/html/htmlwin.cpp       |   8 +--
 src/html/m_image.cpp       | 142 +++++++++++++++++++++++++++----------
 src/html/winpars.cpp       |  23 +++++-
 10 files changed, 243 insertions(+), 84 deletions(-)

diff --git a/docs/latex/wx/htparser.tex b/docs/latex/wx/htparser.tex
index b9d848e609..91dd28305d 100644
--- a/docs/latex/wx/htparser.tex
+++ b/docs/latex/wx/htparser.tex
@@ -134,6 +134,40 @@ Returns pointer to the source being parsed.
 Setups the parser for parsing the {\it source} string. (Should be overridden
 in derived class)
 
+\membersection{wxHtmlParser::OpenURL}\label{wxhtmlparseropenurl}
+
+\func{virtual wxFSFile*}{OpenURL}{\param{wxHtmlURLType }{type}, \param{const wxString\& }{url}}
+
+Opens given URL and returns {\tt wxFSFile} object that can be used to read data
+from it. This method may return NULL in one of two cases: either the URL doesn't
+point to any valid resource or the URL is blocked by overriden implementation
+of {\it OpenURL} in derived class.
+
+\wxheading{Parameters}
+
+\docparam{type}{Indicates type of the resource. Is one of
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf wxHTML\_URL\_PAGE}}{Opening a HTML page.}
+\twocolitem{{\bf wxHTML\_URL\_IMAGE}}{Opening an image.}
+\twocolitem{{\bf wxHTML\_URL\_OTHER}}{Opening a resource that doesn't fall into
+any other category.}
+\end{twocollist}}
+
+\docparam{url}{URL being opened.}
+
+\wxheading{Notes}
+
+Always use this method in tag handlers instead of {\tt GetFS()->OpenFile()} 
+because it can block the URL and is thus more secure.
+
+Default behaviour is to call \helpref{wxHtmlWindow::OnOpeningURL}{wxhtmlwindowonopeningurl}
+of the associated wxHtmlWindow object (which may decide to block the URL or
+redirect it to another one),if there's any, and always open the URL if the 
+parser is not used with wxHtmlWindow.
+
+Returned {\tt wxFSFile} object is not guaranteed to point to {\it url}, it might
+have been redirected!
+
 \membersection{wxHtmlParser::Parse}\label{wxhtmlparserparse}
 
 \func{wxObject*}{Parse}{\param{const wxString\& }{source}}
diff --git a/docs/latex/wx/htwindow.tex b/docs/latex/wx/htwindow.tex
index ed1f0344d9..36c2f810aa 100644
--- a/docs/latex/wx/htwindow.tex
+++ b/docs/latex/wx/htwindow.tex
@@ -200,13 +200,39 @@ Also see \helpref{wxHtmlLinkInfo}{wxhtmllinkinfo}.
 
 \membersection{wxHtmlWindow::OnOpeningURL}\label{wxhtmlwindowonopeningurl}
 
-\func{virtual bool}{OnOpeningURL}{\param{const wxString\& }{url}}
+\func{virtual wxHtmlOpeningStatus}{OnOpeningURL}{\param{wxHtmlURLType }{type},\param{const wxString\& }{url}, \param{wxString *}{redirect}}
 
 Called when an URL is being opened (either when the user clicks on a link or
-an image is loaded). If the function returns FALSE, the URL won't be fetched.
-Default behaviour is to return TRUE.
+an image is loaded). The URL will be opened only if OnOpeningURL returns 
+{\tt wxHTML\_OPEN}. This method is called by
+\helpref{wxHtmlParser::OpenURL}{wxhtmlparseropenurl}.
+You can override OnOpeningURL to selectively block some
+URLs (e.g. for security reasons) or to redirect them elsewhere. Default
+behaviour is to always return {\tt wxHTML\_OPEN}.
 
-Also see \helpref{wxHtmlWinParser::CanOpenURL}{wxhtmlwinparsercanopenurl}.
+\wxheading{Parameters}
+
+\docparam{type}{Indicates type of the resource. Is one of
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf wxHTML\_URL\_PAGE}}{Opening a HTML page.}
+\twocolitem{{\bf wxHTML\_URL\_IMAGE}}{Opening an image.}
+\twocolitem{{\bf wxHTML\_URL\_OTHER}}{Opening a resource that doesn't fall into
+any other category.}
+\end{twocollist}}
+
+\docparam{url}{URL being opened.}
+
+\docparam{redirect}{Pointer to wxString variable that must be filled with an
+URL if OnOpeningURL returns {\tt wxHTML\_REDIRECT}.}
+
+\wxheading{Return value}
+\begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf wxHTML\_OPEN}}{Open the URL.}
+\twocolitem{{\bf wxHTML\_BLOCK}}{Deny access to the URL, \helpref{wxHtmlParser::OpenURL}{wxhtmlparseropenurl} will return NULL.}
+\twocolitem{{\bf wxHTML\_REDIRECT}}{Don't open {\it url}, redirect to another
+URL. OnOpeningURL must fill {\it *redirect} with the new URL. OnOpeningURL will
+be called again on returned URL.}
+\end{twocollist}
 
 \membersection{wxHtmlWindow::OnSetTitle}\label{wxhtmlwindowonsettitle}
 
diff --git a/docs/latex/wx/htwinprs.tex b/docs/latex/wx/htwinprs.tex
index 473a8cd0ea..4ff62130d9 100644
--- a/docs/latex/wx/htwinprs.tex
+++ b/docs/latex/wx/htwinprs.tex
@@ -43,14 +43,6 @@ Constructor. Don't use the default one, use constructor with
 
 Adds \helpref{module}{handlers} to the list of wxHtmlWinParser tag handler.
 
-\membersection{wxHtmlWinParser::CanOpenURL}\label{wxhtmlwinparsercanopenurl}
-
-\func{virtual bool}{CanOpenURL}{\param{const wxString\& }{url}}
-
-Call this function to determine whether you are allowed to open given URL. 
-Default behaviour is to call \helpref{wxHtmlWindow::OnOpeningURL}{wxhtmlwindowonopeningurl}
-of the associated wxHtmlWindow object.
-
 \membersection{wxHtmlWinParser::CloseContainer}\label{wxhtmlwinparserclosecontainer}
 
 \func{wxHtmlContainerCell*}{CloseContainer}{\void}
diff --git a/include/wx/html/htmlpars.h b/include/wx/html/htmlpars.h
index 0faf78d4dd..a7f067b5a1 100644
--- a/include/wx/html/htmlpars.h
+++ b/include/wx/html/htmlpars.h
@@ -31,6 +31,14 @@ class WXDLLEXPORT wxHtmlEntitiesParser;
 class wxHtmlTextPieces;
 class wxHtmlParserState;
 
+
+enum wxHtmlURLType
+{
+    wxHTML_URL_PAGE,
+    wxHTML_URL_IMAGE,
+    wxHTML_URL_OTHER
+};
+
 // This class handles generic parsing of HTML document : it scans
 // the document and divide it into blocks of tags (where one block
 // consists of starting and ending tag and of text between these
@@ -48,9 +56,9 @@ public:
 
     wxFileSystem* GetFS() const { return m_FS; }
 
-    // Returns TRUE if the parser is allowed to open given URL (may be forbidden
+    // Opens file if the parser is allowed to open given URL (may be forbidden
     // for security reasons)    
-    virtual bool CanOpenURL(const wxString& url) const { return TRUE; }
+    virtual wxFSFile *OpenURL(wxHtmlURLType type, const wxString& url) const;
 
     // You can simply call this method when you need parsed output.
     // This method does these things:
diff --git a/include/wx/html/htmlwin.h b/include/wx/html/htmlwin.h
index 22466f4856..cbda2b6ad3 100644
--- a/include/wx/html/htmlwin.h
+++ b/include/wx/html/htmlwin.h
@@ -32,6 +32,19 @@ class wxHtmlWinModule;
 class wxHtmlHistoryArray;
 class wxHtmlProcessorList;
 
+
+// wxHtmlWindow flags:
+#define wxHW_SCROLLBAR_NEVER    0x0002
+#define wxHW_SCROLLBAR_AUTO     0x0004
+
+// enums for wxHtmlWindow::OnOpeningURL
+enum wxHtmlOpeningStatus
+{
+    wxHTML_OPEN,
+    wxHTML_BLOCK,
+    wxHTML_REDIRECT
+};
+
 //--------------------------------------------------------------------------------
 // wxHtmlWindow
 //                  (This is probably the only class you will directly use.)
@@ -106,10 +119,6 @@ public:
     // Sets fonts to be used when displaying HTML page.
     void SetFonts(wxString normal_face, wxString fixed_face, const int *sizes);
 
-    // Sets the title of the window
-    // (depending on the information passed to SetRelatedFrame() method)
-    virtual void OnSetTitle(const wxString& title);
-
     // Sets space between text and window borders.
     void SetBorders(int b) {m_Borders = b;}
 
@@ -136,8 +145,24 @@ public:
     // Adds input filter
     static void AddFilter(wxHtmlFilter *filter);
 
+    // Returns a pointer to the parser.
+    wxHtmlWinParser *GetParser() const { return m_Parser; }
+
+    // Adds HTML processor to this instance of wxHtmlWindow:
+    void AddProcessor(wxHtmlProcessor *processor);
+    // Adds HTML processor to wxHtmlWindow class as whole:
+    static void AddGlobalProcessor(wxHtmlProcessor *processor);
+
+    // what would we do with it?
+    virtual bool AcceptsFocusFromKeyboard() const { return FALSE; }
+
+    // -- Callbacks --
+
+    // Sets the title of the window
+    // (depending on the information passed to SetRelatedFrame() method)
+    virtual void OnSetTitle(const wxString& title);
+
     // Called when the mouse hovers over a cell: (x, y) are logical coords
-    //
     // Default behaviour is to do nothing at all
     virtual void OnCellMouseHover(wxHtmlCell *cell, wxCoord x, wxCoord y);
 
@@ -151,21 +176,14 @@ public:
     // call LoadPage(loc)
     virtual void OnLinkClicked(const wxHtmlLinkInfo& link);
     
-    // Called when wxHtmlWindow wants to fetch data from an URL (e.g. when loading
-    // a page or loading an image). The data are downloaded if and only if 
-    // OnOpeningURL returns TRUE.
-    virtual bool OnOpeningURL(const wxString& url) const { return TRUE; }
-
-    // Returns a pointer to the parser.
-    wxHtmlWinParser *GetParser() const { return m_Parser; }
-
-    // Adds HTML processor to this instance of wxHtmlWindow:
-    void AddProcessor(wxHtmlProcessor *processor);
-    // Adds HTML processor to wxHtmlWindow class as whole:
-    static void AddGlobalProcessor(wxHtmlProcessor *processor);
-
-    // what would we do with it?
-    virtual bool AcceptsFocusFromKeyboard() const { return FALSE; }
+    // Called when wxHtmlWindow wants to fetch data from an URL (e.g. when 
+    // loading a page or loading an image). The data are downloaded if and only if 
+    // OnOpeningURL returns TRUE. If OnOpeningURL returns wxHTML_REDIRECT,
+    // it must set *redirect to the new URL
+    virtual wxHtmlOpeningStatus OnOpeningURL(wxHtmlURLType type,
+                                             const wxString& url,
+                                             wxString *redirect) const 
+        { return wxHTML_OPEN; }
 
 protected:
     void Init();
diff --git a/include/wx/html/winpars.h b/include/wx/html/winpars.h
index 396526b92a..4ce8afd0f7 100644
--- a/include/wx/html/winpars.h
+++ b/include/wx/html/winpars.h
@@ -48,7 +48,7 @@ public:
     virtual void DoneParser();
     virtual wxObject* GetProduct();
 
-    virtual bool CanOpenURL(const wxString& url) const;
+    virtual wxFSFile *OpenURL(wxHtmlURLType type, const wxString& url) const;
 
     // Set's the DC used for parsing. If SetDC() is not called,
     // parsing won't proceed
diff --git a/src/html/htmlpars.cpp b/src/html/htmlpars.cpp
index 9efd706bea..69be9d281e 100644
--- a/src/html/htmlpars.cpp
+++ b/src/html/htmlpars.cpp
@@ -812,4 +812,10 @@ wxChar wxHtmlEntitiesParser::GetEntityChar(const wxString& entity)
         return GetCharForCode(code);
 }
 
+wxFSFile *wxHtmlParser::OpenURL(wxHtmlURLType WXUNUSED(type), 
+                                const wxString& url) const
+{
+    return GetFS()->OpenFile(url);
+}
+
 #endif
diff --git a/src/html/htmlwin.cpp b/src/html/htmlwin.cpp
index 9625513f47..212d556d99 100644
--- a/src/html/htmlwin.cpp
+++ b/src/html/htmlwin.cpp
@@ -263,13 +263,7 @@ bool wxHtmlWindow::LoadPage(const wxString& location)
             Refresh(FALSE);
         }
         
-        if ( !m_Parser->CanOpenURL(location) )
-        {
-            wxLogError(_("Access denied to document '%s'!"), location.c_str());
-            return FALSE;
-        }
-
-        f = m_FS->OpenFile(location);
+        f = m_Parser->OpenURL(wxHTML_URL_PAGE, location);
 
         if (f == NULL)
         {
diff --git a/src/html/m_image.cpp b/src/html/m_image.cpp
index 5f5cc37d91..9fb42a9500 100644
--- a/src/html/m_image.cpp
+++ b/src/html/m_image.cpp
@@ -292,6 +292,7 @@ public:
 private:
     wxBitmap           *m_bitmap;
     int                 m_bmpW, m_bmpH;
+    bool                m_showFrame:1;
     wxScrolledWindow   *m_window;
 #if wxUSE_GIF && wxUSE_TIMER
     wxGIFDecoder       *m_gifDecoder;
@@ -323,12 +324,55 @@ class wxGIFTimer : public wxTimer
 // wxHtmlImageCell
 //--------------------------------------------------------------------------------
 
+/* XPM */
+static const char * broken_image_xpm[] = {
+"29 31 7 1",
+" 	c None",
+".	c #808080",
+"+	c #FFFFFF",
+"@	c #C0C0C0",
+"#	c #000000",
+"$	c #333366",
+"%	c #B2B2B2",
+".....................        ",
+".+++++++++++++++++++..       ",
+".+++++++++++++++++++.@.      ",
+".++@@@@@@@@@@@@@@@@@.+@.     ",
+".++@@@@@@@@@@@@@@@@@.++@.    ",
+".++@@@@@.@@@@.@@@@@@.+++@.   ",
+".++@@@@@@@@@@@@@@@@@.++++@.  ",
+".++@@@@@@@@@@@@@@@@@.+++++@. ",
+".++@@.@@@@@@@@@@.@@@######## ",
+".++@@@@@@@@@@@@@@@@@@$$$$$$#.",
+".######@@@@@@@@@@@@@@@.....#.",
+"       ###@@@@@@@@@@@@@@@++#.",
+"          #####@@@@@@@@@@++#.",
+"              #@.@@@@@@@@++#.",
+"..             ###@@@@@@@++#.",
+".+....            #@@@@@@++#.",
+".++@@@...          ####@@++#.",
+".++@@@@@@..            #####.",
+".++@@@@@@@@...               ",
+".++@@@@@@%%%%@.              ",
+".++@@@@@@%%%%@@....          ",
+".++@@@@@@%%%%@@@@@@....      ",
+".++@@@@@@%%%%@@@@@@@@@@....  ",
+".++@@@@@@@@@@@@@@@@@@@@@@++#.",
+".++@@@@@@@@@@@@@@@@@@@@@@++#.",
+".++@@@@@@@@@@@@@@@@@@@@@@++#.",
+".++@@@@@@@@@@@@@@@@@@@@@@++#.",
+".++@@@@@@@@@@@@@@@@@@@@@@++#.",
+".++++++++++++++++++++++++++#.",
+".++++++++++++++++++++++++++#.",
+"############################."};
+
 wxHtmlImageCell::wxHtmlImageCell(wxWindow *window, wxFSFile *input, 
                                  int w, int h, double scale, int align, 
                                  const wxString& mapname) : wxHtmlCell()
 {
     m_window = window ? wxStaticCast(window, wxScrolledWindow) : NULL;
     m_scale = scale;
+    m_showFrame = FALSE;
     m_bitmap = NULL;
     m_bmpW = w;
     m_bmpH = h;
@@ -341,46 +385,63 @@ wxHtmlImageCell::wxHtmlImageCell(wxWindow *window, wxFSFile *input,
     m_physX = m_physY = -1;
 #endif
 
-    wxInputStream *s = input->GetStream();
-    
-    if ( s )
+    if ( input )
     {
-        bool readImg = TRUE;
-        
-#if wxUSE_GIF && wxUSE_TIMER
-        if ( (input->GetLocation().Matches(wxT("*.gif")) ||
-              input->GetLocation().Matches(wxT("*.GIF"))) && m_window )
+        wxInputStream *s = input->GetStream();
+
+        if ( s )
         {
-            m_gifDecoder = new wxGIFDecoder(s, TRUE);
-            if ( m_gifDecoder->ReadGIF() == wxGIF_OK )
+            bool readImg = TRUE;
+
+#if wxUSE_GIF && wxUSE_TIMER
+            if ( (input->GetLocation().Matches(wxT("*.gif")) ||
+                  input->GetLocation().Matches(wxT("*.GIF"))) && m_window )
             {
-                wxImage img;
-                if ( m_gifDecoder->ConvertToImage(&img) )
-                    SetImage(img);
+                m_gifDecoder = new wxGIFDecoder(s, TRUE);
+                if ( m_gifDecoder->ReadGIF() == wxGIF_OK )
+                {
+                    wxImage img;
+                    if ( m_gifDecoder->ConvertToImage(&img) )
+                        SetImage(img);
 
-                readImg = FALSE;
+                    readImg = FALSE;
 
-                if ( m_gifDecoder->IsAnimation() )
-                {
-                    m_gifTimer = new wxGIFTimer(this);
-                    m_gifTimer->Start(m_gifDecoder->GetDelay(), TRUE);
+                    if ( m_gifDecoder->IsAnimation() )
+                    {
+                        m_gifTimer = new wxGIFTimer(this);
+                        m_gifTimer->Start(m_gifDecoder->GetDelay(), TRUE);
+                    }
+                    else
+                    {
+                        wxDELETE(m_gifDecoder);
+                    }
                 }
                 else
                 {
                     wxDELETE(m_gifDecoder);
                 }
             }
-            else
+
+            if ( readImg )
+#endif
             {
-                wxDELETE(m_gifDecoder);
+                SetImage(wxImage(*s, wxBITMAP_TYPE_ANY));
             }
         }
-
-        if ( readImg )
-#endif
+    }
+    else // input==NULL, use "broken image" bitmap
+    {
+        if ( m_bmpW == -1 && m_bmpH == -1 )
+        {
+            m_bmpW == 29, m_bmpH = 31;            
+        }
+        else
         {
-            SetImage(wxImage(*s, wxBITMAP_TYPE_ANY));
+            m_showFrame = TRUE;
+            if ( m_bmpW == -1 ) m_bmpW = 31;
+            if ( m_bmpH == -1 ) m_bmpH = 33;
         }
+        m_bitmap = new wxBitmap(broken_image_xpm);
     }
 
     m_Width = (int)(scale * (double)m_bmpW);
@@ -487,7 +548,14 @@ wxHtmlImageCell::~wxHtmlImageCell()
 
 void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int WXUNUSED(view_y1), int WXUNUSED(view_y2))
 {
-    if (m_bitmap)
+    if ( m_showFrame )
+    {
+        dc.SetBrush(*wxTRANSPARENT_BRUSH);
+        dc.SetPen(*wxBLACK_PEN);
+        dc.DrawRectangle(x + m_PosX, y + m_PosY, m_Width, m_Height);
+        x++, y++;
+    }
+    if ( m_bitmap )
     {
         double us_x, us_y;
         dc.GetUserScale(&us_x, &us_y);
@@ -549,10 +617,8 @@ TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
                 wxString tmp = tag.GetParam(wxT("SRC"));
                 wxString mn = wxEmptyString;
                 
-                if ( !m_WParser->CanOpenURL(tmp) )
-                    return FALSE;
-
-                str = m_WParser->GetFS()->OpenFile(tmp);
+                str = m_WParser->OpenURL(wxHTML_URL_IMAGE, tmp);
+                
                 if (tag.HasParam(wxT("WIDTH")))
                     tag.GetParamAsInt(wxT("WIDTH"), &w);
                 if (tag.HasParam(wxT("HEIGHT")))
@@ -575,18 +641,16 @@ TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
                         mn = mn.Mid( 1 );
                     }
                 }
-                wxHtmlImageCell *cel = NULL;
+                wxHtmlImageCell *cel = new wxHtmlImageCell(
+                                          m_WParser->GetWindow(),
+                                          str, w, h, 
+                                          m_WParser->GetPixelScale(), 
+                                          al, mn);
+                cel->SetLink(m_WParser->GetLink());
+                cel->SetId(tag.GetParam(wxT("id"))); // may be empty
+                m_WParser->GetContainer()->InsertCell(cel);
                 if (str)
-                {
-                    cel = new wxHtmlImageCell(m_WParser->GetWindow(),
-                                              str, w, h, 
-                                              m_WParser->GetPixelScale(), 
-                                              al, mn);
-                    cel->SetLink(m_WParser->GetLink());
-                    cel->SetId(tag.GetParam(wxT("id"))); // may be empty
-                    m_WParser->GetContainer()->InsertCell(cel);
                     delete str;
-                }
             }
         }
         if (tag.GetName() == wxT("MAP"))
diff --git a/src/html/winpars.cpp b/src/html/winpars.cpp
index 479401d392..86dbfd1b90 100644
--- a/src/html/winpars.cpp
+++ b/src/html/winpars.cpp
@@ -180,14 +180,31 @@ wxObject* wxHtmlWinParser::GetProduct()
     return top;
 }
 
-bool wxHtmlWinParser::CanOpenURL(const wxString& url) const
+wxFSFile *wxHtmlWinParser::OpenURL(wxHtmlURLType type, 
+                                   const wxString& url) const
 {
     // FIXME - normalize the URL to full path before passing to
     //         OnOpeningURL!!
     if ( m_Window )
-        return m_Window->OnOpeningURL(url);
+    {
+        wxString redirect;
+        wxString myurl(url);
+        wxHtmlOpeningStatus status;
+        for (;;)
+        {
+            if ( m_Window->OnOpeningURL(type, myurl, &redirect) == wxHTML_REDIRECT )
+                myurl = redirect;
+            else
+                break;
+        }
+        
+        if ( status == wxHTML_BLOCK )
+            return NULL;
+        else
+            return GetFS()->OpenFile(myurl);
+    }
     else
-        return TRUE;
+        return wxHtmlParser::OpenURL(type, url);
 }
 
 void wxHtmlWinParser::AddText(const wxChar* txt)
-- 
2.45.2

