added id handling to image cells
[wxWidgets.git] / src / html / m_image.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: m_image.cpp
3 // Purpose: wxHtml module for displaying images
4 // Author: Vaclav Slavik
5 // RCS-ID: $Id$
6 // Copyright: (c) 1999 Vaclav Slavik, Joel Lucsy
7 // Licence: wxWindows Licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #ifdef __GNUG__
11 #pragma implementation
12 #endif
13
14 #include "wx/wxprec.h"
15
16 #include "wx/defs.h"
17 #if wxUSE_HTML && wxUSE_STREAMS
18
19 #ifdef __BORDLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WXPRECOMP
24 #include "wx/dc.h"
25 #endif
26
27 #include "wx/html/forcelnk.h"
28 #include "wx/html/m_templ.h"
29
30 #include "wx/image.h"
31 #include "wx/dynarray.h"
32
33 #include <math.h>
34 #include <float.h>
35
36 FORCE_LINK_ME(m_image)
37
38
39
40
41 WX_DECLARE_OBJARRAY(int, CoordArray);
42 #include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
43 WX_DEFINE_OBJARRAY(CoordArray);
44
45
46 //--------------------------------------------------------------------------------
47 // wxHtmlImageMapAreaCell
48 // 0-width, 0-height cell that represents single area in imagemap
49 // (it's GetLink is called from wxHtmlImageCell's)
50 //--------------------------------------------------------------------------------
51
52 class wxHtmlImageMapAreaCell : public wxHtmlCell
53 {
54 public:
55 enum celltype { CIRCLE, RECT, POLY };
56 protected:
57 CoordArray coords;
58 celltype type;
59 int radius;
60 public:
61 wxHtmlImageMapAreaCell( celltype t, wxString &coords, double pixel_scale = 1.0);
62 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
63 };
64
65
66
67
68
69 wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t, wxString &incoords, double pixel_scale )
70 {
71 int i;
72 wxString x = incoords, y;
73
74 type = t;
75 while ((i = x.Find( ',' )) != -1)
76 {
77 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.Left( i ).c_str())) );
78 x = x.Mid( i + 1 );
79 }
80 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.c_str())) );
81 }
82
83 wxHtmlLinkInfo *wxHtmlImageMapAreaCell::GetLink( int x, int y ) const
84 {
85 switch (type)
86 {
87 case RECT:
88 {
89 int l, t, r, b;
90
91 l = coords[ 0 ];
92 t = coords[ 1 ];
93 r = coords[ 2 ];
94 b = coords[ 3 ];
95 if (x >= l && x <= r && y >= t && y <= b)
96 {
97 return m_Link;
98 }
99 break;
100 }
101 case CIRCLE:
102 {
103 int l, t, r;
104 double d;
105
106 l = coords[ 0 ];
107 t = coords[ 1 ];
108 r = coords[ 2 ];
109 d = sqrt( (double) (((x - l) * (x - l)) + ((y - t) * (y - t))) );
110 if (d < (double)r)
111 {
112 return m_Link;
113 }
114 }
115 break;
116 case POLY:
117 {
118 if (coords.GetCount() >= 6)
119 {
120 int intersects = 0;
121 int wherex = x;
122 int wherey = y;
123 int totalv = coords.GetCount() / 2;
124 int totalc = totalv * 2;
125 int xval = coords[totalc - 2];
126 int yval = coords[totalc - 1];
127 int end = totalc;
128 int pointer = 1;
129
130 if ((yval >= wherey) != (coords[pointer] >= wherey))
131 {
132 if ((xval >= wherex) == (coords[0] >= wherex))
133 {
134 intersects += (xval >= wherex) ? 1 : 0;
135 }
136 else
137 {
138 intersects += ((xval - (yval - wherey) *
139 (coords[0] - xval) /
140 (coords[pointer] - yval)) >= wherex) ? 1 : 0;
141 }
142 }
143
144 while (pointer < end)
145 {
146 yval = coords[pointer];
147 pointer += 2;
148 if (yval >= wherey)
149 {
150 while ((pointer < end) && (coords[pointer] >= wherey))
151 {
152 pointer += 2;
153 }
154 if (pointer >= end)
155 {
156 break;
157 }
158 if ((coords[pointer - 3] >= wherex) ==
159 (coords[pointer - 1] >= wherex)) {
160 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
161 }
162 else
163 {
164 intersects +=
165 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
166 (coords[pointer - 1] - coords[pointer - 3]) /
167 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
168 }
169 }
170 else
171 {
172 while ((pointer < end) && (coords[pointer] < wherey))
173 {
174 pointer += 2;
175 }
176 if (pointer >= end)
177 {
178 break;
179 }
180 if ((coords[pointer - 3] >= wherex) ==
181 (coords[pointer - 1] >= wherex))
182 {
183 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
184 }
185 else
186 {
187 intersects +=
188 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
189 (coords[pointer - 1] - coords[pointer - 3]) /
190 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
191 }
192 }
193 }
194 if ((intersects & 1) != 0)
195 {
196 return m_Link;
197 }
198 }
199 }
200 break;
201 }
202
203 if (m_Next)
204 {
205 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
206 return a->GetLink( x, y );
207 }
208 return NULL;
209 }
210
211
212
213
214
215
216
217
218 //--------------------------------------------------------------------------------
219 // wxHtmlImageMapCell
220 // 0-width, 0-height cell that represents map from imagemaps
221 // it is always placed before wxHtmlImageMapAreaCells
222 // It responds to Find(wxHTML_COND_ISIMAGEMAP)
223 //--------------------------------------------------------------------------------
224
225
226 class wxHtmlImageMapCell : public wxHtmlCell
227 {
228 public:
229 wxHtmlImageMapCell( wxString &name );
230 protected:
231 wxString m_Name;
232 public:
233 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
234 virtual const wxHtmlCell *Find( int cond, const void *param ) const;
235 };
236
237
238 wxHtmlImageMapCell::wxHtmlImageMapCell( wxString &name )
239 {
240 m_Name = name ;
241 }
242
243 wxHtmlLinkInfo *wxHtmlImageMapCell::GetLink( int x, int y ) const
244 {
245 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
246 if (a)
247 return a->GetLink( x, y );
248 return wxHtmlCell::GetLink( x, y );
249 }
250
251 const wxHtmlCell *wxHtmlImageMapCell::Find( int cond, const void *param ) const
252 {
253 if (cond == wxHTML_COND_ISIMAGEMAP)
254 {
255 if (m_Name == *((wxString*)(param)))
256 return this;
257 }
258 return wxHtmlCell::Find(cond, param);
259 }
260
261
262
263
264
265 //--------------------------------------------------------------------------------
266 // wxHtmlImageCell
267 // Image/bitmap
268 //--------------------------------------------------------------------------------
269
270 class wxHtmlImageCell : public wxHtmlCell
271 {
272 public:
273 wxBitmap *m_Image;
274 double m_Scale;
275 wxHtmlImageMapCell *m_ImageMap;
276 wxString m_MapName;
277
278 wxHtmlImageCell(wxFSFile *input, int w = -1, int h = -1, double scale = 1.0, int align = wxHTML_ALIGN_BOTTOM, wxString mapname = wxEmptyString);
279 ~wxHtmlImageCell() {if (m_Image) delete m_Image; }
280 void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2);
281 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
282 };
283
284
285
286
287 //--------------------------------------------------------------------------------
288 // wxHtmlImageCell
289 //--------------------------------------------------------------------------------
290
291 wxHtmlImageCell::wxHtmlImageCell(wxFSFile *input, int w, int h, double scale, int align, wxString mapname) : wxHtmlCell()
292 {
293 wxImage *img;
294 int ww, hh, bw, bh;
295 wxInputStream *s = input->GetStream();
296
297 m_Scale = scale;
298 img = new wxImage(*s, wxBITMAP_TYPE_ANY);
299 m_Image = NULL;
300 if (img && (img->Ok()))
301 {
302 ww = img->GetWidth();
303 hh = img->GetHeight();
304 if (w != -1) bw = w; else bw = ww;
305 if (h != -1) bh = h; else bh = hh;
306
307 m_Width = (int)(scale * (double)bw);
308 m_Height = (int)(scale * (double)bh);
309
310 if ((bw != ww) || (bh != hh))
311 {
312 wxImage img2 = img->Scale(bw, bh);
313 m_Image = new wxBitmap(img2.ConvertToBitmap());
314 }
315 else
316 m_Image = new wxBitmap(img->ConvertToBitmap());
317 delete img;
318 }
319 switch (align)
320 {
321 case wxHTML_ALIGN_TOP :
322 m_Descent = m_Height;
323 break;
324 case wxHTML_ALIGN_CENTER :
325 m_Descent = m_Height / 2;
326 break;
327 case wxHTML_ALIGN_BOTTOM :
328 default :
329 m_Descent = 0;
330 break;
331 }
332
333 m_ImageMap = NULL;
334 m_MapName = mapname;
335 SetCanLiveOnPagebreak(FALSE);
336 }
337
338
339
340 void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int WXUNUSED(view_y1), int WXUNUSED(view_y2))
341 {
342 if (m_Image)
343 {
344 double us_x, us_y;
345 dc.GetUserScale(&us_x, &us_y);
346 dc.SetUserScale(us_x * m_Scale, us_y * m_Scale);
347
348 // dc.DrawBitmap(*m_Image, x + m_PosX, y + m_PosY, (m_Image->GetMask() != (wxMask*) 0));
349 dc.DrawBitmap(*m_Image, (int) ((x + m_PosX) / m_Scale),
350 (int) ((y + m_PosY) / m_Scale), TRUE);
351 dc.SetUserScale(us_x, us_y);
352 }
353 }
354
355 wxHtmlLinkInfo *wxHtmlImageCell::GetLink( int x, int y ) const
356 {
357 if (m_MapName.IsEmpty())
358 return wxHtmlCell::GetLink( x, y );
359 if (!m_ImageMap)
360 {
361 wxHtmlContainerCell *p, *op;
362 op = p = GetParent();
363 while (p)
364 {
365 op = p;
366 p = p->GetParent();
367 }
368 p = op;
369 wxHtmlCell *cell = (wxHtmlCell*)p->Find( wxHTML_COND_ISIMAGEMAP, (const void*)(&m_MapName));
370 if (!cell)
371 {
372 ((wxString&)m_MapName).Clear();
373 return wxHtmlCell::GetLink( x, y );
374 }
375 { // dirty hack, ask Joel why he fills m_ImageMap in this place
376 // THE problem is that we're in const method and we can't modify m_ImageMap
377 wxHtmlImageMapCell **cx = (wxHtmlImageMapCell**)(&m_ImageMap);
378 *cx = (wxHtmlImageMapCell*)cell;
379 }
380 }
381 return m_ImageMap->GetLink( x, y );
382 }
383
384
385
386 //--------------------------------------------------------------------------------
387 // tag handler
388 //--------------------------------------------------------------------------------
389
390 TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
391
392 TAG_HANDLER_PROC(tag)
393 {
394 if (tag.GetName() == wxT("IMG"))
395 {
396 if (tag.HasParam(wxT("SRC")))
397 {
398 int w = -1, h = -1;
399 int al;
400 wxFSFile *str;
401 wxString tmp = tag.GetParam(wxT("SRC"));
402 wxString mn = wxEmptyString;
403
404 str = m_WParser->GetFS()->OpenFile(tmp);
405 if (tag.HasParam(wxT("WIDTH")))
406 tag.GetParamAsInt(wxT("WIDTH"), &w);
407 if (tag.HasParam(wxT("HEIGHT")))
408 tag.GetParamAsInt(wxT("HEIGHT"), &h);
409 al = wxHTML_ALIGN_BOTTOM;
410 if (tag.HasParam(wxT("ALIGN")))
411 {
412 wxString alstr = tag.GetParam(wxT("ALIGN"));
413 alstr.MakeUpper(); // for the case alignment was in ".."
414 if (alstr == wxT("TEXTTOP"))
415 al = wxHTML_ALIGN_TOP;
416 else if ((alstr == wxT("CENTER")) || (alstr == wxT("ABSCENTER")))
417 al = wxHTML_ALIGN_CENTER;
418 }
419 if (tag.HasParam(wxT("USEMAP")))
420 {
421 mn = tag.GetParam( wxT("USEMAP") );
422 if (mn.GetChar(0) == wxT('#'))
423 {
424 mn = mn.Mid( 1 );
425 }
426 }
427 wxHtmlImageCell *cel = NULL;
428 if (str)
429 {
430 cel = new wxHtmlImageCell(str, w, h, m_WParser->GetPixelScale(), al, mn);
431 cel->SetLink(m_WParser->GetLink());
432 cel->SetId(tag.GetParam(wxT("id"))); // may be empty
433 m_WParser->GetContainer()->InsertCell(cel);
434 delete str;
435 }
436 }
437 }
438 if (tag.GetName() == wxT("MAP"))
439 {
440 m_WParser->CloseContainer();
441 m_WParser->OpenContainer();
442 if (tag.HasParam(wxT("NAME")))
443 {
444 wxString tmp = tag.GetParam(wxT("NAME"));
445 wxHtmlImageMapCell *cel = new wxHtmlImageMapCell( tmp );
446 m_WParser->GetContainer()->InsertCell( cel );
447 }
448 ParseInner( tag );
449 m_WParser->CloseContainer();
450 m_WParser->OpenContainer();
451 }
452 if (tag.GetName() == wxT("AREA"))
453 {
454 if (tag.HasParam(wxT("SHAPE")))
455 {
456 wxString tmp = tag.GetParam(wxT("SHAPE"));
457 wxString coords = wxEmptyString;
458 tmp.MakeUpper();
459 wxHtmlImageMapAreaCell *cel = NULL;
460 if (tag.HasParam(wxT("COORDS")))
461 {
462 coords = tag.GetParam(wxT("COORDS"));
463 }
464 if (tmp == wxT("POLY"))
465 {
466 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY, coords, m_WParser->GetPixelScale() );
467 }
468 else if (tmp == wxT("CIRCLE"))
469 {
470 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE, coords, m_WParser->GetPixelScale() );
471 }
472 else if (tmp == wxT("RECT"))
473 {
474 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT, coords, m_WParser->GetPixelScale() );
475 }
476 if (cel != NULL && tag.HasParam(wxT("HREF")))
477 {
478 wxString tmp = tag.GetParam(wxT("HREF"));
479 wxString target = wxEmptyString;
480 if (tag.HasParam(wxT("TARGET"))) target = tag.GetParam(wxT("TARGET"));
481 cel->SetLink( wxHtmlLinkInfo(tmp, target));
482 }
483 if (cel != NULL) m_WParser->GetContainer()->InsertCell( cel );
484 }
485 }
486
487 return FALSE;
488 }
489
490 TAG_HANDLER_END(IMG)
491
492
493
494 TAGS_MODULE_BEGIN(Image)
495
496 TAGS_MODULE_ADD(IMG)
497
498 TAGS_MODULE_END(Image)
499
500
501 #endif