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
203 // we're not using GetCharWidth/Height() because of
204 // differences under X and win
206 m_DC
->GetTextExtent( wxT("H"), &w
, &h
);
211 m_Link
= wxHtmlLinkInfo( wxEmptyString
);
212 m_LinkColor
.Set(0, 0, 0xFF);
213 m_ActualColor
.Set(0, 0, 0);
214 m_Align
= wxHTML_ALIGN_LEFT
;
215 m_ScriptMode
= wxHTML_SCRIPT_NORMAL
;
216 m_ScriptBaseline
= 0;
217 m_tmpLastWasSpace
= false;
218 m_lastWordCell
= NULL
;
220 // open the toplevel container that contains everything else and that
221 // is never closed (this makes parser's life easier):
224 // then open the first container into which page's content will go:
228 wxString charset
= ExtractCharsetInformation(source
);
229 if (!charset
.empty())
231 wxFontEncoding enc
= wxFontMapper::Get()->CharsetToEncoding(charset
);
232 if (enc
!= wxFONTENCODING_SYSTEM
)
233 SetInputEncoding(enc
);
237 m_Container
->InsertCell(new wxHtmlColourCell(m_ActualColor
));
238 wxColour windowColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
) ;
240 m_Container
->InsertCell
245 ? m_windowInterface
->GetHTMLBackgroundColour()
247 wxHTML_CLR_BACKGROUND
251 m_Container
->InsertCell(new wxHtmlFontCell(CreateCurrentFont()));
254 void wxHtmlWinParser::DoneParser()
258 SetInputEncoding(wxFONTENCODING_ISO8859_1
); // for next call
260 wxHtmlParser::DoneParser();
263 #if WXWIN_COMPATIBILITY_2_6
264 wxHtmlWindow
*wxHtmlWinParser::GetWindow()
266 if (!m_windowInterface
)
268 return wxDynamicCast(m_windowInterface
->GetHTMLWindow(), wxHtmlWindow
);
272 wxObject
* wxHtmlWinParser::GetProduct()
274 wxHtmlContainerCell
*top
;
280 while (top
->GetParent()) top
= top
->GetParent();
281 top
->RemoveExtraSpacing(true, true);
286 wxFSFile
*wxHtmlWinParser::OpenURL(wxHtmlURLType type
,
287 const wxString
& url
) const
289 if ( !m_windowInterface
)
290 return wxHtmlParser::OpenURL(type
, url
);
293 wxHtmlOpeningStatus status
;
296 wxString
myfullurl(myurl
);
298 // consider url as absolute path first
299 wxURI
current(myurl
);
300 myfullurl
= current
.BuildUnescapedURI();
302 // if not absolute then ...
303 if( current
.IsReference() )
305 wxString basepath
= GetFS()->GetPath();
306 wxURI
base(basepath
);
308 // ... try to apply base path if valid ...
309 if( !base
.IsReference() )
311 wxURI
path(myfullurl
);
312 path
.Resolve( base
);
313 myfullurl
= path
.BuildUnescapedURI();
317 // ... or force such addition if not included already
318 if( !current
.GetPath().Contains(base
.GetPath()) )
321 wxURI
connected( basepath
);
322 myfullurl
= connected
.BuildUnescapedURI();
328 status
= m_windowInterface
->OnHTMLOpeningURL(type
, myfullurl
, &redirect
);
329 if ( status
!= wxHTML_REDIRECT
)
335 if ( status
== wxHTML_BLOCK
)
338 int flags
= wxFS_READ
;
339 if (type
== wxHTML_URL_IMAGE
)
340 flags
|= wxFS_SEEKABLE
;
342 return GetFS()->OpenFile(myurl
, flags
);
345 void wxHtmlWinParser::AddText(const wxChar
* txt
)
352 wxChar nbsp
= GetEntitiesParser()->GetCharForCode(160 /* nbsp */);
354 if (lng
+1 > m_tmpStrBufSize
)
356 delete[] m_tmpStrBuf
;
357 m_tmpStrBuf
= new wxChar
[lng
+1];
358 m_tmpStrBufSize
= lng
+1;
360 wxChar
*temp
= m_tmpStrBuf
;
362 if (m_tmpLastWasSpace
)
365 ((txt
[i
] == wxT('\n')) || (txt
[i
] == wxT('\r')) || (txt
[i
] == wxT(' ')) ||
366 (txt
[i
] == wxT('\t')))) i
++;
372 d
= temp
[templen
++] = txt
[i
];
373 if ((d
== wxT('\n')) || (d
== wxT('\r')) || (d
== wxT(' ')) || (d
== wxT('\t')))
376 while ((i
< lng
) && ((txt
[i
] == wxT('\n')) || (txt
[i
] == wxT('\r')) ||
377 (txt
[i
] == wxT(' ')) || (txt
[i
] == wxT('\t')))) i
++, x
++;
383 temp
[templen
-1] = wxT(' ');
384 DoAddText(temp
, templen
, nbsp
);
385 m_tmpLastWasSpace
= true;
389 if (templen
&& (templen
> 1 || temp
[0] != wxT(' ')))
391 DoAddText(temp
, templen
, nbsp
);
392 m_tmpLastWasSpace
= false;
396 void wxHtmlWinParser::DoAddText(wxChar
*temp
, int& templen
, wxChar nbsp
)
402 m_EncConv
->Convert(temp
);
404 size_t len
= wxStrlen(temp
);
405 for (size_t j
= 0; j
< len
; j
++)
411 wxHtmlCell
*c
= new wxHtmlWordCell(temp
, *(GetDC()));
415 m_Container
->InsertCell(c
);
416 ((wxHtmlWordCell
*)c
)->SetPreviousWord(m_lastWordCell
);
417 m_lastWordCell
= (wxHtmlWordCell
*)c
;
422 wxHtmlContainerCell
* wxHtmlWinParser::OpenContainer()
424 m_Container
= new wxHtmlContainerCell(m_Container
);
425 m_Container
->SetAlignHor(m_Align
);
426 m_tmpLastWasSpace
= true;
427 /* to avoid space being first character in paragraph */
433 wxHtmlContainerCell
* wxHtmlWinParser::SetContainer(wxHtmlContainerCell
*c
)
435 m_tmpLastWasSpace
= true;
436 /* to avoid space being first character in paragraph */
437 return m_Container
= c
;
442 wxHtmlContainerCell
* wxHtmlWinParser::CloseContainer()
444 m_Container
= m_Container
->GetParent();
449 void wxHtmlWinParser::SetFontSize(int s
)
452 else if (s
> 7) s
= 7;
458 wxFont
* wxHtmlWinParser::CreateCurrentFont()
460 int fb
= GetFontBold(),
461 fi
= GetFontItalic(),
462 fu
= GetFontUnderlined(),
464 fs
= GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ;
466 wxString face
= ff
? m_FontFaceFixed
: m_FontFaceNormal
;
467 wxString
*faceptr
= &(m_FontsFacesTable
[fb
][fi
][fu
][ff
][fs
]);
468 wxFont
**fontptr
= &(m_FontsTable
[fb
][fi
][fu
][ff
][fs
]);
470 wxFontEncoding
*encptr
= &(m_FontsEncTable
[fb
][fi
][fu
][ff
][fs
]);
473 if (*fontptr
!= NULL
&& (*faceptr
!= face
475 || *encptr
!= m_OutputEnc
483 if (*fontptr
== NULL
)
486 *fontptr
= new wxFont(
487 (int) (m_FontsSizes
[fs
] * m_PixelScale
),
488 ff
? wxMODERN
: wxSWISS
,
489 fi
? wxITALIC
: wxNORMAL
,
490 fb
? wxBOLD
: wxNORMAL
,
491 fu
? true : false, face
496 *encptr
= m_OutputEnc
;
499 m_DC
->SetFont(**fontptr
);
505 void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo
& link
)
508 m_UseLink
= (link
.GetHref() != wxEmptyString
);
511 void wxHtmlWinParser::SetFontFace(const wxString
& face
)
513 if (GetFontFixed()) m_FontFaceFixed
= face
;
514 else m_FontFaceNormal
= face
;
517 if (m_InputEnc
!= wxFONTENCODING_DEFAULT
)
518 SetInputEncoding(m_InputEnc
);
522 void wxHtmlWinParser::ApplyStateToCell(wxHtmlCell
*cell
)
526 cell
->SetLink(GetLink());
528 // apply current script mode settings:
529 cell
->SetScriptMode(GetScriptMode(), GetScriptBaseline());
534 void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc
)
536 m_InputEnc
= m_OutputEnc
= wxFONTENCODING_DEFAULT
;
543 if (enc
== wxFONTENCODING_DEFAULT
) return;
545 wxFontEncoding altfix
, altnorm
;
546 bool availfix
, availnorm
;
549 availnorm
= wxFontMapper::Get()->IsEncodingAvailable(enc
, m_FontFaceNormal
);
550 availfix
= wxFontMapper::Get()->IsEncodingAvailable(enc
, m_FontFaceFixed
);
551 if (availnorm
&& availfix
)
555 else if (wxFontMapper::Get()->GetAltForEncoding(enc
, &altnorm
, m_FontFaceNormal
, false) &&
556 wxFontMapper::Get()->GetAltForEncoding(enc
, &altfix
, m_FontFaceFixed
, false) &&
558 m_OutputEnc
= altnorm
;
560 // at least normal face?
563 else if (wxFontMapper::Get()->GetAltForEncoding(enc
, &altnorm
, m_FontFaceNormal
, false))
564 m_OutputEnc
= altnorm
;
569 // okay, let's convert to ISO_8859-1, available always
570 m_OutputEnc
= wxFONTENCODING_DEFAULT
;
572 m_OutputEnc
= wxLocale::GetSystemEncoding() ;
577 if (m_OutputEnc
== wxFONTENCODING_DEFAULT
)
578 GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM
);
580 GetEntitiesParser()->SetEncoding(m_OutputEnc
);
582 if (m_InputEnc
== m_OutputEnc
) return;
584 m_EncConv
= new wxEncodingConverter();
585 if (!m_EncConv
->Init(m_InputEnc
,
586 (m_OutputEnc
== wxFONTENCODING_DEFAULT
) ?
587 wxFONTENCODING_ISO8859_1
: m_OutputEnc
,
588 wxCONVERT_SUBSTITUTE
))
589 { // total failure :-(
590 wxLogError(_("Failed to display HTML document in %s encoding"),
591 wxFontMapper::GetEncodingName(enc
).c_str());
592 m_InputEnc
= m_OutputEnc
= wxFONTENCODING_DEFAULT
;
602 //-----------------------------------------------------------------------------
603 // wxHtmlWinTagHandler
604 //-----------------------------------------------------------------------------
606 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler
, wxHtmlTagHandler
)
608 //-----------------------------------------------------------------------------
610 //-----------------------------------------------------------------------------
612 // NB: This is *NOT* winpars.cpp's initialization and shutdown code!!
613 // This module is an ancestor for tag handlers modules defined
614 // in m_*.cpp files with TAGS_MODULE_BEGIN...TAGS_MODULE_END construct.
616 // Do not add any winpars.cpp shutdown or initialization code to it,
617 // create a new module instead!
619 IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule
, wxModule
)
621 bool wxHtmlTagsModule::OnInit()
623 wxHtmlWinParser::AddModule(this);
627 void wxHtmlTagsModule::OnExit()
629 wxHtmlWinParser::RemoveModule(this);