]> git.saurik.com Git - wxWidgets.git/blob - src/html/m_image.cpp
fixed mouse capture release code -- it previously released capture of window that...
[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 #include "wx/scrolwin.h"
26 #include "wx/timer.h"
27 #endif
28
29 #include "wx/html/forcelnk.h"
30 #include "wx/html/m_templ.h"
31
32 #include "wx/image.h"
33 #include "wx/gifdecod.h"
34 #include "wx/dynarray.h"
35
36 #include <math.h>
37 #include <float.h>
38
39 FORCE_LINK_ME(m_image)
40
41
42
43
44 WX_DECLARE_OBJARRAY(int, CoordArray);
45 #include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
46 WX_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
55 class wxHtmlImageMapAreaCell : public wxHtmlCell
56 {
57 public:
58 enum celltype { CIRCLE, RECT, POLY };
59 protected:
60 CoordArray coords;
61 celltype type;
62 int radius;
63 public:
64 wxHtmlImageMapAreaCell( celltype t, wxString &coords, double pixel_scale = 1.0);
65 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
66 };
67
68
69
70
71
72 wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t, wxString &incoords, double pixel_scale )
73 {
74 int i;
75 wxString x = incoords, y;
76
77 type = t;
78 while ((i = x.Find( ',' )) != -1)
79 {
80 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.Left( i ).c_str())) );
81 x = x.Mid( i + 1 );
82 }
83 coords.Add( (int)(pixel_scale * (double)wxAtoi( x.c_str())) );
84 }
85
86 wxHtmlLinkInfo *wxHtmlImageMapAreaCell::GetLink( int x, int y ) const
87 {
88 switch (type)
89 {
90 case RECT:
91 {
92 int l, t, r, b;
93
94 l = coords[ 0 ];
95 t = coords[ 1 ];
96 r = coords[ 2 ];
97 b = coords[ 3 ];
98 if (x >= l && x <= r && y >= t && y <= b)
99 {
100 return m_Link;
101 }
102 break;
103 }
104 case CIRCLE:
105 {
106 int l, t, r;
107 double d;
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))) );
113 if (d < (double)r)
114 {
115 return m_Link;
116 }
117 }
118 break;
119 case POLY:
120 {
121 if (coords.GetCount() >= 6)
122 {
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;
132
133 if ((yval >= wherey) != (coords[pointer] >= wherey))
134 {
135 if ((xval >= wherex) == (coords[0] >= wherex))
136 {
137 intersects += (xval >= wherex) ? 1 : 0;
138 }
139 else
140 {
141 intersects += ((xval - (yval - wherey) *
142 (coords[0] - xval) /
143 (coords[pointer] - yval)) >= wherex) ? 1 : 0;
144 }
145 }
146
147 while (pointer < end)
148 {
149 yval = coords[pointer];
150 pointer += 2;
151 if (yval >= wherey)
152 {
153 while ((pointer < end) && (coords[pointer] >= wherey))
154 {
155 pointer += 2;
156 }
157 if (pointer >= end)
158 {
159 break;
160 }
161 if ((coords[pointer - 3] >= wherex) ==
162 (coords[pointer - 1] >= wherex)) {
163 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
164 }
165 else
166 {
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 }
172 }
173 else
174 {
175 while ((pointer < end) && (coords[pointer] < wherey))
176 {
177 pointer += 2;
178 }
179 if (pointer >= end)
180 {
181 break;
182 }
183 if ((coords[pointer - 3] >= wherex) ==
184 (coords[pointer - 1] >= wherex))
185 {
186 intersects += (coords[pointer - 3] >= wherex) ? 1 : 0;
187 }
188 else
189 {
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 }
197 if ((intersects & 1) != 0)
198 {
199 return m_Link;
200 }
201 }
202 }
203 break;
204 }
205
206 if (m_Next)
207 {
208 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
209 return a->GetLink( x, y );
210 }
211 return NULL;
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
225 // It responds to Find(wxHTML_COND_ISIMAGEMAP)
226 //--------------------------------------------------------------------------------
227
228
229 class wxHtmlImageMapCell : public wxHtmlCell
230 {
231 public:
232 wxHtmlImageMapCell( wxString &name );
233 protected:
234 wxString m_Name;
235 public:
236 virtual wxHtmlLinkInfo *GetLink( int x = 0, int y = 0 ) const;
237 virtual const wxHtmlCell *Find( int cond, const void *param ) const;
238 };
239
240
241 wxHtmlImageMapCell::wxHtmlImageMapCell( wxString &name )
242 {
243 m_Name = name ;
244 }
245
246 wxHtmlLinkInfo *wxHtmlImageMapCell::GetLink( int x, int y ) const
247 {
248 wxHtmlImageMapAreaCell *a = (wxHtmlImageMapAreaCell*)m_Next;
249 if (a)
250 return a->GetLink( x, y );
251 return wxHtmlCell::GetLink( x, y );
252 }
253
254 const wxHtmlCell *wxHtmlImageMapCell::Find( int cond, const void *param ) const
255 {
256 if (cond == wxHTML_COND_ISIMAGEMAP)
257 {
258 if (m_Name == *((wxString*)(param)))
259 return this;
260 }
261 return wxHtmlCell::Find(cond, param);
262 }
263
264
265
266
267
268 //--------------------------------------------------------------------------------
269 // wxHtmlImageCell
270 // Image/bitmap
271 //--------------------------------------------------------------------------------
272
273 class wxHtmlImageCell : public wxHtmlCell
274 {
275 public:
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
290 private:
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;
302 };
303
304 #if wxUSE_GIF && wxUSE_TIMER
305 class wxGIFTimer : public wxTimer
306 {
307 public:
308 wxGIFTimer(wxHtmlImageCell *cell) : m_cell(cell) {}
309 virtual void Notify()
310 {
311 m_cell->AdvanceAnimation(this);
312 }
313
314 private:
315 wxHtmlImageCell *m_cell;
316 };
317 #endif
318
319
320 //--------------------------------------------------------------------------------
321 // wxHtmlImageCell
322 //--------------------------------------------------------------------------------
323
324 wxHtmlImageCell::wxHtmlImageCell(wxWindow *window, wxFSFile *input,
325 int w, int h, double scale, int align,
326 const wxString& mapname) : wxHtmlCell()
327 {
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
341
342 wxInputStream *s = input->GetStream();
343
344 if ( s )
345 {
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);
358
359 readImg = FALSE;
360
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
379 {
380 SetImage(wxImage(*s, wxBITMAP_TYPE_ANY));
381 }
382 }
383
384 m_Width = (int)(scale * (double)m_bmpW);
385 m_Height = (int)(scale * (double)m_bmpH);
386
387 switch (align)
388 {
389 case wxHTML_ALIGN_TOP :
390 m_Descent = m_Height;
391 break;
392 case wxHTML_ALIGN_CENTER :
393 m_Descent = m_Height / 2;
394 break;
395 case wxHTML_ALIGN_BOTTOM :
396 default :
397 m_Descent = 0;
398 break;
399 }
400 }
401
402 void 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 }
425 }
426
427 #if wxUSE_GIF && wxUSE_TIMER
428 void 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
458 void wxHtmlImageCell::Layout(int w)
459 {
460 wxHtmlCell::Layout(w);
461 m_physX = m_physY = -1;
462 }
463
464 #endif
465
466 wxHtmlImageCell::~wxHtmlImageCell()
467 {
468 delete m_bitmap;
469 #if wxUSE_GIF && wxUSE_TIMER
470 delete m_gifTimer;
471 delete m_gifDecoder;
472 #endif
473 }
474
475
476 void wxHtmlImageCell::Draw(wxDC& dc, int x, int y, int WXUNUSED(view_y1), int WXUNUSED(view_y2))
477 {
478 if (m_bitmap)
479 {
480 double us_x, us_y;
481 dc.GetUserScale(&us_x, &us_y);
482 dc.SetUserScale(us_x * m_scale, us_y * m_scale);
483
484 dc.DrawBitmap(*m_bitmap, (int) ((x + m_PosX) / m_scale),
485 (int) ((y + m_PosY) / m_scale), TRUE);
486 dc.SetUserScale(us_x, us_y);
487 }
488 }
489
490 wxHtmlLinkInfo *wxHtmlImageCell::GetLink( int x, int y ) const
491 {
492 if (m_mapName.IsEmpty())
493 return wxHtmlCell::GetLink( x, y );
494 if (!m_imageMap)
495 {
496 wxHtmlContainerCell *p, *op;
497 op = p = GetParent();
498 while (p)
499 {
500 op = p;
501 p = p->GetParent();
502 }
503 p = op;
504 wxHtmlCell *cell = (wxHtmlCell*)p->Find(wxHTML_COND_ISIMAGEMAP,
505 (const void*)(&m_mapName));
506 if (!cell)
507 {
508 ((wxString&)m_mapName).Clear();
509 return wxHtmlCell::GetLink( x, y );
510 }
511 { // dirty hack, ask Joel why he fills m_ImageMap in this place
512 // THE problem is that we're in const method and we can't modify m_ImageMap
513 wxHtmlImageMapCell **cx = (wxHtmlImageMapCell**)(&m_imageMap);
514 *cx = (wxHtmlImageMapCell*)cell;
515 }
516 }
517 return m_imageMap->GetLink(x, y);
518 }
519
520
521
522 //--------------------------------------------------------------------------------
523 // tag handler
524 //--------------------------------------------------------------------------------
525
526 TAG_HANDLER_BEGIN(IMG, "IMG,MAP,AREA")
527
528 TAG_HANDLER_PROC(tag)
529 {
530 if (tag.GetName() == wxT("IMG"))
531 {
532 if (tag.HasParam(wxT("SRC")))
533 {
534 int w = -1, h = -1;
535 int al;
536 wxFSFile *str;
537 wxString tmp = tag.GetParam(wxT("SRC"));
538 wxString mn = wxEmptyString;
539
540 str = m_WParser->GetFS()->OpenFile(tmp);
541 if (tag.HasParam(wxT("WIDTH")))
542 tag.GetParamAsInt(wxT("WIDTH"), &w);
543 if (tag.HasParam(wxT("HEIGHT")))
544 tag.GetParamAsInt(wxT("HEIGHT"), &h);
545 al = wxHTML_ALIGN_BOTTOM;
546 if (tag.HasParam(wxT("ALIGN")))
547 {
548 wxString alstr = tag.GetParam(wxT("ALIGN"));
549 alstr.MakeUpper(); // for the case alignment was in ".."
550 if (alstr == wxT("TEXTTOP"))
551 al = wxHTML_ALIGN_TOP;
552 else if ((alstr == wxT("CENTER")) || (alstr == wxT("ABSCENTER")))
553 al = wxHTML_ALIGN_CENTER;
554 }
555 if (tag.HasParam(wxT("USEMAP")))
556 {
557 mn = tag.GetParam( wxT("USEMAP") );
558 if (mn.GetChar(0) == wxT('#'))
559 {
560 mn = mn.Mid( 1 );
561 }
562 }
563 wxHtmlImageCell *cel = NULL;
564 if (str)
565 {
566 cel = new wxHtmlImageCell(m_WParser->GetWindow(),
567 str, w, h,
568 m_WParser->GetPixelScale(),
569 al, mn);
570 cel->SetLink(m_WParser->GetLink());
571 cel->SetId(tag.GetParam(wxT("id"))); // may be empty
572 m_WParser->GetContainer()->InsertCell(cel);
573 delete str;
574 }
575 }
576 }
577 if (tag.GetName() == wxT("MAP"))
578 {
579 m_WParser->CloseContainer();
580 m_WParser->OpenContainer();
581 if (tag.HasParam(wxT("NAME")))
582 {
583 wxString tmp = tag.GetParam(wxT("NAME"));
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 }
591 if (tag.GetName() == wxT("AREA"))
592 {
593 if (tag.HasParam(wxT("SHAPE")))
594 {
595 wxString tmp = tag.GetParam(wxT("SHAPE"));
596 wxString coords = wxEmptyString;
597 tmp.MakeUpper();
598 wxHtmlImageMapAreaCell *cel = NULL;
599 if (tag.HasParam(wxT("COORDS")))
600 {
601 coords = tag.GetParam(wxT("COORDS"));
602 }
603 if (tmp == wxT("POLY"))
604 {
605 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY, coords, m_WParser->GetPixelScale() );
606 }
607 else if (tmp == wxT("CIRCLE"))
608 {
609 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE, coords, m_WParser->GetPixelScale() );
610 }
611 else if (tmp == wxT("RECT"))
612 {
613 cel = new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT, coords, m_WParser->GetPixelScale() );
614 }
615 if (cel != NULL && tag.HasParam(wxT("HREF")))
616 {
617 wxString tmp = tag.GetParam(wxT("HREF"));
618 wxString target = wxEmptyString;
619 if (tag.HasParam(wxT("TARGET"))) target = tag.GetParam(wxT("TARGET"));
620 cel->SetLink( wxHtmlLinkInfo(tmp, target));
621 }
622 if (cel != NULL) m_WParser->GetContainer()->InsertCell( cel );
623 }
624 }
625
626 return FALSE;
627 }
628
629 TAG_HANDLER_END(IMG)
630
631
632
633 TAGS_MODULE_BEGIN(Image)
634
635 TAGS_MODULE_ADD(IMG)
636
637 TAGS_MODULE_END(Image)
638
639
640 #endif