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