1. added abstract interface to wxHtmlWindow for use by wxHtmlWinParser and implemente...
[wxWidgets.git] / src / html / winpars.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: winpars.cpp
3 // Purpose: wxHtmlParser class (generic parser)
4 // Author: Vaclav Slavik
5 // RCS-ID: $Id$
6 // Copyright: (c) 1999 Vaclav Slavik
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #include "wx/wxprec.h"
11
12 #include "wx/defs.h"
13 #if wxUSE_HTML && wxUSE_STREAMS
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WXPRECOMP
20 #include "wx/intl.h"
21 #include "wx/dc.h"
22 #endif
23
24 #include "wx/html/htmldefs.h"
25 #include "wx/html/winpars.h"
26 #include "wx/html/htmlwin.h"
27 #include "wx/fontmap.h"
28 #include "wx/log.h"
29 #include "wx/settings.h"
30 #include "wx/uri.h"
31
32
33 //-----------------------------------------------------------------------------
34 // wxHtmlWinParser
35 //-----------------------------------------------------------------------------
36
37 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinParser, wxHtmlParser)
38
39 wxList wxHtmlWinParser::m_Modules;
40
41 wxHtmlWinParser::wxHtmlWinParser(wxHtmlWindowInterface *wndIface)
42 {
43 m_tmpStrBuf = NULL;
44 m_tmpStrBufSize = 0;
45 m_windowInterface = wndIface;
46 m_Container = NULL;
47 m_DC = NULL;
48 m_CharHeight = m_CharWidth = 0;
49 m_UseLink = false;
50 #if !wxUSE_UNICODE
51 m_EncConv = NULL;
52 m_InputEnc = wxFONTENCODING_ISO8859_1;
53 m_OutputEnc = wxFONTENCODING_DEFAULT;
54 #endif
55 m_lastWordCell = NULL;
56
57 {
58 int i, j, k, l, m;
59 for (i = 0; i < 2; i++)
60 for (j = 0; j < 2; j++)
61 for (k = 0; k < 2; k++)
62 for (l = 0; l < 2; l++)
63 for (m = 0; m < 7; m++)
64 {
65 m_FontsTable[i][j][k][l][m] = NULL;
66 m_FontsFacesTable[i][j][k][l][m] = wxEmptyString;
67 #if !wxUSE_UNICODE
68 m_FontsEncTable[i][j][k][l][m] = wxFONTENCODING_DEFAULT;
69 #endif
70 }
71
72 SetFonts(wxEmptyString, wxEmptyString, NULL);
73 }
74
75 // fill in wxHtmlParser's tables:
76 wxList::compatibility_iterator node = m_Modules.GetFirst();
77 while (node)
78 {
79 wxHtmlTagsModule *mod = (wxHtmlTagsModule*) node->GetData();
80 mod->FillHandlersTable(this);
81 node = node->GetNext();
82 }
83 }
84
85 wxHtmlWinParser::~wxHtmlWinParser()
86 {
87 int i, j, k, l, m;
88
89 for (i = 0; i < 2; i++)
90 for (j = 0; j < 2; j++)
91 for (k = 0; k < 2; k++)
92 for (l = 0; l < 2; l++)
93 for (m = 0; m < 7; m++)
94 {
95 if (m_FontsTable[i][j][k][l][m] != NULL)
96 delete m_FontsTable[i][j][k][l][m];
97 }
98 #if !wxUSE_UNICODE
99 delete m_EncConv;
100 #endif
101 delete[] m_tmpStrBuf;
102 }
103
104 void wxHtmlWinParser::AddModule(wxHtmlTagsModule *module)
105 {
106 m_Modules.Append(module);
107 }
108
109 void wxHtmlWinParser::RemoveModule(wxHtmlTagsModule *module)
110 {
111 m_Modules.DeleteObject(module);
112 }
113
114 void wxHtmlWinParser::SetFonts(const wxString& normal_face, const wxString& fixed_face,
115 const int *sizes)
116 {
117 static int default_sizes[7] =
118 {
119 wxHTML_FONT_SIZE_1,
120 wxHTML_FONT_SIZE_2,
121 wxHTML_FONT_SIZE_3,
122 wxHTML_FONT_SIZE_4,
123 wxHTML_FONT_SIZE_5,
124 wxHTML_FONT_SIZE_6,
125 wxHTML_FONT_SIZE_7
126 };
127
128 if (sizes == NULL) sizes = default_sizes;
129
130 int i, j, k, l, m;
131
132 for (i = 0; i < 7; i++) m_FontsSizes[i] = sizes[i];
133 m_FontFaceFixed = fixed_face;
134 m_FontFaceNormal = normal_face;
135
136 #if !wxUSE_UNICODE
137 SetInputEncoding(m_InputEnc);
138 #endif
139
140 for (i = 0; i < 2; i++)
141 for (j = 0; j < 2; j++)
142 for (k = 0; k < 2; k++)
143 for (l = 0; l < 2; l++)
144 for (m = 0; m < 7; m++) {
145 if (m_FontsTable[i][j][k][l][m] != NULL)
146 {
147 delete m_FontsTable[i][j][k][l][m];
148 m_FontsTable[i][j][k][l][m] = NULL;
149 }
150 }
151 }
152
153 void wxHtmlWinParser::SetStandardFonts(int size,
154 const wxString& normal_face,
155 const wxString& fixed_face)
156 {
157 wxFont defaultFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
158
159 int f_sizes[7];
160 if (size == -1)
161 size = defaultFont.GetPointSize();
162
163 f_sizes[0] = int(size * 0.6);
164 f_sizes[1] = int(size * 0.8);
165 f_sizes[2] = size;
166 f_sizes[3] = int(size * 1.2);
167 f_sizes[4] = int(size * 1.4);
168 f_sizes[5] = int(size * 1.6);
169 f_sizes[6] = int(size * 1.8);
170
171 wxString normal = normal_face.empty() ?
172 defaultFont.GetFaceName() : normal_face;
173
174 SetFonts(normal, fixed_face, f_sizes);
175 }
176
177 void wxHtmlWinParser::InitParser(const wxString& source)
178 {
179 wxHtmlParser::InitParser(source);
180 wxASSERT_MSG(m_DC != NULL, wxT("no DC assigned to wxHtmlWinParser!!"));
181
182 m_FontBold = m_FontItalic = m_FontUnderlined = m_FontFixed = FALSE;
183 m_FontSize = 3; //default one
184 CreateCurrentFont(); // we're selecting default font into
185 m_DC->GetTextExtent( wxT("H"), &m_CharWidth, &m_CharHeight);
186 /* NOTE : we're not using GetCharWidth/Height() because
187 of differences under X and win
188 */
189
190 m_UseLink = false;
191 m_Link = wxHtmlLinkInfo( wxEmptyString );
192 m_LinkColor.Set(0, 0, 0xFF);
193 m_ActualColor.Set(0, 0, 0);
194 m_Align = wxHTML_ALIGN_LEFT;
195 m_ScriptMode = wxHTML_SCRIPT_NORMAL;
196 m_ScriptBaseline = 0;
197 m_tmpLastWasSpace = false;
198 m_lastWordCell = NULL;
199
200 OpenContainer();
201 OpenContainer();
202
203 #if !wxUSE_UNICODE
204 wxString charset = ExtractCharsetInformation(source);
205 if (!charset.empty())
206 {
207 wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(charset);
208 if (enc != wxFONTENCODING_SYSTEM)
209 SetInputEncoding(enc);
210 }
211 #endif
212
213 m_Container->InsertCell(new wxHtmlColourCell(m_ActualColor));
214 wxColour windowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW) ;
215
216 m_Container->InsertCell
217 (
218 new wxHtmlColourCell
219 (
220 m_windowInterface
221 ? m_windowInterface->GetHTMLBackgroundColour()
222 : windowColour,
223 wxHTML_CLR_BACKGROUND
224 )
225 );
226
227 m_Container->InsertCell(new wxHtmlFontCell(CreateCurrentFont()));
228 }
229
230 void wxHtmlWinParser::DoneParser()
231 {
232 m_Container = NULL;
233 #if !wxUSE_UNICODE
234 SetInputEncoding(wxFONTENCODING_ISO8859_1); // for next call
235 #endif
236 wxHtmlParser::DoneParser();
237 }
238
239 #if WXWIN_COMPATIBILITY_2_6
240 wxHtmlWindow *wxHtmlWinParser::GetWindow()
241 {
242 if (!m_windowInterface)
243 return NULL;
244 return wxDynamicCast(m_windowInterface->GetHTMLWindow(), wxHtmlWindow);
245 }
246 #endif
247
248 wxObject* wxHtmlWinParser::GetProduct()
249 {
250 wxHtmlContainerCell *top;
251
252 CloseContainer();
253 OpenContainer();
254
255 top = m_Container;
256 while (top->GetParent()) top = top->GetParent();
257 top->RemoveExtraSpacing(true, true);
258
259 return top;
260 }
261
262 wxFSFile *wxHtmlWinParser::OpenURL(wxHtmlURLType type,
263 const wxString& url) const
264 {
265 if ( !m_windowInterface )
266 return wxHtmlParser::OpenURL(type, url);
267
268 wxString myurl(url);
269 wxHtmlOpeningStatus status;
270 for (;;)
271 {
272 wxString myfullurl(myurl);
273
274 // consider url as absolute path first
275 wxURI current(myurl);
276 myfullurl = current.BuildUnescapedURI();
277
278 // if not absolute then ...
279 if( current.IsReference() )
280 {
281 wxString basepath = GetFS()->GetPath();
282 wxURI base(basepath);
283
284 // ... try to apply base path if valid ...
285 if( !base.IsReference() )
286 {
287 wxURI path(myfullurl);
288 path.Resolve( base );
289 myfullurl = path.BuildUnescapedURI();
290 }
291 else
292 {
293 // ... or force such addition if not included already
294 if( !current.GetPath().Contains(base.GetPath()) )
295 {
296 basepath += myurl;
297 wxURI connected( basepath );
298 myfullurl = connected.BuildUnescapedURI();
299 }
300 }
301 }
302
303 wxString redirect;
304 status = m_windowInterface->OnHTMLOpeningURL(type, myfullurl, &redirect);
305 if ( status != wxHTML_REDIRECT )
306 break;
307
308 myurl = redirect;
309 }
310
311 if ( status == wxHTML_BLOCK )
312 return NULL;
313
314 return GetFS()->OpenFile(myurl);
315 }
316
317 void wxHtmlWinParser::AddText(const wxChar* txt)
318 {
319 size_t i = 0,
320 x,
321 lng = wxStrlen(txt);
322 register wxChar d;
323 int templen = 0;
324 wxChar nbsp = GetEntitiesParser()->GetCharForCode(160 /* nbsp */);
325
326 if (lng+1 > m_tmpStrBufSize)
327 {
328 delete[] m_tmpStrBuf;
329 m_tmpStrBuf = new wxChar[lng+1];
330 m_tmpStrBufSize = lng+1;
331 }
332 wxChar *temp = m_tmpStrBuf;
333
334 if (m_tmpLastWasSpace)
335 {
336 while ((i < lng) &&
337 ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) || (txt[i] == wxT(' ')) ||
338 (txt[i] == wxT('\t')))) i++;
339 }
340
341 while (i < lng)
342 {
343 x = 0;
344 d = temp[templen++] = txt[i];
345 if ((d == wxT('\n')) || (d == wxT('\r')) || (d == wxT(' ')) || (d == wxT('\t')))
346 {
347 i++, x++;
348 while ((i < lng) && ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) ||
349 (txt[i] == wxT(' ')) || (txt[i] == wxT('\t')))) i++, x++;
350 }
351 else i++;
352
353 if (x)
354 {
355 temp[templen-1] = wxT(' ');
356 DoAddText(temp, templen, nbsp);
357 m_tmpLastWasSpace = true;
358 }
359 }
360
361 if (templen && (templen > 1 || temp[0] != wxT(' ')))
362 {
363 DoAddText(temp, templen, nbsp);
364 m_tmpLastWasSpace = false;
365 }
366 }
367
368 void wxHtmlWinParser::DoAddText(wxChar *temp, int& templen, wxChar nbsp)
369 {
370 temp[templen] = 0;
371 templen = 0;
372 #if !wxUSE_UNICODE
373 if (m_EncConv)
374 m_EncConv->Convert(temp);
375 #endif
376 size_t len = wxStrlen(temp);
377 for (size_t j = 0; j < len; j++)
378 {
379 if (temp[j] == nbsp)
380 temp[j] = wxT(' ');
381 }
382
383 wxHtmlCell *c = new wxHtmlWordCell(temp, *(GetDC()));
384
385 ApplyStateToCell(c);
386
387 m_Container->InsertCell(c);
388 ((wxHtmlWordCell*)c)->SetPreviousWord(m_lastWordCell);
389 m_lastWordCell = (wxHtmlWordCell*)c;
390 }
391
392
393
394 wxHtmlContainerCell* wxHtmlWinParser::OpenContainer()
395 {
396 m_Container = new wxHtmlContainerCell(m_Container);
397 m_Container->SetAlignHor(m_Align);
398 m_tmpLastWasSpace = true;
399 /* to avoid space being first character in paragraph */
400 return m_Container;
401 }
402
403
404
405 wxHtmlContainerCell* wxHtmlWinParser::SetContainer(wxHtmlContainerCell *c)
406 {
407 m_tmpLastWasSpace = true;
408 /* to avoid space being first character in paragraph */
409 return m_Container = c;
410 }
411
412
413
414 wxHtmlContainerCell* wxHtmlWinParser::CloseContainer()
415 {
416 m_Container = m_Container->GetParent();
417 return m_Container;
418 }
419
420
421 void wxHtmlWinParser::SetFontSize(int s)
422 {
423 if (s < 1) s = 1;
424 else if (s > 7) s = 7;
425 m_FontSize = s;
426 }
427
428
429
430 wxFont* wxHtmlWinParser::CreateCurrentFont()
431 {
432 int fb = GetFontBold(),
433 fi = GetFontItalic(),
434 fu = GetFontUnderlined(),
435 ff = GetFontFixed(),
436 fs = GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ;
437
438 wxString face = ff ? m_FontFaceFixed : m_FontFaceNormal;
439 wxString *faceptr = &(m_FontsFacesTable[fb][fi][fu][ff][fs]);
440 wxFont **fontptr = &(m_FontsTable[fb][fi][fu][ff][fs]);
441 #if !wxUSE_UNICODE
442 wxFontEncoding *encptr = &(m_FontsEncTable[fb][fi][fu][ff][fs]);
443 #endif
444
445 if (*fontptr != NULL && (*faceptr != face
446 #if !wxUSE_UNICODE
447 || *encptr != m_OutputEnc
448 #endif
449 ))
450 {
451 delete *fontptr;
452 *fontptr = NULL;
453 }
454
455 if (*fontptr == NULL)
456 {
457 *faceptr = face;
458 *fontptr = new wxFont(
459 (int) (m_FontsSizes[fs] * m_PixelScale),
460 ff ? wxMODERN : wxSWISS,
461 fi ? wxITALIC : wxNORMAL,
462 fb ? wxBOLD : wxNORMAL,
463 fu ? true : false, face
464 #if wxUSE_UNICODE
465 );
466 #else
467 , m_OutputEnc);
468 *encptr = m_OutputEnc;
469 #endif
470 }
471 m_DC->SetFont(**fontptr);
472 return (*fontptr);
473 }
474
475
476
477 void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo& link)
478 {
479 m_Link = link;
480 m_UseLink = (link.GetHref() != wxEmptyString);
481 }
482
483 void wxHtmlWinParser::SetFontFace(const wxString& face)
484 {
485 if (GetFontFixed()) m_FontFaceFixed = face;
486 else m_FontFaceNormal = face;
487
488 #if !wxUSE_UNICODE
489 if (m_InputEnc != wxFONTENCODING_DEFAULT)
490 SetInputEncoding(m_InputEnc);
491 #endif
492 }
493
494 void wxHtmlWinParser::ApplyStateToCell(wxHtmlCell *cell)
495 {
496 // set the link:
497 if (m_UseLink)
498 cell->SetLink(GetLink());
499
500 // apply current script mode settings:
501 cell->SetScriptMode(GetScriptMode(), GetScriptBaseline());
502 }
503
504
505 #if !wxUSE_UNICODE
506 void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc)
507 {
508 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
509 if (m_EncConv)
510 {
511 delete m_EncConv;
512 m_EncConv = NULL;
513 }
514
515 if (enc == wxFONTENCODING_DEFAULT) return;
516
517 wxFontEncoding altfix, altnorm;
518 bool availfix, availnorm;
519
520 // exact match?
521 availnorm = wxFontMapper::Get()->IsEncodingAvailable(enc, m_FontFaceNormal);
522 availfix = wxFontMapper::Get()->IsEncodingAvailable(enc, m_FontFaceFixed);
523 if (availnorm && availfix)
524 m_OutputEnc = enc;
525
526 // alternatives?
527 else if (wxFontMapper::Get()->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, false) &&
528 wxFontMapper::Get()->GetAltForEncoding(enc, &altfix, m_FontFaceFixed, false) &&
529 altnorm == altfix)
530 m_OutputEnc = altnorm;
531
532 // at least normal face?
533 else if (availnorm)
534 m_OutputEnc = enc;
535 else if (wxFontMapper::Get()->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, false))
536 m_OutputEnc = altnorm;
537
538 else
539 {
540 #ifndef __WXMAC__
541 // okay, let convert to ISO_8859-1, available always
542 m_OutputEnc = wxFONTENCODING_DEFAULT;
543 #else
544 m_OutputEnc = wxLocale::GetSystemEncoding() ;
545 #endif
546 }
547
548 m_InputEnc = enc;
549 if (m_OutputEnc == wxFONTENCODING_DEFAULT)
550 GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM);
551 else
552 GetEntitiesParser()->SetEncoding(m_OutputEnc);
553
554 if (m_InputEnc == m_OutputEnc) return;
555
556 m_EncConv = new wxEncodingConverter();
557 if (!m_EncConv->Init(m_InputEnc,
558 (m_OutputEnc == wxFONTENCODING_DEFAULT) ?
559 wxFONTENCODING_ISO8859_1 : m_OutputEnc,
560 wxCONVERT_SUBSTITUTE))
561 { // total failture :-(
562 wxLogError(_("Failed to display HTML document in %s encoding"),
563 wxFontMapper::GetEncodingName(enc).c_str());
564 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
565 delete m_EncConv;
566 m_EncConv = NULL;
567 }
568 }
569 #endif
570
571
572
573
574 //-----------------------------------------------------------------------------
575 // wxHtmlWinTagHandler
576 //-----------------------------------------------------------------------------
577
578 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler, wxHtmlTagHandler)
579
580 //-----------------------------------------------------------------------------
581 // wxHtmlTagsModule
582 //-----------------------------------------------------------------------------
583
584 // NB: This is *NOT* winpars.cpp's initialization and shutdown code!!
585 // This module is an ancestor for tag handlers modules defined
586 // in m_*.cpp files with TAGS_MODULE_BEGIN...TAGS_MODULE_END construct.
587 //
588 // Do not add any winpars.cpp shutdown or initialization code to it,
589 // create a new module instead!
590
591 IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule, wxModule)
592
593 bool wxHtmlTagsModule::OnInit()
594 {
595 wxHtmlWinParser::AddModule(this);
596 return true;
597 }
598
599 void wxHtmlTagsModule::OnExit()
600 {
601 wxHtmlWinParser::RemoveModule(this);
602 }
603
604 #endif
605