1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/html/winpars.cpp 
   3 // Purpose:     wxHtmlParser class (generic parser) 
   4 // Author:      Vaclav Slavik 
   6 // Copyright:   (c) 1999 Vaclav Slavik 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #include "wx/wxprec.h" 
  16 #if wxUSE_HTML && wxUSE_STREAMS 
  22     #include "wx/settings.h" 
  25 #include "wx/html/htmldefs.h" 
  26 #include "wx/html/winpars.h" 
  27 #include "wx/html/htmlwin.h" 
  28 #include "wx/fontmap.h" 
  32 //----------------------------------------------------------------------------- 
  34 //----------------------------------------------------------------------------- 
  36 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinParser
, wxHtmlParser
) 
  38 wxList 
wxHtmlWinParser::m_Modules
; 
  40 wxHtmlWinParser::wxHtmlWinParser(wxHtmlWindowInterface 
*wndIface
) 
  44     m_windowInterface 
= wndIface
; 
  47     m_CharHeight 
= m_CharWidth 
= 0; 
  51     m_InputEnc 
= wxFONTENCODING_ISO8859_1
; 
  52     m_OutputEnc 
= wxFONTENCODING_DEFAULT
; 
  54     m_lastWordCell 
= NULL
; 
  58         for (i 
= 0; i 
< 2; i
++) 
  59             for (j 
= 0; j 
< 2; j
++) 
  60                 for (k 
= 0; k 
< 2; k
++) 
  61                     for (l 
= 0; l 
< 2; l
++) 
  62                         for (m 
= 0; m 
< 7; m
++) 
  64                             m_FontsTable
[i
][j
][k
][l
][m
] = NULL
; 
  65                             m_FontsFacesTable
[i
][j
][k
][l
][m
] = wxEmptyString
; 
  67                             m_FontsEncTable
[i
][j
][k
][l
][m
] = wxFONTENCODING_DEFAULT
; 
  71         SetFonts(wxEmptyString
, wxEmptyString
, NULL
); 
  74     // fill in wxHtmlParser's tables: 
  75     wxList::compatibility_iterator node 
= m_Modules
.GetFirst(); 
  78         wxHtmlTagsModule 
*mod 
= (wxHtmlTagsModule
*) node
->GetData(); 
  79         mod
->FillHandlersTable(this); 
  80         node 
= node
->GetNext(); 
  84 wxHtmlWinParser::~wxHtmlWinParser() 
  88     for (i 
= 0; i 
< 2; i
++) 
  89         for (j 
= 0; j 
< 2; j
++) 
  90             for (k 
= 0; k 
< 2; k
++) 
  91                 for (l 
= 0; l 
< 2; l
++) 
  92                     for (m 
= 0; m 
< 7; m
++) 
  94                         if (m_FontsTable
[i
][j
][k
][l
][m
] != NULL
) 
  95                             delete m_FontsTable
[i
][j
][k
][l
][m
]; 
 100     delete[] m_tmpStrBuf
; 
 103 void wxHtmlWinParser::AddModule(wxHtmlTagsModule 
*module) 
 105     m_Modules
.Append(module); 
 108 void wxHtmlWinParser::RemoveModule(wxHtmlTagsModule 
*module) 
 110     m_Modules
.DeleteObject(module); 
 113 // build all HTML font sizes (1..7) from the given base size 
 114 static void wxBuildFontSizes(int *sizes
, int size
) 
 116     // using a fixed factor (1.2, from CSS2) is a bad idea as explained at 
 117     // http://www.w3.org/TR/CSS21/fonts.html#font-size-props but this is by far 
 118     // simplest thing to do so still do it like this for now 
 119     sizes
[0] = int(size 
* 0.75); // exception to 1.2 rule, otherwise too small 
 120     sizes
[1] = int(size 
* 0.83); 
 122     sizes
[3] = int(size 
* 1.2); 
 123     sizes
