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