]> git.saurik.com Git - wxWidgets.git/blame - src/html/m_image.cpp
toplevel fixes
[wxWidgets.git] / src / html / m_image.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
c88293a4 2// Name: m_image.cpp
5526e819
VS
3// Purpose: wxHtml module for displaying images
4// Author: Vaclav Slavik
69941f05 5// RCS-ID: $Id$
25082126 6// Copyright: (c) 1999 Vaclav Slavik, Joel Lucsy
5526e819
VS
7// Licence: wxWindows Licence
8/////////////////////////////////////////////////////////////////////////////
9
3364ab79
RS
10#ifdef __GNUG__
11#pragma implementation
12#endif
13
25082126 14#include "wx/wxprec.h"
3364ab79 15
5526e819 16#include "wx/defs.h"
f6bcfd97 17#if wxUSE_HTML && wxUSE_STREAMS
5526e819 18
3364ab79
RS
19#ifdef __BORDLANDC__
20#pragma hdrstop
21#endif
22
23#ifndef WXPRECOMP
04dbb646 24 #include "wx/dc.h"
ea5c1679
VS
25 #include "wx/scrolwin.h"
26 #include "wx/timer.h"
3364ab79
RS
27#endif
28
69941f05
VS
29#include "wx/html/forcelnk.h"
30#include "wx/html/m_templ.h"
5526e819 31
25082126 32#include "wx/image.h"
ea5c1679 33#include "wx/gifdecod.h"
25082126
VS
34#include "wx/dynarray.h"
35
36#include <math.h>
37#include <float.h>
5526e819 38
c88293a4 39FORCE_LINK_ME(m_image)
5526e819
VS
40
41
25082126
VS
42
43
44WX_DECLARE_OBJARRAY(int, CoordArray);
3096bd2f 45#include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
25082126
VS
46WX_DEFINE_OBJARRAY(CoordArray);
47
48
49//--------------------------------------------------------------------------------
50// wxHtmlImageMapAreaCell
51// 0-width, 0-height cell that represents single area in imagemap
52// (it's GetLink is called from wxHtmlImageCell's)
53//--------------------------------------------------------------------------------
54
55class wxHtmlImageMapAreaCell : public wxHtmlCell
56{
01325161
VS
57 public:
58 enum celltype { CIRCLE, RECT, POLY };
59 protected:
60 CoordArray coords;
61 celltype type;
edbd0635 62 int radius;
01325161 63 public:
edbd0635 64 wxHtmlImageMapAreaCell( celltype t, wxString &coords, double pixel_scale = 1.0);
846914d1 65 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
25082126
VS
66};
67
68
69
70
71
edbd0635 72wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t, wxString &incoords, double pixel_scale )
25082126 73{
edbd0635 74 int i;
01325161
VS
75 wxString x = incoords, y;
76
77 type = t;
04dbb646 78 while ((i = x.Find( ',' )) != -1)
4f9297b0 79 {
edbd0635 80 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.Left( i ).c_str())) );
01325161
VS
81 x = x.Mid( i + 1 );
82 }
edbd0635 83 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.c_str())) );
25082126
VS
84}
85
846914d1 86wxHtmlLinkInfo *wxHtmlImageMapAreaCell::GetLink( int x, int y ) const
25082126 87{
04dbb646 88 switch (type)
4f9297b0 89 {
01325161
VS
90 case RECT:
91 {
edbd0635 92 int l, t, r, b;
01325161
VS
93
94 l = coords[ 0 ];
95 t = coords[ 1 ];
96 r = coords[ 2 ];
97 b = coords[ 3 ];
04dbb646
VZ
98 if (x >= l && x <= r && y >= t && y <= b)
99 {
01325161
VS
100 return m_Link;
101 }
102 break;
103 }
104 case CIRCLE:
105 {
edbd0635
VS
106 int l, t, r;
107 double d;
01325161
VS
108
109 l = coords[ 0 ];
110 t = coords[ 1 ];
111 r = coords[ 2 ];
112 d = sqrt( (double) (((x - l) * (x - l)) + ((y - t) * (y - t))) );
04dbb646
VZ
113 if (d < (double)r)
114 {
01325161
VS
115 return m_Link;
116 }
117 }
118 break;
119 case POLY:
120 {
04dbb646
VZ
121 if (coords.GetCount() >= 6)
122 {
edbd0635
VS
123 int intersects = 0;
124 int wherex = x;
125 int wherey = y;
126 int totalv = coords.GetCount() / 2;
127 int totalc = totalv * 2;
128 int xval = coords[totalc - 2];
129 int yval = coords[totalc - 1];
130 int end = totalc;
131 int pointer = 1;
01325161 132
04dbb646
VZ
133 if ((yval >= wherey) != (coords[pointer] >= wherey))
134 {
135 if ((xval >= wherex) == (coords[0] >= wherex))
136 {
01325161 137 intersects += (xval >= wherex) ? 1 : 0;
04dbb646
VZ
138 }
139 else
140 {
01325161
VS
141 intersects += ((xval - (yval - wherey) *
142 (coords[0] - xval) /
143 (coords[pointer] - yval)) >= wherex) ? 1 : 0;
144 }
145 }
146
04dbb646
VZ
147 while (pointer < end)
148 {
01325161
VS
149 yval = coords[pointer];
150 pointer += 2;
04dbb646
VZ
151 if (yval >= wherey)
152 {
153 while ((pointer < end) && (coords[pointer] >= wherey))
154 {
01325161
VS
155 pointer += 2;
156 }
04dbb646
VZ
157 if (pointer >= end)
158 {
01325161
VS
159 break;
160 }
161 if ((coords[pointer - 3] >= wherex) ==
162 (coords[pointer - 1] >= wherex)) {
163 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
04dbb646
VZ
164 }
165 else
166 {
01325161
VS
167 intersects +=
168 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
169 (coords[pointer - 1] - coords[pointer - 3]) /
170 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
171 }
04dbb646
VZ
172 }
173 else
174 {
175 while ((pointer < end) && (coords[pointer] < wherey))
176 {
01325161
VS
177 pointer += 2;
178 }
04dbb646
VZ
179 if (pointer >= end)
180 {
01325161
VS
181 break;
182 }
183 if ((coords[pointer - 3] >= wherex) ==
04dbb646
VZ
184 (coords[pointer - 1] >= wherex))
185 {
01325161 186 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
04dbb646
VZ
187 }
188 else
189 {
01325161
VS
190 intersects +=
191 ((coords[pointer - 3] - (coords[pointer - 2] - wherey) *
192 (coords[pointer - 1] - coords[pointer - 3]) /
193 (coords[pointer] - coords[pointer - 2])) >= wherex) ? 1 : 0;
194 }
195 }
196 }
04dbb646
VZ
197 if ((intersects & 1) != 0)
198 {
01325161
VS
199 return m_Link;
200 }
201 }
202 }
203 break;
204 }
4f9297b0 205
04dbb646 206 if (m_Next)
4f9297b0 207 {
edbd0635 208 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
01325161
VS
209 return a->GetLink( x, y );
210 }
846914d1 211 return NULL;
25082126
VS
212}
213
214
215
216
217
218
219
220
221//--------------------------------------------------------------------------------
222// wxHtmlImageMapCell
223// 0-width, 0-height cell that represents map from imagemaps
224// it is always placed before wxHtmlImageMapAreaCells
efba2b89 225// It responds to Find(wxHTML_COND_ISIMAGEMAP)
25082126
VS
226//--------------------------------------------------------------------------------
227
228
229class wxHtmlImageMapCell : public wxHtmlCell
230{
01325161
VS
231 public:
232 wxHtmlImageMapCell( wxString &name );
233 protected:
234 wxString m_Name;
235 public:
846914d1 236 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
01325161 237 virtual const wxHtmlCell *Find( int cond, const void *param ) const;
25082126
VS
238};
239
240
241wxHtmlImageMapCell::wxHtmlImageMapCell( wxString &name )
242{
01325161 243 m_Name = name ;
25082126
VS
244}
245
846914d1 246wxHtmlLinkInfo *wxHtmlImageMapCell::GetLink( int x, int y ) const
25082126 247{
edbd0635 248 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
01325161
VS
249 if (a)
250 return a->GetLink( x, y );
251 return wxHtmlCell::GetLink( x, y );
25082126
VS
252}
253
254const wxHtmlCell *wxHtmlImageMapCell::Find( int cond, const void *param ) const
255{
04dbb646 256 if (cond == wxHTML_COND_ISIMAGEMAP)
4f9297b0 257 {
01325161
VS
258 if (m_Name == *((wxString*)(param)))
259 return this;
260 }
261 return wxHtmlCell::Find(cond, param);
25082126
VS
262}
263
264
265
266
267
5526e819
VS
268//--------------------------------------------------------------------------------
269// wxHtmlImageCell
270// Image/bitmap
271//--------------------------------------------------------------------------------
272
273class wxHtmlImageCell : public wxHtmlCell
274{
ea5c1679
VS
275public:
276 wxHtmlImageCell(wxWindow *window,
277 wxFSFile *input, int w = -1, int h = -1,
278 double scale = 1.0, int align = wxHTML_ALIGN_BOTTOM,
279 const wxString& mapname = wxEmptyString);
280 ~wxHtmlImageCell();
281 void Draw(wxDC& dc, int x, int y, int view_y1, int view_y2);
282 virtual wxHtmlLinkInfo *GetLink(int x = 0, int y = 0) const;
283
284 void SetImage(const wxImage& img);
285#if wxUSE_GIF && wxUSE_TIMER
286 void AdvanceAnimation(wxTimer *timer);
287 virtual void Layout(int w);
288#endif
289
290private:
291 wxBitmap *m_bitmap;
292 int m_bmpW, m_bmpH;
293 wxScrolledWindow *m_window;
294#if wxUSE_GIF && wxUSE_TIMER
295 wxGIFDecoder *m_gifDecoder;
296 wxTimer *m_gifTimer;
297 int m_physX, m_physY;
298#endif
299 double m_scale;
300 wxHtmlImageMapCell *m_imageMap;
301 wxString m_mapName;
5526e819
VS
302};
303
ea5c1679
VS
304#if wxUSE_GIF && wxUSE_TIMER
305class wxGIFTimer : public wxTimer
306{
307 public:
308 wxGIFTimer(wxHtmlImageCell *cell) : m_cell(cell) {}
309 virtual void Notify()
310 {
311 m_cell->AdvanceAnimation(this);
312 }
5526e819 313
ea5c1679
VS
314 private:
315 wxHtmlImageCell *m_cell;
316};
317#endif
5526e819 318
25082126 319
5526e819
VS
320//--------------------------------------------------------------------------------
321// wxHtmlImageCell
322//--------------------------------------------------------------------------------
323
ea5c1679
VS
324wxHtmlImageCell::wxHtmlImageCell(wxWindow *window, wxFSFile *input,
325 int w, int h, double scale, int align,
326 const wxString& mapname) : wxHtmlCell()
5526e819 327{
ea5c1679
VS
328 m_window = wxStaticCast(window, wxScrolledWindow);
329 m_scale = scale;
330 m_bitmap = NULL;
331 m_bmpW = w;
332 m_bmpH = h;
333 m_imageMap = NULL;
334 m_mapName = mapname;
335 SetCanLiveOnPagebreak(FALSE);
336#if wxUSE_GIF && wxUSE_TIMER
337 m_gifDecoder = NULL;
338 m_gifTimer = NULL;
339 m_physX = m_physY = -1;
340#endif
04dbb646 341
ea5c1679
VS
342 wxInputStream *s = input->GetStream();
343
344 if ( s )
4f9297b0 345 {
ea5c1679
VS
346 bool readImg = TRUE;
347
348#if wxUSE_GIF && wxUSE_TIMER
349 if ( (input->GetLocation().Matches(wxT("*.gif")) ||
350 input->GetLocation().Matches(wxT("*.GIF"))) && m_window )
351 {
352 m_gifDecoder = new wxGIFDecoder(s, TRUE);
353 if ( m_gifDecoder->ReadGIF() == wxGIF_OK )
354 {
355 wxImage img;
356 if ( m_gifDecoder->ConvertToImage(&img) )
357 SetImage(img);
37a1f3f6 358
ea5c1679 359 readImg = FALSE;
37a1f3f6 360
ea5c1679
VS
361 if ( m_gifDecoder->IsAnimation() )
362 {
363 m_gifTimer = new wxGIFTimer(this);
364 m_gifTimer->Start(m_gifDecoder->GetDelay(), TRUE);
365 }
366 else
367 {
368 wxDELETE(m_gifDecoder);
369 }
370 }
371 else
372 {
373 wxDELETE(m_gifDecoder);
374 }
375 }
376
377 if ( readImg )
378#endif
04dbb646 379 {
ea5c1679 380 SetImage(wxImage(*s, wxBITMAP_TYPE_ANY));
04dbb646 381 }
5526e819 382 }
ea5c1679
VS
383
384 m_Width = (int)(scale * (double)m_bmpW);
385 m_Height = (int)(scale * (double)m_bmpH);
386
04dbb646 387 switch (align)
4f9297b0 388 {
efba2b89 389 case wxHTML_ALIGN_TOP :
01325161
VS
390 m_Descent = m_Height;
391 break;
efba2b89 392 case wxHTML_ALIGN_CENTER :
01325161
VS
393 m_Descent = m_Height / 2;
394 break;
395 case wxHTML_ALIGN_BOTTOM :
396 default :
397 m_Descent = 0;
398 break;
5526e819 399 }
ea5c1679 400 }
25082126 401
ea5c1679
VS
402void wxHtmlImageCell::SetImage(const wxImage& img)
403{
404 if ( img.Ok() )
405 {
406 delete m_bitmap;
407
408 int ww, hh;
409 ww = img.GetWidth();
410 hh = img.GetHeight();
411
412 if ( m_bmpW == -1 )
413 m_bmpW = ww;
414 if ( m_bmpH == -1 )
415 m_bmpH = hh;
416
417 if ((m_bmpW != ww) || (m_bmpH != hh))
418 {
419 wxImage img2 = img.Scale(m_bmpW, m_bmpH);
420 m_bitmap = new wxBitmap(img2);
421 }
422 else
423 m_bitmap = new wxBitmap(img);
424 }
5526e819
VS
425}
426
ea5c1679
VS
427#if wxUSE_GIF && wxUSE_TIMER
428void wxHtmlImageCell::AdvanceAnimation(wxTimer *timer)
429{
430 wxImage img;
431
432 m_gifDecoder->GoNextFrame(TRUE);
433
434 if ( m_physX == -1 )
435 {
436 m_physX = m_physY = 0;
437 for (wxHtmlCell *cell = this; cell; cell = cell->GetParent())
438 {
439 m_physX += cell->GetPosX();
440 m_physY += cell->GetPosY();
441 }
442 }
443
444 int x, y;
445 m_window->CalcScrolledPosition(m_physX, m_physY, &x, &y);
446 wxRect rect(x, y, m_Width, m_Height);
447
448 if ( m_window->GetClientRect().Intersects(rect) &&
449 m_gifDecoder->ConvertToImage(&img) )
450 {
451 SetImage(img);
452 m_window->Refresh(img.HasMask(), &rect);
453 }
454
455 timer->Start(m_gifDecoder->GetDelay(), TRUE);
456}
457
458void wxHtmlImageCell::Layout(int w)
459{
460 wxHtmlCell::Layout(w);
461 m_physX = m_physY = -1;
462}
463
464#endif
465
466wxHtmlImageCell::~wxHtmlImageCell()
467{
468 delete m_bitmap;
469#if wxUSE_GIF && wxUSE_TIMER
470 delete m_gifTimer;
471 delete m_gifDecoder;
472#endif
473}
5526e819
VS
474
475
d699f48b 476void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int WXUNUSED(view_y1), int WXUNUSED(view_y2))
5526e819 477{
ea5c1679 478 if (m_bitmap)
b5c01940
VS
479 {
480 double us_x, us_y;
481 dc.GetUserScale(&us_x, &us_y);
ea5c1679 482 dc.SetUserScale(us_x * m_scale, us_y * m_scale);
04dbb646 483
ea5c1679
VS
484 dc.DrawBitmap(*m_bitmap, (int) ((x + m_PosX) / m_scale),
485 (int) ((y + m_PosY) / m_scale), TRUE);
b5c01940
VS
486 dc.SetUserScale(us_x, us_y);
487 }
5526e819
VS
488}
489
846914d1 490wxHtmlLinkInfo *wxHtmlImageCell::GetLink( int x, int y ) const
25082126 491{
ea5c1679 492 if (m_mapName.IsEmpty())
01325161 493 return wxHtmlCell::GetLink( x, y );
ea5c1679 494 if (!m_imageMap)
4f9297b0 495 {
edbd0635 496 wxHtmlContainerCell *p, *op;
01325161 497 op = p = GetParent();
04dbb646
VZ
498 while (p)
499 {
01325161
VS
500 op = p;
501 p = p->GetParent();
502 }
503 p = op;
ea5c1679
VS
504 wxHtmlCell *cell = (wxHtmlCell*)p->Find(wxHTML_COND_ISIMAGEMAP,
505 (const void*)(&m_mapName));
04dbb646
VZ
506 if (!cell)
507 {
ea5c1679 508 ((wxString&)m_mapName).Clear();
01325161
VS
509 return wxHtmlCell::GetLink( x, y );
510 }
4f9297b0 511 { // dirty hack, ask Joel why he fills m_ImageMap in this place
01325161 512 // THE problem is that we're in const method and we can't modify m_ImageMap
ea5c1679 513 wxHtmlImageMapCell **cx = (wxHtmlImageMapCell**)(&m_imageMap);
01325161 514 *cx = (wxHtmlImageMapCell*)cell;
25082126 515 }
01325161 516 }
ea5c1679 517 return m_imageMap->GetLink(x, y);
25082126 518}
5526e819
VS
519
520
521
522//--------------------------------------------------------------------------------
523// tag handler
524//--------------------------------------------------------------------------------
525
01325161 526TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
5526e819
VS
527
528 TAG_HANDLER_PROC(tag)
529 {
04dbb646
VZ
530 if (tag.GetName() == wxT("IMG"))
531 {
532 if (tag.HasParam(wxT("SRC")))
533 {
01325161
VS
534 int w = -1, h = -1;
535 int al;
536 wxFSFile *str;
0413cec5 537 wxString tmp = tag.GetParam(wxT("SRC"));
01325161
VS
538 wxString mn = wxEmptyString;
539
4f9297b0 540 str = m_WParser->GetFS()->OpenFile(tmp);
04dbb646 541 if (tag.HasParam(wxT("WIDTH")))
8bd72d90 542 tag.GetParamAsInt(wxT("WIDTH"), &w);
04dbb646 543 if (tag.HasParam(wxT("HEIGHT")))
8bd72d90 544 tag.GetParamAsInt(wxT("HEIGHT"), &h);
01325161 545 al = wxHTML_ALIGN_BOTTOM;
04dbb646
VZ
546 if (tag.HasParam(wxT("ALIGN")))
547 {
0413cec5 548 wxString alstr = tag.GetParam(wxT("ALIGN"));
01325161 549 alstr.MakeUpper(); // for the case alignment was in ".."
04dbb646 550 if (alstr == wxT("TEXTTOP"))
8bd72d90 551 al = wxHTML_ALIGN_TOP;
04dbb646 552 else if ((alstr == wxT("CENTER")) || (alstr == wxT("ABSCENTER")))
8bd72d90 553 al = wxHTML_ALIGN_CENTER;
01325161 554 }
04dbb646
VZ
555 if (tag.HasParam(wxT("USEMAP")))
556 {
0413cec5 557 mn = tag.GetParam( wxT("USEMAP") );
04dbb646
VZ
558 if (mn.GetChar(0) == wxT('#'))
559 {
01325161
VS
560 mn = mn.Mid( 1 );
561 }
562 }
563 wxHtmlImageCell *cel = NULL;
04dbb646
VZ
564 if (str)
565 {
ea5c1679
VS
566 cel = new wxHtmlImageCell(m_WParser->GetWindow(),
567 str, w, h,
568 m_WParser->GetPixelScale(),
569 al, mn);
4f9297b0 570 cel->SetLink(m_WParser->GetLink());
50da928b 571 cel->SetId(tag.GetParam(wxT("id"))); // may be empty
4f9297b0 572 m_WParser->GetContainer()->InsertCell(cel);
01325161
VS
573 delete str;
574 }
575 }
576 }
04dbb646
VZ
577 if (tag.GetName() == wxT("MAP"))
578 {
01325161
VS
579 m_WParser->CloseContainer();
580 m_WParser->OpenContainer();
04dbb646
VZ
581 if (tag.HasParam(wxT("NAME")))
582 {
0413cec5 583 wxString tmp = tag.GetParam(wxT("NAME"));
01325161
VS
584 wxHtmlImageMapCell *cel = new wxHtmlImageMapCell( tmp );
585 m_WParser->GetContainer()->InsertCell( cel );
586 }
587 ParseInner( tag );
588 m_WParser->CloseContainer();
589 m_WParser->OpenContainer();
590 }
04dbb646
VZ
591 if (tag.GetName() == wxT("AREA"))
592 {
593 if (tag.HasParam(wxT("SHAPE")))
594 {
0413cec5 595 wxString tmp = tag.GetParam(wxT("SHAPE"));
edbd0635 596 wxString coords = wxEmptyString;
01325161
VS
597 tmp.MakeUpper();
598 wxHtmlImageMapAreaCell *cel = NULL;
04dbb646
VZ
599 if (tag.HasParam(wxT("COORDS")))
600 {
0413cec5 601 coords = tag.GetParam(wxT("COORDS"));
01325161 602 }
04dbb646
VZ
603 if (tmp == wxT("POLY"))
604 {
4f9297b0 605 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY, coords, m_WParser->GetPixelScale() );
04dbb646
VZ
606 }
607 else if (tmp == wxT("CIRCLE"))
608 {
4f9297b0 609 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE, coords, m_WParser->GetPixelScale() );
04dbb646
VZ
610 }
611 else if (tmp == wxT("RECT"))
612 {
4f9297b0 613 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT, coords, m_WParser->GetPixelScale() );
01325161 614 }
04dbb646
VZ
615 if (cel != NULL && tag.HasParam(wxT("HREF")))
616 {
0413cec5 617 wxString tmp = tag.GetParam(wxT("HREF"));
846914d1 618 wxString target = wxEmptyString;
0413cec5 619 if (tag.HasParam(wxT("TARGET"))) target = tag.GetParam(wxT("TARGET"));
846914d1 620 cel->SetLink( wxHtmlLinkInfo(tmp, target));
01325161
VS
621 }
622 if (cel != NULL) m_WParser->GetContainer()->InsertCell( cel );
623 }
624 }
5526e819
VS
625
626 return FALSE;
627 }
628
01325161 629TAG_HANDLER_END(IMG)
5526e819
VS
630
631
632
633TAGS_MODULE_BEGIN(Image)
634
635 TAGS_MODULE_ADD(IMG)
636
637TAGS_MODULE_END(Image)
638
639
3364ab79 640#endif