[4] = int(size 
* 1.44); 
 124     sizes
[5] = int(size 
* 1.73); 
 125     sizes
[6] = int(size 
* 2); 
 128 static int wxGetDefaultHTMLFontSize() 
 130     // base the default font size on the size of the default system font but 
 131     // also ensure that we have a font of reasonable size, otherwise small HTML 
 132     // fonts are unreadable 
 133     int size 
= wxNORMAL_FONT
->GetPointSize(); 
 139 void wxHtmlWinParser::SetFonts(const wxString
& normal_face
, 
 140                                const wxString
& fixed_face
, 
 143     static int default_sizes
[7] = { 0 }; 
 146         if ( !default_sizes
[0] ) 
 147             wxBuildFontSizes(default_sizes
, wxGetDefaultHTMLFontSize()); 
 149         sizes 
= default_sizes
; 
 154     for (i 
= 0; i 
< 7; i
++) 
 155         m_FontsSizes
[i
] = sizes
[i
]; 
 157     m_FontFaceFixed 
= fixed_face
; 
 158     m_FontFaceNormal 
= normal_face
; 
 161     SetInputEncoding(m_InputEnc
); 
 164     for (i 
= 0; i 
< 2; i
++) 
 165         for (j 
= 0; j 
< 2; j
++) 
 166             for (k 
= 0; k 
< 2; k
++) 
 167                 for (l 
= 0; l 
< 2; l
++) 
 168                     for (m 
= 0; m 
< 7; m
++) { 
 169                         if (m_FontsTable
[i
][j
][k
][l
][m
] != NULL
) 
 171                             delete m_FontsTable
[i
][j
][k
][l
][m
]; 
 172                             m_FontsTable
[i
][j
][k
][l
][m
] = NULL
; 
 177 void wxHtmlWinParser::SetStandardFonts(int size
, 
 178                                        const wxString
& normal_face
, 
 179                                        const wxString
& fixed_face
) 
 182         size 
= wxGetDefaultHTMLFontSize(); 
 185     wxBuildFontSizes(f_sizes
, size
); 
 187     wxString normal 
= normal_face
; 
 188     if ( normal
.empty() ) 
 189         normal 
= wxNORMAL_FONT
->GetFaceName(); 
 191     SetFonts(normal
, fixed_face
, f_sizes
); 
 194 void wxHtmlWinParser::InitParser(const wxString
& source
) 
 196     wxHtmlParser::InitParser(source
); 
 197     wxASSERT_MSG(m_DC 
!= NULL
, wxT("no DC assigned to wxHtmlWinParser!!")); 
 199     m_FontBold 
= m_FontItalic 
= m_FontUnderlined 
= m_FontFixed 
= FALSE
; 
 200     m_FontSize 
= 3; //default one 
 201     CreateCurrentFont();           // we're selecting default font into 
 202     m_DC
->GetTextExtent( wxT("H"), &m_CharWidth
, &m_CharHeight
); 
 203                 /* NOTE : we're not using GetCharWidth/Height() because 
 204                    of differences under X and win 
 208     m_Link 
= wxHtmlLinkInfo( wxEmptyString 
); 
 209     m_LinkColor
.Set(0, 0, 0xFF); 
 210     m_ActualColor
.Set(0, 0, 0); 
 211     m_Align 
= wxHTML_ALIGN_LEFT
; 
 212     m_ScriptMode 
= wxHTML_SCRIPT_NORMAL
; 
 213     m_ScriptBaseline 
= 0; 
 214     m_tmpLastWasSpace 
= false; 
 215     m_lastWordCell 
= NULL
; 
 217     // open the toplevel container that contains everything else and that 
 218     // is never closed (this makes parser's life easier): 
 221     // then open the first container into which page's content will go: 
 225     wxString charset 
= ExtractCharsetInformation(source
); 
 226     if (!charset
.empty()) 
 228         wxFontEncoding enc 
= wxFontMapper::Get()->CharsetToEncoding(charset
); 
 229         if (enc 
!= wxFONTENCODING_SYSTEM
) 
 230           SetInputEncoding(enc
); 
 234     m_Container
->InsertCell(new wxHtmlColourCell(m_ActualColor
)); 
 235     wxColour windowColour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
) ; 
 237     m_Container
->InsertCell
 
 242                             ? m_windowInterface
->GetHTMLBackgroundColour() 
 244                          wxHTML_CLR_BACKGROUND
 
 248     m_Container
->InsertCell(new wxHtmlFontCell(CreateCurrentFont())); 
 251 void wxHtmlWinParser::DoneParser() 
 255     SetInputEncoding(wxFONTENCODING_ISO8859_1
); // for next call 
 257     wxHtmlParser::DoneParser(); 
 260 #if WXWIN_COMPATIBILITY_2_6 
 261 wxHtmlWindow 
*wxHtmlWinParser::GetWindow() 
 263     if (!m_windowInterface
) 
 265     return wxDynamicCast(m_windowInterface
->GetHTMLWindow(), wxHtmlWindow
); 
 269 wxObject
* wxHtmlWinParser::GetProduct() 
 271     wxHtmlContainerCell 
*top
; 
 277     while (top
->GetParent()) top 
= top
->GetParent(); 
 278     top
->RemoveExtraSpacing(true, true); 
 283 wxFSFile 
*wxHtmlWinParser::OpenURL(wxHtmlURLType type
, 
 284                                    const wxString
& url
) const 
 286     if ( !m_windowInterface 
) 
 287         return wxHtmlParser::OpenURL(type
, url
); 
 290     wxHtmlOpeningStatus status
; 
 293         wxString 
myfullurl(myurl
); 
 295         // consider url as absolute path first 
 296         wxURI 
current(myurl
); 
 297         myfullurl 
= current
.BuildUnescapedURI(); 
 299         // if not absolute then ... 
 300         if( current
.IsReference() ) 
 302             wxString basepath 
= GetFS()->GetPath(); 
 303             wxURI 
base(basepath
); 
 305             // ... try to apply base path if valid ... 
 306             if( !base
.IsReference() ) 
 308                 wxURI 
path(myfullurl
); 
 309                 path
.Resolve( base 
); 
 310                 myfullurl 
= path
.BuildUnescapedURI(); 
 314                 // ... or force such addition if not included already 
 315                 if( !current
.GetPath().Contains(base
.GetPath()) ) 
 318                     wxURI 
connected( basepath 
); 
 319                     myfullurl 
= connected
.BuildUnescapedURI(); 
 325         status 
= m_windowInterface
->OnHTMLOpeningURL(type
, myfullurl
, &redirect
); 
 326         if ( status 
!= wxHTML_REDIRECT 
) 
 332     if ( status 
== wxHTML_BLOCK 
) 
 335     return GetFS()->OpenFile(myurl
); 
 338 void wxHtmlWinParser::AddText(const wxChar
* txt
) 
 345     wxChar nbsp 
= GetEntitiesParser()->GetCharForCode(160 /* nbsp */); 
 347     if (lng
+1 > m_tmpStrBufSize
) 
 349         delete[] m_tmpStrBuf
; 
 350         m_tmpStrBuf 
= new wxChar
[lng
+1]; 
 351         m_tmpStrBufSize 
= lng
+1; 
 353     wxChar 
*temp 
= m_tmpStrBuf
; 
 355     if (m_tmpLastWasSpace
) 
 358                ((txt
[i
] == wxT('\n')) || (txt
[i
] == wxT('\r')) || (txt
[i
] == wxT(' ')) || 
 359                 (txt
[i
] == wxT('\t')))) i
++; 
 365         d 
