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;
52 m_InputEnc
= wxFONTENCODING_ISO8859_1
;
53 m_OutputEnc
= wxFONTENCODING_DEFAULT
;
55 m_whitespaceMode
= Whitespace_Normal
;
56 m_lastWordCell
= NULL
;
61 for (i
= 0; i
< 2; i
++)
62 for (j
= 0; j
< 2; j
++)
63 for (k
= 0; k
< 2; k
++)
64 for (l
= 0; l
< 2; l
++)
65 for (m
= 0; m
< 7; m
++)
67 m_FontsTable
[i
][j
][k
][l
][m
] = NULL
;
68 m_FontsFacesTable
[i
][j
][k
][l
][m
] = wxEmptyString
;
70 m_FontsEncTable
[i
][j
][k
][l
][m
] = wxFONTENCODING_DEFAULT
;
74 SetFonts(wxEmptyString
, wxEmptyString
, NULL
);
77 // fill in wxHtmlParser's tables:
78 wxList::compatibility_iterator node
= m_Modules
.GetFirst();
81 wxHtmlTagsModule
*mod
= (wxHtmlTagsModule
*) node
->GetData();
82 mod
->FillHandlersTable(this);
83 node
= node
->GetNext();
87 wxHtmlWinParser::~wxHtmlWinParser()
91 for (i
= 0; i
< 2; i
++)
92 for (j
= 0; j
< 2; j
++)
93 for (k
= 0; k
< 2; k
++)
94 for (l
= 0; l
< 2; l
++)
95 for (m
= 0; m
< 7; m
++)
97 if (m_FontsTable
[i
][j
][k
][l
][m
] != NULL
)
98 delete m_FontsTable
[i
][j
][k
][l
][m
];
103 delete[] m_tmpStrBuf
;
106 void wxHtmlWinParser::AddModule(wxHtmlTagsModule
*module)
108 m_Modules
.Append(module);
111 void wxHtmlWinParser::RemoveModule(wxHtmlTagsModule
*module)
113 m_Modules
.DeleteObject(module);
116 // build all HTML font sizes (1..7) from the given base size
117 static void wxBuildFontSizes(int *sizes
, int size
)
119 // using a fixed factor (1.2, from CSS2) is a bad idea as explained at
120 // http://www.w3.org/TR/CSS21/fonts.html#font-size-props but this is by far
121 // simplest thing to do so still do it like this for now
122 sizes
[0] = int(size
* 0.75); // exception to 1.2 rule, otherwise too small
123 sizes
[1] = int(size
* 0.83);
125 sizes
[3] = int(size
* 1.2);
126 sizes
[4] = int(size
* 1.44);
127 sizes
[5] = int(size
* 1.73);
128 sizes
[6] = int(size
* 2);
131 static int wxGetDefaultHTMLFontSize()
133 // base the default font size on the size of the default system font but
134 // also ensure that we have a font of reasonable size, otherwise small HTML
135 // fonts are unreadable
136 int size
= wxNORMAL_FONT
->GetPointSize();
142 void wxHtmlWinParser::SetFonts(const wxString
& normal_face
,
143 const wxString
& fixed_face
,
146 static int default_sizes
[7] = { 0 };
149 if ( !default_sizes
[0] )
150 wxBuildFontSizes(default_sizes
, wxGetDefaultHTMLFontSize());
152 sizes
= default_sizes
;
157 for (i
= 0; i
< 7; i
++)
158 m_FontsSizes
[i
] = sizes
[i
];
160 m_FontFaceFixed
= fixed_face
;
161 m_FontFaceNormal
= normal_face
;
164 SetInputEncoding(m_InputEnc
);
167 for (i
= 0; i
< 2; i
++)
168 for (j
= 0; j
< 2; j
++)
169 for (k
= 0; k
< 2; k
++)
170 for (l
= 0; l
< 2; l
++)
171 for (m
= 0; m
< 7; m
++) {
172 if (m_FontsTable
[i
][j
][k
][l
][m
] != NULL
)
174 delete m_FontsTable
[i
][j
][k
][l
][m
];
175 m_FontsTable
[i
][j
][k
][l
][m
] = NULL
;
180 void wxHtmlWinParser::SetStandardFonts(int size
,
181 const wxString
& normal_face
,
182 const wxString
& fixed_face
)
185 size
= wxGetDefaultHTMLFontSize();
188 wxBuildFontSizes(f_sizes
, size
);
190 wxString normal
= normal_face
;
191 if ( normal
.empty() )
192 normal
= wxNORMAL_FONT
->GetFaceName();
194 SetFonts(normal
, fixed_face
, f_sizes
);
197 void wxHtmlWinParser::InitParser(const wxString
& source
)
199 wxHtmlParser::InitParser(source
);
200 wxASSERT_MSG(m_DC
!= NULL
, wxT("no DC assigned to wxHtmlWinParser!!"));
202 m_FontBold
= m_FontItalic
= m_FontUnderlined
= m_FontFixed
= FALSE
;
203 m_FontSize
= 3; //default one
204 CreateCurrentFont(); // we're selecting default font into
206 // we're not using GetCharWidth/Height() because of
207 // differences under X and win
209 m_DC
->GetTextExtent( wxT("H"), &w
, &h
);
214 m_Link
= wxHtmlLinkInfo( wxEmptyString
);
215 m_LinkColor
.Set(0, 0, 0xFF);
216 m_ActualColor
.Set(0, 0, 0);
217 m_Align
= wxHTML_ALIGN_LEFT
;
218 m_ScriptMode
= wxHTML_SCRIPT_NORMAL
;
219 m_ScriptBaseline
= 0;
220 m_tmpLastWasSpace
= false;
221 m_lastWordCell
= NULL
;
223 // open the toplevel container that contains everything else and that
224 // is never closed (this makes parser's life easier):
227 // then open the first container into which page's content will go:
231 wxString charset
= ExtractCharsetInformation(source
);
232 if (!charset
.empty())
234 wxFontEncoding enc
= wxFontMapper::Get()->CharsetToEncoding(charset
);
235 if (enc
!= wxFONTENCODING_SYSTEM
)
236 SetInputEncoding(enc
);
240 m_Container
->InsertCell(new wxHtmlColourCell(m_ActualColor
));
241 wxColour windowColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
) ;
243 m_Container
->InsertCell
248 ? m_windowInterface
->GetHTMLBackgroundColour()
250 wxHTML_CLR_BACKGROUND
254 m_Container
->InsertCell(new wxHtmlFontCell(CreateCurrentFont()));
257 void wxHtmlWinParser::DoneParser()
261 SetInputEncoding(wxFONTENCODING_ISO8859_1
); // for next call
263 wxHtmlParser::DoneParser();
266 #if WXWIN_COMPATIBILITY_2_6
267 wxHtmlWindow
*wxHtmlWinParser::GetWindow()
269 if (!m_windowInterface
)
271 return wxDynamicCast(m_windowInterface
->GetHTMLWindow(), wxHtmlWindow
);
275 wxObject
* wxHtmlWinParser::GetProduct()
277 wxHtmlContainerCell
*top
;
283 while (top
->GetParent()) top
= top
->GetParent();
284 top
->RemoveExtraSpacing(true, true);
289 wxFSFile
*wxHtmlWinParser::OpenURL(wxHtmlURLType type
,
290 const wxString
& url
) const
292 if ( !m_windowInterface
)
293 return wxHtmlParser::OpenURL(type
, url
);
296 wxHtmlOpeningStatus status
;
299 wxString
myfullurl(myurl
);
301 // consider url as absolute path first
302 wxURI
current(myurl
);
303 myfullurl
= current
.BuildUnescapedURI();
305 // if not absolute then ...
306 if( current
.IsReference() )
308 wxString basepath
= GetFS()->GetPath();
309 wxURI
base(basepath
);
311 // ... try to apply base path if valid ...
312 if( !base
.IsReference() )
314 wxURI
path(myfullurl
);
315 path
.Resolve( base
);
316 myfullurl
= path
.BuildUnescapedURI();
320 // ... or force such addition if not included already
321 if( !current
.GetPath().Contains(base
.GetPath()) )
324 wxURI
connected( basepath
);
325 myfullurl
= connected
.BuildUnescapedURI();
331 status
= m_windowInterface
->OnHTMLOpeningURL(type
, myfullurl
, &redirect
);
332 if ( status
!= wxHTML_REDIRECT
)
338 if ( status
== wxHTML_BLOCK
)
341 int flags
= wxFS_READ
;
342 if (type
== wxHTML_URL_IMAGE
)
343 flags
|= wxFS_SEEKABLE
;
345 return GetFS()->OpenFile(myurl
, flags
);
348 void wxHtmlWinParser::AddText(const wxString
& txt
)
350 #define NBSP_UNICODE_VALUE (wxChar(160))
353 m_nbsp
= GetEntitiesParser()->GetCharForCode(NBSP_UNICODE_VALUE
);
354 #define CUR_NBSP_VALUE m_nbsp
356 #define CUR_NBSP_VALUE NBSP_UNICODE_VALUE
359 if ( m_whitespaceMode
== Whitespace_Normal
)
363 size_t lng
= txt
.length();
364 if (lng
+1 > m_tmpStrBufSize
)
366 delete[] m_tmpStrBuf
;
367 m_tmpStrBuf
= new wxChar
[lng
+1];
368 m_tmpStrBufSize
= lng
+1;
370 wxChar
*temp
= m_tmpStrBuf
;
372 wxString::const_iterator i
= txt
.begin();
373 const wxString::const_iterator end
= txt
.end();
375 if (m_tmpLastWasSpace
)
378 (*i
== wxT('\n') || *i
== wxT('\r') || *i
== wxT(' ') ||
389 if ((d
== wxT('\n')) || (d
== wxT('\r')) || (d
== wxT(' ')) || (d
== wxT('\t')))
393 (*i
== wxT('\n') || *i
== wxT('\r') ||
394 *i
== wxT(' ') || *i
== wxT('\t')) )
405 if (d
== CUR_NBSP_VALUE
)
412 temp
[templen
-1] = wxT(' ');
413 FlushWordBuf(temp
, templen
);
414 m_tmpLastWasSpace
= true;
418 if (templen
&& (templen
> 1 || temp
[0] != wxT(' ')))
420 FlushWordBuf(temp
, templen
);
421 m_tmpLastWasSpace
= false;
424 else // m_whitespaceMode == Whitespace_Pre
426 if ( txt
.find(CUR_NBSP_VALUE
) != wxString::npos
)
428 // we need to substitute spaces for here just like we
429 // did in the Whitespace_Normal branch above
431 txt2
.Replace(CUR_NBSP_VALUE
, ' ');
439 // don't eat any whitespace in <pre> block
440 m_tmpLastWasSpace
= false;
444 void wxHtmlWinParser::FlushWordBuf(wxChar
*buf
, int& len
)
450 m_EncConv
->Convert(buf
);
453 AddWord(wxString(buf
, len
));
458 void wxHtmlWinParser::AddWord(wxHtmlWordCell
*word
)
460 ApplyStateToCell(word
);
462 m_Container
->InsertCell(word
);
463 word
->SetPreviousWord(m_lastWordCell
);
464 m_lastWordCell
= word
;
467 void wxHtmlWinParser::AddPreBlock(const wxString
& text
)
469 if ( text
.find('\t') != wxString::npos
)
472 text2
.reserve(text
.length());
474 const wxString::const_iterator end
= text
.end();
475 wxString::const_iterator copyFrom
= text
.begin();
478 int posColumn
= m_posColumn
;
479 for ( wxString::const_iterator i
= copyFrom
; i
!= end
; ++i
, ++pos
)
484 text2
.append(copyFrom
, i
);
486 const unsigned SPACES_PER_TAB
= 8;
487 const size_t expandTo
= SPACES_PER_TAB
- posColumn
% SPACES_PER_TAB
;
488 text2
.append(expandTo
, ' ');
490 posColumn
+= expandTo
;
499 if ( copyFrom
!= text
.end() )
500 text2
.append(copyFrom
, text
.end());
502 AddWord(new wxHtmlWordWithTabsCell(text2
, text
, m_posColumn
, *(GetDC())));
504 m_posColumn
= posColumn
;
508 // no special formatting needed
510 m_posColumn
+= text
.length();
515 wxHtmlContainerCell
* wxHtmlWinParser::OpenContainer()
517 m_Container
= new wxHtmlContainerCell(m_Container
);
518 m_Container
->SetAlignHor(m_Align
);
520 m_tmpLastWasSpace
= true;
521 /* to avoid space being first character in paragraph */
527 wxHtmlContainerCell
* wxHtmlWinParser::SetContainer(wxHtmlContainerCell
*c
)
529 m_tmpLastWasSpace
= true;
530 /* to avoid space being first character in paragraph */
531 return m_Container
= c
;
536 wxHtmlContainerCell
* wxHtmlWinParser::CloseContainer()
538 m_Container
= m_Container
->GetParent();
543 void wxHtmlWinParser::SetFontSize(int s
)
554 wxFont
* wxHtmlWinParser::CreateCurrentFont()
556 int fb
= GetFontBold(),
557 fi
= GetFontItalic(),
558 fu
= GetFontUnderlined(),
560 fs
= GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ;
562 wxString face
= ff
? m_FontFaceFixed
: m_FontFaceNormal
;
563 wxString
*faceptr
= &(m_FontsFacesTable
[fb
][fi
][fu
][ff
][fs
]);
564 wxFont
**fontptr
= &(m_FontsTable
[fb
][fi
][fu
][ff
][fs
]);
566 wxFontEncoding
*encptr
= &(m_FontsEncTable
[fb
][fi
][fu
][ff
][fs
]);
569 if (*fontptr
!= NULL
&& (*faceptr
!= face
571 || *encptr
!= m_OutputEnc
579 if (*fontptr
== NULL
)
582 *fontptr
= new wxFont(
583 (int) (m_FontsSizes
[fs
] * m_PixelScale
),
584 ff
? wxMODERN
: wxSWISS
,
585 fi
? wxITALIC
: wxNORMAL
,
586 fb
? wxBOLD
: wxNORMAL
,
587 fu
? true : false, face
592 *encptr
= m_OutputEnc
;
595 m_DC
->SetFont(**fontptr
);
601 void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo
& link
)
604 m_UseLink
= (link
.GetHref() != wxEmptyString
);
607 void wxHtmlWinParser::SetFontFace(const wxString
& face
)
610 m_FontFaceFixed
= face
;
612 m_FontFaceNormal
= face
;
615 if (m_InputEnc
!= wxFONTENCODING_DEFAULT
)
616 SetInputEncoding(m_InputEnc
);
620 void wxHtmlWinParser::ApplyStateToCell(wxHtmlCell
*cell
)
624 cell
->SetLink(GetLink());
626 // apply current script mode settings:
627 cell
->SetScriptMode(GetScriptMode(), GetScriptBaseline());
632 void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc
)
634 // the character used for non-breakable space may change:
637 m_InputEnc
= m_OutputEnc
= wxFONTENCODING_DEFAULT
;
644 if (enc
== wxFONTENCODING_DEFAULT
)
647 wxFontEncoding altfix
, altnorm
;
648 bool availfix
, availnorm
;
650 availnorm
= wxFontMapper::Get()->IsEncodingAvailable(enc
, m_FontFaceNormal
);
651 availfix
= wxFontMapper::Get()->IsEncodingAvailable(enc
, m_FontFaceFixed
);
653 if (availnorm
&& availfix
)
659 else if (wxFontMapper::Get()->GetAltForEncoding(enc
, &altnorm
, m_FontFaceNormal
, false) &&
660 wxFontMapper::Get()->GetAltForEncoding(enc
, &altfix
, m_FontFaceFixed
, false) &&
664 m_OutputEnc
= altnorm
;
668 // at least normal face?
671 else if (wxFontMapper::Get()->GetAltForEncoding(enc
, &altnorm
, m_FontFaceNormal
, false))
673 m_OutputEnc
= altnorm
;
678 // okay, let's convert to ISO_8859-1, available always
679 m_OutputEnc
= wxFONTENCODING_DEFAULT
;
681 m_OutputEnc
= wxLocale::GetSystemEncoding() ;
686 if (m_OutputEnc
== wxFONTENCODING_DEFAULT
)
688 GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM
);
692 GetEntitiesParser()->SetEncoding(m_OutputEnc
);
695 if (m_InputEnc
== m_OutputEnc
)
698 m_EncConv
= new wxEncodingConverter();
699 if (!m_EncConv
->Init(m_InputEnc
,
700 (m_OutputEnc
== wxFONTENCODING_DEFAULT
) ?
701 wxFONTENCODING_ISO8859_1
: m_OutputEnc
,
702 wxCONVERT_SUBSTITUTE
))
703 { // total failure :-(
704 wxLogError(_("Failed to display HTML document in %s encoding"),
705 wxFontMapper::GetEncodingName(enc
).c_str());
706 m_InputEnc
= m_OutputEnc
= wxFONTENCODING_DEFAULT
;
716 //-----------------------------------------------------------------------------
717 // wxHtmlWinTagHandler
718 //-----------------------------------------------------------------------------
720 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler
, wxHtmlTagHandler
)
722 //-----------------------------------------------------------------------------
724 //-----------------------------------------------------------------------------
726 // NB: This is *NOT* winpars.cpp's initialization and shutdown code!!
727 // This module is an ancestor for tag handlers modules defined
728 // in m_*.cpp files with TAGS_MODULE_BEGIN...TAGS_MODULE_END construct.
730 // Do not add any winpars.cpp shutdown or initialization code to it,
731 // create a new module instead!
733 IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule
, wxModule
)
735 bool wxHtmlTagsModule::OnInit()
737 wxHtmlWinParser::AddModule(this);
741 void wxHtmlTagsModule::OnExit()
743 wxHtmlWinParser::RemoveModule(this);