]> git.saurik.com Git - wxWidgets.git/blob - src/html/winpars.cpp
rewrite core foundation conversion to be efficient, double-pass mac WC2MB to verify...
[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::SetStandardFonts(int size,
158 const wxString& normal_face,
159 const wxString& fixed_face)
160 {
161 wxFont defaultFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
162
163 int f_sizes[7];
164 if (size == -1)
165 size = defaultFont.GetPointSize();
166
167 f_sizes[0] = int(size * 0.6);
168 f_sizes[1] = int(size * 0.8);
169 f_sizes[2] = size;
170 f_sizes[3] = int(size * 1.2);
171 f_sizes[4] = int(size * 1.4);
172 f_sizes[5] = int(size * 1.6);
173 f_sizes[6] = int(size * 1.8);
174
175 wxString normal = normal_face.empty() ?
176 defaultFont.GetFaceName() : normal_face;
177
178 SetFonts(normal, fixed_face, f_sizes);
179 }
180
181 void wxHtmlWinParser::InitParser(const wxString& source)
182 {
183 wxHtmlParser::InitParser(source);
184 wxASSERT_MSG(m_DC != NULL, wxT("no DC assigned to wxHtmlWinParser!!"));
185
186 m_FontBold = m_FontItalic = m_FontUnderlined = m_FontFixed = FALSE;
187 m_FontSize = 3; //default one
188 CreateCurrentFont(); // we're selecting default font into
189 m_DC->GetTextExtent( wxT("H"), &m_CharWidth, &m_CharHeight);
190 /* NOTE : we're not using GetCharWidth/Height() because
191 of differences under X and win
192 */
193
194 m_UseLink = false;
195 m_Link = wxHtmlLinkInfo( wxT(""), wxT("") );
196 m_LinkColor.Set(0, 0, 0xFF);
197 m_ActualColor.Set(0, 0, 0);
198 m_Align = wxHTML_ALIGN_LEFT;
199 m_tmpLastWasSpace = false;
200 m_lastWordCell = NULL;
201
202 OpenContainer();
203 OpenContainer();
204
205 #if !wxUSE_UNICODE
206 wxString charset = ExtractCharsetInformation(source);
207 if (!charset.empty())
208 {
209 wxFontEncoding enc = wxFontMapper::Get()->CharsetToEncoding(charset);
210 if (enc != wxFONTENCODING_SYSTEM)
211 SetInputEncoding(enc);
212 }
213 #endif
214
215 m_Container->InsertCell(new wxHtmlColourCell(m_ActualColor));
216 wxColour windowColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW) ;
217 m_Container->InsertCell(
218 new wxHtmlColourCell(GetWindow() ?
219 GetWindow()->GetBackgroundColour() :
220 windowColour,
221 wxHTML_CLR_BACKGROUND));
222 m_Container->InsertCell(new wxHtmlFontCell(CreateCurrentFont()));
223 }
224
225 void wxHtmlWinParser::DoneParser()
226 {
227 m_Container = NULL;
228 #if !wxUSE_UNICODE
229 SetInputEncoding(wxFONTENCODING_ISO8859_1); // for next call
230 #endif
231 wxHtmlParser::DoneParser();
232 }
233
234 wxObject* wxHtmlWinParser::GetProduct()
235 {
236 wxHtmlContainerCell *top;
237
238 CloseContainer();
239 OpenContainer();
240
241 top = m_Container;
242 while (top->GetParent()) top = top->GetParent();
243 top->RemoveExtraSpacing(true, true);
244
245 return top;
246 }
247
248 wxFSFile *wxHtmlWinParser::OpenURL(wxHtmlURLType type,
249 const wxString& url) const
250 {
251 // FIXME - normalize the URL to full path before passing to
252 // OnOpeningURL!!
253 if ( m_Window )
254 {
255 wxString myurl(url);
256 wxHtmlOpeningStatus status;
257 for (;;)
258 {
259 wxString redirect;
260 status = m_Window->OnOpeningURL(type, myurl, &redirect);
261 if ( status != wxHTML_REDIRECT )
262 break;
263
264 myurl = redirect;
265 }
266
267 if ( status == wxHTML_BLOCK )
268 return NULL;
269
270 return GetFS()->OpenFile(myurl);
271 }
272
273 return wxHtmlParser::OpenURL(type, url);
274 }
275
276 void wxHtmlWinParser::AddText(const wxChar* txt)
277 {
278 wxHtmlCell *c;
279 size_t i = 0,
280 x,
281 lng = wxStrlen(txt);
282 register wxChar d;
283 int templen = 0;
284 wxChar nbsp = GetEntitiesParser()->GetCharForCode(160 /* nbsp */);
285
286 if (lng+1 > m_tmpStrBufSize)
287 {
288 delete[] m_tmpStrBuf;
289 m_tmpStrBuf = new wxChar[lng+1];
290 m_tmpStrBufSize = lng+1;
291 }
292 wxChar *temp = m_tmpStrBuf;
293
294 if (m_tmpLastWasSpace)
295 {
296 while ((i < lng) &&
297 ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) || (txt[i] == wxT(' ')) ||
298 (txt[i] == wxT('\t')))) i++;
299 }
300
301 while (i < lng)
302 {
303 x = 0;
304 d = temp[templen++] = txt[i];
305 if ((d == wxT('\n')) || (d == wxT('\r')) || (d == wxT(' ')) || (d == wxT('\t')))
306 {
307 i++, x++;
308 while ((i < lng) && ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) ||
309 (txt[i] == wxT(' ')) || (txt[i] == wxT('\t')))) i++, x++;
310 }
311 else i++;
312
313 if (x)
314 {
315 temp[templen-1] = wxT(' ');
316 temp[templen] = 0;
317 templen = 0;
318 #if !wxUSE_UNICODE
319 if (m_EncConv)
320 m_EncConv->Convert(temp);
321 #endif
322 size_t len = wxStrlen(temp);
323 for (size_t j = 0; j < len; j++)
324 if (temp[j] == nbsp)
325 temp[j] = wxT(' ');
326 c = new wxHtmlWordCell(temp, *(GetDC()));
327 if (m_UseLink)
328 c->SetLink(m_Link);
329 m_Container->InsertCell(c);
330 ((wxHtmlWordCell*)c)->SetPreviousWord(m_lastWordCell);
331 m_lastWordCell = (wxHtmlWordCell*)c;
332 m_tmpLastWasSpace = true;
333 }
334 }
335
336 if (templen && (templen > 1 || temp[0] != wxT(' ')))
337 {
338 temp[templen] = 0;
339 #if !wxUSE_UNICODE
340 if (m_EncConv)
341 m_EncConv->Convert(temp);
342 #endif
343 size_t len = wxStrlen(temp);
344 for (size_t j = 0; j < len; j++)
345 if (temp[j] == nbsp)
346 temp[j] = wxT(' ');
347 c = new wxHtmlWordCell(temp, *(GetDC()));
348 if (m_UseLink)
349 c->SetLink(m_Link);
350 m_Container->InsertCell(c);
351 ((wxHtmlWordCell*)c)->SetPreviousWord(m_lastWordCell);
352 m_lastWordCell = (wxHtmlWordCell*)c;
353 m_tmpLastWasSpace = false;
354 }
355 }
356
357
358
359 wxHtmlContainerCell* wxHtmlWinParser::OpenContainer()
360 {
361 m_Container = new wxHtmlContainerCell(m_Container);
362 m_Container->SetAlignHor(m_Align);
363 m_tmpLastWasSpace = true;
364 /* to avoid space being first character in paragraph */
365 return m_Container;
366 }
367
368
369
370 wxHtmlContainerCell* wxHtmlWinParser::SetContainer(wxHtmlContainerCell *c)
371 {
372 m_tmpLastWasSpace = true;
373 /* to avoid space being first character in paragraph */
374 return m_Container = c;
375 }
376
377
378
379 wxHtmlContainerCell* wxHtmlWinParser::CloseContainer()
380 {
381 m_Container = m_Container->GetParent();
382 return m_Container;
383 }
384
385
386 void wxHtmlWinParser::SetFontSize(int s)
387 {
388 if (s < 1) s = 1;
389 else if (s > 7) s = 7;
390 m_FontSize = s;
391 }
392
393
394
395 wxFont* wxHtmlWinParser::CreateCurrentFont()
396 {
397 int fb = GetFontBold(),
398 fi = GetFontItalic(),
399 fu = GetFontUnderlined(),
400 ff = GetFontFixed(),
401 fs = GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ;
402
403 wxString face = ff ? m_FontFaceFixed : m_FontFaceNormal;
404 wxString *faceptr = &(m_FontsFacesTable[fb][fi][fu][ff][fs]);
405 wxFont **fontptr = &(m_FontsTable[fb][fi][fu][ff][fs]);
406 #if !wxUSE_UNICODE
407 wxFontEncoding *encptr = &(m_FontsEncTable[fb][fi][fu][ff][fs]);
408 #endif
409
410 if (*fontptr != NULL && (*faceptr != face
411 #if !wxUSE_UNICODE
412 || *encptr != m_OutputEnc
413 #endif
414 ))
415 {
416 delete *fontptr;
417 *fontptr = NULL;
418 }
419
420 if (*fontptr == NULL)
421 {
422 *faceptr = face;
423 *fontptr = new wxFont(
424 (int) (m_FontsSizes[fs] * m_PixelScale),
425 ff ? wxMODERN : wxSWISS,
426 fi ? wxITALIC : wxNORMAL,
427 fb ? wxBOLD : wxNORMAL,
428 fu ? true : false, face
429 #if wxUSE_UNICODE
430 );
431 #else
432 , m_OutputEnc);
433 *encptr = m_OutputEnc;
434 #endif
435 }
436 m_DC->SetFont(**fontptr);
437 return (*fontptr);
438 }
439
440
441
442 void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo& link)
443 {
444 m_Link = link;
445 m_UseLink = (link.GetHref() != wxEmptyString);
446 }
447
448
449 void wxHtmlWinParser::SetFontFace(const wxString& face)
450 {
451 if (GetFontFixed()) m_FontFaceFixed = face;
452 else m_FontFaceNormal = face;
453
454 #if !wxUSE_UNICODE
455 if (m_InputEnc != wxFONTENCODING_DEFAULT)
456 SetInputEncoding(m_InputEnc);
457 #endif
458 }
459
460
461
462 #if !wxUSE_UNICODE
463 void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc)
464 {
465 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
466 if (m_EncConv)
467 {
468 delete m_EncConv;
469 m_EncConv = NULL;
470 }
471
472 if (enc == wxFONTENCODING_DEFAULT) return;
473
474 wxFontEncoding altfix, altnorm;
475 bool availfix, availnorm;
476
477 // exact match?
478 availnorm = wxFontMapper::Get()->IsEncodingAvailable(enc, m_FontFaceNormal);
479 availfix = wxFontMapper::Get()->IsEncodingAvailable(enc, m_FontFaceFixed);
480 if (availnorm && availfix)
481 m_OutputEnc = enc;
482
483 // alternatives?
484 else if (wxFontMapper::Get()->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, false) &&
485 wxFontMapper::Get()->GetAltForEncoding(enc, &altfix, m_FontFaceFixed, false) &&
486 altnorm == altfix)
487 m_OutputEnc = altnorm;
488
489 // at least normal face?
490 else if (availnorm)
491 m_OutputEnc = enc;
492 else if (wxFontMapper::Get()->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, false))
493 m_OutputEnc = altnorm;
494
495 else
496 {
497 #ifndef __WXMAC__
498 // okay, let convert to ISO_8859-1, available always
499 m_OutputEnc = wxFONTENCODING_DEFAULT;
500 #else
501 m_OutputEnc = wxLocale::GetSystemEncoding() ;
502 #endif
503 }
504
505 m_InputEnc = enc;
506 if (m_OutputEnc == wxFONTENCODING_DEFAULT)
507 GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM);
508 else
509 GetEntitiesParser()->SetEncoding(m_OutputEnc);
510
511 if (m_InputEnc == m_OutputEnc) return;
512
513 m_EncConv = new wxEncodingConverter();
514 if (!m_EncConv->Init(m_InputEnc,
515 (m_OutputEnc == wxFONTENCODING_DEFAULT) ?
516 wxFONTENCODING_ISO8859_1 : m_OutputEnc,
517 wxCONVERT_SUBSTITUTE))
518 { // total failture :-(
519 wxLogError(_("Failed to display HTML document in %s encoding"),
520 wxFontMapper::GetEncodingName(enc).c_str());
521 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
522 delete m_EncConv;
523 m_EncConv = NULL;
524 }
525 }
526 #endif
527
528
529
530
531 //-----------------------------------------------------------------------------
532 // wxHtmlWinTagHandler
533 //-----------------------------------------------------------------------------
534
535 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler, wxHtmlTagHandler)
536
537 //-----------------------------------------------------------------------------
538 // wxHtmlTagsModule
539 //-----------------------------------------------------------------------------
540
541 // NB: This is *NOT* winpars.cpp's initialization and shutdown code!!
542 // This module is an ancestor for tag handlers modules defined
543 // in m_*.cpp files with TAGS_MODULE_BEGIN...TAGS_MODULE_END construct.
544 //
545 // Do not add any winpars.cpp shutdown or initialization code to it,
546 // create a new module instead!
547
548 IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule, wxModule)
549
550 bool wxHtmlTagsModule::OnInit()
551 {
552 wxHtmlWinParser::AddModule(this);
553 return true;
554 }
555
556 void wxHtmlTagsModule::OnExit()
557 {
558 wxHtmlWinParser::RemoveModule(this);
559 }
560
561 #endif
562