= temp
[templen
++] = txt
[i
]; 
 366         if ((d 
== wxT('\n')) || (d 
== wxT('\r')) || (d 
== wxT(' ')) || (d 
== wxT('\t'))) 
 369             while ((i 
< lng
) && ((txt
[i
] == wxT('\n')) || (txt
[i
] == wxT('\r')) || 
 370                                  (txt
[i
] == wxT(' ')) || (txt
[i
] == wxT('\t')))) i
++, x
++; 
 376             temp
[templen
-1] = wxT(' '); 
 377             DoAddText(temp
, templen
, nbsp
); 
 378             m_tmpLastWasSpace 
= true; 
 382     if (templen 
&& (templen 
> 1 || temp
[0] != wxT(' '))) 
 384         DoAddText(temp
, templen
, nbsp
); 
 385         m_tmpLastWasSpace 
= false; 
 389 void wxHtmlWinParser::DoAddText(wxChar 
*temp
, int& templen
, wxChar nbsp
) 
 395         m_EncConv
->Convert(temp
); 
 397     size_t len 
= wxStrlen(temp
); 
 398     for (size_t j 
= 0; j 
< len
; j
++) 
 404     wxHtmlCell 
*c 
= new wxHtmlWordCell(temp
, *(GetDC())); 
 408     m_Container
