oops, HTML entities were parsed twice
[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 #ifdef __GNUG__
12 #pragma implementation
13 #endif
14
15 #include "wx/wxprec.h"
16
17 #include "wx/defs.h"
18 #if wxUSE_HTML && wxUSE_STREAMS
19
20 #ifdef __BORDLANDC__
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
35
36 //-----------------------------------------------------------------------------
37 // wxHtmlWinParser
38 //-----------------------------------------------------------------------------
39
40
41 wxList wxHtmlWinParser::m_Modules;
42
43 wxHtmlWinParser::wxHtmlWinParser(wxWindow *wnd) : wxHtmlParser()
44 {
45 m_tmpStrBuf = NULL;
46 m_tmpStrBufSize = 0;
47 m_Window = wnd;
48 m_Container = NULL;
49 m_DC = NULL;
50 m_CharHeight = m_CharWidth = 0;
51 m_UseLink = FALSE;
52 m_EncConv = NULL;
53 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
54
55 {
56 int i, j, k, l, m;
57 for (i = 0; i < 2; i++)
58 for (j = 0; j < 2; j++)
59 for (k = 0; k < 2; k++)
60 for (l = 0; l < 2; l++)
61 for (m = 0; m < 7; m++)
62 {
63 m_FontsTable[i][j][k][l][m] = NULL;
64 m_FontsFacesTable[i][j][k][l][m] = wxEmptyString;
65 m_FontsEncTable[i][j][k][l][m] = wxFONTENCODING_DEFAULT;
66 }
67 #ifdef __WXMSW__
68 static int default_sizes[7] = {7, 8, 10, 12, 16, 22, 30};
69 #elif defined(__WXMAC__)
70 static int default_sizes[7] = {9, 12, 14, 18, 24, 30, 36};
71 #else
72 static int default_sizes[7] = {10, 12, 14, 16, 19, 24, 32};
73 #endif
74 SetFonts("", "", default_sizes);
75 }
76
77 // fill in wxHtmlParser's tables:
78 wxNode *node = m_Modules.GetFirst();
79 while (node)
80 {
81 wxHtmlTagsModule *mod = (wxHtmlTagsModule*) node->GetData();
82 mod->FillHandlersTable(this);
83 node = node->GetNext();
84 }
85 }
86
87
88 wxHtmlWinParser::~wxHtmlWinParser()
89 {
90 int i, j, k, l, m;
91
92 for (i = 0; i < 2; i++)
93 for (j = 0; j < 2; j++)
94 for (k = 0; k < 2; k++)
95 for (l = 0; l < 2; l++)
96 for (m = 0; m < 7; m++)
97 {
98 if (m_FontsTable[i][j][k][l][m] != NULL)
99 delete m_FontsTable[i][j][k][l][m];
100 }
101 delete m_EncConv;
102 delete[] m_tmpStrBuf;
103 }
104
105
106 void wxHtmlWinParser::AddModule(wxHtmlTagsModule *module)
107 {
108 m_Modules.Append(module);
109 }
110
111
112
113 void wxHtmlWinParser::RemoveModule(wxHtmlTagsModule *module)
114 {
115 m_Modules.DeleteObject(module);
116 }
117
118
119
120 void wxHtmlWinParser::SetFonts(wxString normal_face, wxString fixed_face, const int *sizes)
121 {
122 int i, j, k, l, m;
123
124 for (i = 0; i < 7; i++) m_FontsSizes[i] = sizes[i];
125 m_FontFaceFixed = fixed_face;
126 m_FontFaceNormal = normal_face;
127
128 SetInputEncoding(m_InputEnc);
129
130 for (i = 0; i < 2; i++)
131 for (j = 0; j < 2; j++)
132 for (k = 0; k < 2; k++)
133 for (l = 0; l < 2; l++)
134 for (m = 0; m < 7; m++) {
135 if (m_FontsTable[i][j][k][l][m] != NULL)
136 {
137 delete m_FontsTable[i][j][k][l][m];
138 m_FontsTable[i][j][k][l][m] = NULL;
139 }
140 }
141 }
142
143
144
145 void wxHtmlWinParser::InitParser(const wxString& source)
146 {
147 wxHtmlParser::InitParser(source);
148 wxASSERT_MSG(m_DC != NULL, _T("no DC assigned to wxHtmlWinParser!!"));
149
150 m_FontBold = m_FontItalic = m_FontUnderlined = m_FontFixed = FALSE;
151 m_FontSize = 3; //default one
152 CreateCurrentFont(); // we're selecting default font into
153 m_DC->GetTextExtent("H", &m_CharWidth, &m_CharHeight);
154 /* NOTE : we're not using GetCharWidth/Height() because
155 of differences under X and win
156 */
157
158 m_UseLink = FALSE;
159 m_Link = wxHtmlLinkInfo("", "");
160 m_LinkColor.Set(0, 0, 0xFF);
161 m_ActualColor.Set(0, 0, 0);
162 m_Align = wxHTML_ALIGN_LEFT;
163 m_tmpLastWasSpace = FALSE;
164
165 OpenContainer();
166
167 OpenContainer();
168 m_Container->InsertCell(new wxHtmlColourCell(m_ActualColor));
169 m_Container->InsertCell(new wxHtmlFontCell(CreateCurrentFont()));
170 }
171
172
173
174 void wxHtmlWinParser::DoneParser()
175 {
176 m_Container = NULL;
177 SetInputEncoding(wxFONTENCODING_DEFAULT); // for next call
178 wxHtmlParser::DoneParser();
179 }
180
181
182
183 wxObject* wxHtmlWinParser::GetProduct()
184 {
185 wxHtmlContainerCell *top;
186
187 CloseContainer();
188 OpenContainer();
189
190 top = m_Container;
191 while (top->GetParent()) top = top->GetParent();
192 return top;
193 }
194
195
196 void wxHtmlWinParser::AddText(const wxChar* txt)
197 {
198 wxHtmlCell *c;
199 size_t i = 0,
200 x,
201 lng = wxStrlen(txt);
202 register wxChar d;
203 int templen = 0;
204 wxChar nbsp = GetEntitiesParser()->GetCharForCode(160 /* nbsp */);
205
206 if (lng+1 > m_tmpStrBufSize)
207 {
208 delete[] m_tmpStrBuf;
209 m_tmpStrBuf = new wxChar[lng+1];
210 m_tmpStrBufSize = lng+1;
211 }
212 wxChar *temp = m_tmpStrBuf;
213
214 if (m_tmpLastWasSpace)
215 {
216 while ((i < lng) &&
217 ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) || (txt[i] == wxT(' ')) ||
218 (txt[i] == wxT('\t')))) i++;
219 }
220
221 while (i < lng)
222 {
223 x = 0;
224 d = temp[templen++] = txt[i];
225 if ((d == wxT('\n')) || (d == wxT('\r')) || (d == wxT(' ')) || (d == wxT('\t')))
226 {
227 i++, x++;
228 while ((i < lng) && ((txt[i] == wxT('\n')) || (txt[i] == wxT('\r')) ||
229 (txt[i] == wxT(' ')) || (txt[i] == wxT('\t')))) i++, x++;
230 }
231 else i++;
232
233 if (x)
234 {
235 temp[templen-1] = wxT(' ');
236 temp[templen] = 0;
237 if (templen == 1) continue;
238 templen = 0;
239 if (m_EncConv)
240 m_EncConv->Convert(temp);
241 size_t len = wxStrlen(temp);
242 for (size_t j = 0; j < len; j++)
243 if (temp[j] == nbsp)
244 temp[j] = wxT(' ');
245 c = new wxHtmlWordCell(temp, *(GetDC()));
246 if (m_UseLink)
247 c->SetLink(m_Link);
248 m_Container->InsertCell(c);
249 m_tmpLastWasSpace = TRUE;
250 }
251 }
252
253 if (templen && (templen > 1 || temp[0] != wxT(' ')))
254 {
255 temp[templen] = 0;
256 if (m_EncConv)
257 m_EncConv->Convert(temp);
258 size_t len = wxStrlen(temp);
259 for (size_t j = 0; j < len; j++)
260 if (temp[j] == nbsp)
261 temp[j] = wxT(' ');
262 c = new wxHtmlWordCell(temp, *(GetDC()));
263 if (m_UseLink)
264 c->SetLink(m_Link);
265 m_Container->InsertCell(c);
266 m_tmpLastWasSpace = FALSE;
267 }
268 }
269
270
271
272 wxHtmlContainerCell* wxHtmlWinParser::OpenContainer()
273 {
274 m_Container = new wxHtmlContainerCell(m_Container);
275 m_Container->SetAlignHor(m_Align);
276 m_tmpLastWasSpace = TRUE;
277 /* to avoid space being first character in paragraph */
278 return m_Container;
279 }
280
281
282
283 wxHtmlContainerCell* wxHtmlWinParser::SetContainer(wxHtmlContainerCell *c)
284 {
285 m_tmpLastWasSpace = TRUE;
286 /* to avoid space being first character in paragraph */
287 return m_Container = c;
288 }
289
290
291
292 wxHtmlContainerCell* wxHtmlWinParser::CloseContainer()
293 {
294 m_Container = m_Container->GetParent();
295 return m_Container;
296 }
297
298
299 void wxHtmlWinParser::SetFontSize(int s)
300 {
301 if (s < 1) s = 1;
302 else if (s > 7) s = 7;
303 m_FontSize = s;
304 }
305
306
307
308 wxFont* wxHtmlWinParser::CreateCurrentFont()
309 {
310 int fb = GetFontBold(),
311 fi = GetFontItalic(),
312 fu = GetFontUnderlined(),
313 ff = GetFontFixed(),
314 fs = GetFontSize() - 1 /*remap from <1;7> to <0;6>*/ ;
315
316 wxString face = ff ? m_FontFaceFixed : m_FontFaceNormal;
317 wxString *faceptr = &(m_FontsFacesTable[fb][fi][fu][ff][fs]);
318 wxFont **fontptr = &(m_FontsTable[fb][fi][fu][ff][fs]);
319 wxFontEncoding *encptr = &(m_FontsEncTable[fb][fi][fu][ff][fs]);
320
321 if (*fontptr != NULL && (*faceptr != face || *encptr != m_OutputEnc))
322 {
323 delete *fontptr;
324 *fontptr = NULL;
325 }
326
327 if (*fontptr == NULL)
328 {
329 *faceptr = face;
330 *encptr = m_OutputEnc;
331 *fontptr = new wxFont(
332 (int) (m_FontsSizes[fs] * m_PixelScale),
333 ff ? wxMODERN : wxSWISS,
334 fi ? wxITALIC : wxNORMAL,
335 fb ? wxBOLD : wxNORMAL,
336 fu ? TRUE : FALSE, face,
337 m_OutputEnc);
338 }
339 m_DC->SetFont(**fontptr);
340 return (*fontptr);
341 }
342
343
344
345 void wxHtmlWinParser::SetLink(const wxHtmlLinkInfo& link)
346 {
347 m_Link = link;
348 m_UseLink = (link.GetHref() != wxEmptyString);
349 }
350
351
352 void wxHtmlWinParser::SetFontFace(const wxString& face)
353 {
354 if (GetFontFixed()) m_FontFaceFixed = face;
355 else m_FontFaceNormal = face;
356
357 if (m_InputEnc != wxFONTENCODING_DEFAULT)
358 SetInputEncoding(m_InputEnc);
359 }
360
361
362
363 void wxHtmlWinParser::SetInputEncoding(wxFontEncoding enc)
364 {
365 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
366 if (m_EncConv)
367 {
368 delete m_EncConv;
369 m_EncConv = NULL;
370 }
371
372 if (enc == wxFONTENCODING_DEFAULT) return;
373
374 wxFontEncoding altfix, altnorm;
375 bool availfix, availnorm;
376
377 // exact match?
378 availnorm = wxTheFontMapper->IsEncodingAvailable(enc, m_FontFaceNormal);
379 availfix = wxTheFontMapper->IsEncodingAvailable(enc, m_FontFaceFixed);
380 if (availnorm && availfix)
381 m_OutputEnc = enc;
382
383 // alternatives?
384 else if (wxTheFontMapper->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, FALSE) &&
385 wxTheFontMapper->GetAltForEncoding(enc, &altfix, m_FontFaceFixed, FALSE) &&
386 altnorm == altfix)
387 m_OutputEnc = altnorm;
388
389 // at least normal face?
390 else if (availnorm)
391 m_OutputEnc = enc;
392 else if (wxTheFontMapper->GetAltForEncoding(enc, &altnorm, m_FontFaceNormal, FALSE))
393 m_OutputEnc = altnorm;
394
395 // okay, let convert to ISO_8859-1, available always
396 else
397 m_OutputEnc = wxFONTENCODING_DEFAULT;
398
399 m_InputEnc = enc;
400 if (m_OutputEnc == wxFONTENCODING_DEFAULT)
401 GetEntitiesParser()->SetEncoding(wxFONTENCODING_SYSTEM);
402 else
403 GetEntitiesParser()->SetEncoding(m_OutputEnc);
404
405 if (m_InputEnc == m_OutputEnc) return;
406
407 m_EncConv = new wxEncodingConverter();
408 if (!m_EncConv->Init(m_InputEnc,
409 (m_OutputEnc == wxFONTENCODING_DEFAULT) ?
410 wxFONTENCODING_ISO8859_1 : m_OutputEnc,
411 wxCONVERT_SUBSTITUTE))
412 { // total failture :-(
413 wxLogError(_("Failed to display HTML document in %s encoding"),
414 wxFontMapper::GetEncodingName(enc).c_str());
415 m_InputEnc = m_OutputEnc = wxFONTENCODING_DEFAULT;
416 delete m_EncConv;
417 m_EncConv = NULL;
418 }
419 }
420
421
422
423
424
425 //-----------------------------------------------------------------------------
426 // wxHtmlWinTagHandler
427 //-----------------------------------------------------------------------------
428
429 IMPLEMENT_ABSTRACT_CLASS(wxHtmlWinTagHandler, wxHtmlTagHandler)
430
431
432
433 //-----------------------------------------------------------------------------
434 // wxHtmlTagsModule
435 //-----------------------------------------------------------------------------
436
437
438 IMPLEMENT_DYNAMIC_CLASS(wxHtmlTagsModule, wxModule)
439
440
441 bool wxHtmlTagsModule::OnInit()
442 {
443 wxHtmlWinParser::AddModule(this);
444 return TRUE;
445 }
446
447
448
449 void wxHtmlTagsModule::OnExit()
450 {
451 wxHtmlWinParser::RemoveModule(this);
452 }
453 #endif
454