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