->InsertCell(c
); 
 409     ((wxHtmlWordCell
*)c
)->SetPreviousWord(m_lastWordCell
); 
 410     m_lastWordCell 
= (wxHtmlWordCell
*)c
; 
 415 wxHtmlContainerCell
* wxHtmlWinParser::OpenContainer() 
 417     m_Container 
= new wxHtmlContainerCell(m_Container
); 
 418     m_Container
->SetAlignHor(m_Align
); 
 419     m_tmpLastWasSpace 
= true; 
 420         /* to avoid space being first character in paragraph */ 
 426 wxHtmlContainerCell
* wxHtmlWinParser::SetContainer(wxHtmlContainerCell 
*c
) 
 428     m_tmpLastWasSpace 
= true; 
 429         /* to avoid space being first character in paragraph */ 
 430     return m_Container 
= c
; 
 435 wxHtmlContainerCell
* wxHtmlWinParser::CloseContainer() 
 437     m_Container 
= m_Container
->GetParent(); 
 442 void wxHtmlWinParser::SetFontSize(int s
) 
 445     else if (s 
> 7) s 
= 7; 
 451 wxFont
* wxHtmlWinParser::CreateCurrentFont() 
 453     int fb 
= GetFontBold(), 
 454         fi 
= GetFontItalic(), 
 455         fu 
= GetFontUnderlined(), 
 457         fs 
= GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ; 
 459     wxString face 
= ff 
? m_FontFaceFixed 
: m_FontFaceNormal
; 
 460     wxString 
*faceptr 
= &(m_FontsFacesTable
[fb
][fi
][fu
][ff
][fs
]); 
 461     wxFont 
**fontptr 
= &(m_FontsTable
[fb
][fi
][fu
][ff
][fs
]); 
 463     wxFontEncoding 
*encptr 
= &(m_FontsEncTable
[fb
][fi
][fu
][ff
][fs
]); 
 466     if (*fontptr 
!= NULL 
&& (*faceptr 
!= face
 
 468                              || *encptr 
!= m_OutputEnc
 
 476     if (*fontptr 
== NULL
) 
 479         *fontptr 
= new wxFont( 
 480                        (int) (m_FontsSizes
[fs
] * m_PixelScale
), 
 481                        ff 
? wxMODERN 
: wxSWISS
, 
 482                        fi 
? wxITALIC 
: wxNORMAL
, 
 483                        fb 
? wxBOLD 
: wxNORMAL
, 
 484                        fu 
? true : false, face
 
 489         *encptr 
= m_OutputEnc
; 
 492     m_DC
->SetFont(**fontptr
); 
 498 void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo
& link
) 
 501     m_UseLink 
= (link
.GetHref() != wxEmptyString
); 
 504 void wxHtmlWinParser::SetFontFace(const wxString
& face
) 
 506     if (GetFontFixed()) m_FontFaceFixed 
= face
; 
 507     else m_FontFaceNormal 
= face
; 
 510     if (m_InputEnc 
!= wxFONTENCODING_DEFAULT
) 
 511         SetInputEncoding(m_InputEnc
); 
 515 void wxHtmlWinParser::ApplyStateToCell(wxHtmlCell 
*cell
) 
 519         cell
->SetLink(GetLink()); 
 521     // apply current script mode settings: 
 522     cell
->SetScriptMode(GetScriptMode(), GetScriptBaseline()); 
 527 void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc
) 
 529     m_InputEnc 
= m_OutputEnc 
= wxFONTENCODING_DEFAULT
; 
 536     if (enc 
== wxFONTENCODING_DEFAULT
) return; 
 538     wxFontEncoding altfix
, altnorm
; 
 539     bool availfix
, availnorm
; 
 542     availnorm 
= wxFontMapper::Get()->IsEncodingAvailable(enc
, m_FontFaceNormal
); 
 543     availfix 
= wxFontMapper::Get()->IsEncodingAvailable(enc
, m_FontFaceFixed
); 
 544     if (availnorm 
&& availfix
) 
 548     else if (wxFontMapper::Get()->GetAltForEncoding(enc
, &altnorm
, m_FontFaceNormal
, false) && 
 549              wxFontMapper::Get()->GetAltForEncoding(enc
, &altfix
, m_FontFaceFixed
, false) && 
 551         m_OutputEnc 
= altnorm
; 
 553     // at least normal face? 
 556     else if (wxFontMapper::Get()->GetAltForEncoding(enc
, &altnorm
, m_FontFaceNormal
, false)) 
 557         m_OutputEnc 
= altnorm
; 
 562         // okay, let's convert to ISO_8859-1, available always 
 563         m_OutputEnc 
= wxFONTENCODING_DEFAULT
; 
 565         m_OutputEnc 
= wxLocale::GetSystemEncoding() ; 
 570     if (m_OutputEnc 
== wxFONTENCODING_DEFAULT
) 
 571         GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM
); 
 573         GetEntitiesParser()->SetEncoding(m_OutputEnc
); 
 575     if (m_InputEnc 
== m_OutputEnc
) return; 
 577     m_EncConv 
= new wxEncodingConverter(); 
 578     if (!m_EncConv
->Init(m_InputEnc
, 
 579                            (m_OutputEnc 
== wxFONTENCODING_DEFAULT
) ? 
 580                                       wxFONTENCODING_ISO8859_1 
: m_OutputEnc
, 
 581                            wxCONVERT_SUBSTITUTE
)) 
 582     { // total failure :-( 
 583         wxLogError(_("Failed to display HTML document in %s encoding"), 
 584                    wxFontMapper::GetEncodingName(enc
).c_str()); 
 585         m_InputEnc 
= m_OutputEnc 
= wxFONTENCODING_DEFAULT
; 
 595 //----------------------------------------------------------------------------- 
 596 // wxHtmlWinTagHandler 
 597 //----------------------------------------------------------------------------- 
 599 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler
, wxHtmlTagHandler
) 
 601 //----------------------------------------------------------------------------- 
 603 //----------------------------------------------------------------------------- 
 605 // NB: This is *NOT* winpars.cpp's initialization and shutdown code!! 
 606 //     This module is an ancestor for tag handlers modules defined 
 607 //     in m_*.cpp files with TAGS_MODULE_BEGIN...TAGS_MODULE_END construct. 
 609 //     Do not add any winpars.cpp shutdown or initialization code to it, 
 610 //     create a new module instead! 
 612 IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule
, wxModule
) 
 614 bool wxHtmlTagsModule::OnInit() 
 616     wxHtmlWinParser::AddModule(this); 
 620 void wxHtmlTagsModule::OnExit() 
 622     wxHtmlWinParser::RemoveModule(this);