]>
git.saurik.com Git - wxWidgets.git/blob - src/html/m_image.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/html/m_image.cpp
3 // Purpose: wxHtml module for displaying images
4 // Author: Vaclav Slavik
6 // Copyright: (c) 1999 Vaclav Slavik, Joel Lucsy
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 #include "wx/wxprec.h"
16 #if wxUSE_HTML && wxUSE_STREAMS
19 #include "wx/dynarray.h"
21 #include "wx/scrolwin.h"
23 #include "wx/dcmemory.h"
26 #include "wx/html/forcelnk.h"
27 #include "wx/html/m_templ.h"
28 #include "wx/html/htmlwin.h"
31 #include "wx/gifdecod.h"
33 #include "wx/artprov.h"
38 FORCE_LINK_ME(m_image
)
43 WX_DECLARE_OBJARRAY(int, CoordArray
);
44 #include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
45 WX_DEFINE_OBJARRAY(CoordArray
)
48 // ---------------------------------------------------------------------------
49 // wxHtmlImageMapAreaCell
50 // 0-width, 0-height cell that represents single area in
51 // imagemap (it's GetLink is called from wxHtmlImageCell's)
52 // ---------------------------------------------------------------------------
54 class wxHtmlImageMapAreaCell
: public wxHtmlCell
57 enum celltype
{ CIRCLE
, RECT
, POLY
};
63 wxHtmlImageMapAreaCell( celltype t
, wxString
&coords
, double pixel_scale
= 1.0);
64 virtual wxHtmlLinkInfo
*GetLink( int x
= 0, int y
= 0 ) const;
65 void Draw(wxDC
& WXUNUSED(dc
),
66 int WXUNUSED(x
), int WXUNUSED(y
),
67 int WXUNUSED(view_y1
), int WXUNUSED(view_y2
),
68 wxHtmlRenderingInfo
& WXUNUSED(info
)) {}
71 DECLARE_NO_COPY_CLASS(wxHtmlImageMapAreaCell
)
78 wxHtmlImageMapAreaCell::wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::celltype t
, wxString
&incoords
, double pixel_scale
)
81 wxString x
= incoords
, y
;
84 while ((i
= x
.Find( ',' )) != wxNOT_FOUND
)
86 coords
.Add( (int)(pixel_scale
* (double)wxAtoi( x
.Left( i
).c_str())) );
89 coords
.Add( (int)(pixel_scale
* (double)wxAtoi( x
.c_str())) );
92 wxHtmlLinkInfo
*wxHtmlImageMapAreaCell::GetLink( int x
, int y
) const
104 if (x
>= l
&& x
<= r
&& y
>= t
&& y
<= b
)
118 d
= sqrt( (double) (((x
- l
) * (x
- l
)) + ((y
- t
) * (y
- t
))) );
127 if (coords
.GetCount() >= 6)
132 int totalv
= coords
.GetCount() / 2;
133 int totalc
= totalv
* 2;
134 int xval
= coords
[totalc
- 2];
135 int yval
= coords
[totalc
- 1];
139 if ((yval
>= wherey
) != (coords
[pointer
] >= wherey
))
141 if ((xval
>= wherex
) == (coords
[0] >= wherex
))
143 intersects
+= (xval
>= wherex
) ? 1 : 0;
147 intersects
+= ((xval
- (yval
- wherey
) *
149 (coords
[pointer
] - yval
)) >= wherex
) ? 1 : 0;
153 while (pointer
< end
)
155 yval
= coords
[pointer
];
159 while ((pointer
< end
) && (coords
[pointer
] >= wherey
))
167 if ((coords
[pointer
- 3] >= wherex
) ==
168 (coords
[pointer
- 1] >= wherex
)) {
169 intersects
+= (coords
[pointer
- 3] >= wherex
) ? 1 : 0;
174 ((coords
[pointer
- 3] - (coords
[pointer
- 2] - wherey
) *
175 (coords
[pointer
- 1] - coords
[pointer
- 3]) /
176 (coords
[pointer
] - coords
[pointer
- 2])) >= wherex
) ? 1 : 0;
181 while ((pointer
< end
) && (coords
[pointer
] < wherey
))
189 if ((coords
[pointer
- 3] >= wherex
) ==
190 (coords
[pointer
- 1] >= wherex
))
192 intersects
+= (coords
[pointer
- 3] >= wherex
) ? 1 : 0;
197 ((coords
[pointer
- 3] - (coords
[pointer
- 2] - wherey
) *
198 (coords
[pointer
- 1] - coords
[pointer
- 3]) /
199 (coords
[pointer
] - coords
[pointer
- 2])) >= wherex
) ? 1 : 0;
203 if ((intersects
& 1) != 0)
214 wxHtmlImageMapAreaCell
*a
= (wxHtmlImageMapAreaCell
*)m_Next
;
215 return a
->GetLink( x
, y
);
227 //--------------------------------------------------------------------------------
228 // wxHtmlImageMapCell
229 // 0-width, 0-height cell that represents map from imagemaps
230 // it is always placed before wxHtmlImageMapAreaCells
231 // It responds to Find(wxHTML_COND_ISIMAGEMAP)
232 //--------------------------------------------------------------------------------
235 class wxHtmlImageMapCell
: public wxHtmlCell
238 wxHtmlImageMapCell( wxString
&name
);
242 virtual wxHtmlLinkInfo
*GetLink( int x
= 0, int y
= 0 ) const;
243 virtual const wxHtmlCell
*Find( int cond
, const void *param
) const;
244 void Draw(wxDC
& WXUNUSED(dc
),
245 int WXUNUSED(x
), int WXUNUSED(y
),
246 int WXUNUSED(view_y1
), int WXUNUSED(view_y2
),
247 wxHtmlRenderingInfo
& WXUNUSED(info
)) {}
249 DECLARE_NO_COPY_CLASS(wxHtmlImageMapCell
)
253 wxHtmlImageMapCell::wxHtmlImageMapCell( wxString
&name
)
258 wxHtmlLinkInfo
*wxHtmlImageMapCell::GetLink( int x
, int y
) const
260 wxHtmlImageMapAreaCell
*a
= (wxHtmlImageMapAreaCell
*)m_Next
;
262 return a
->GetLink( x
, y
);
263 return wxHtmlCell::GetLink( x
, y
);
266 const wxHtmlCell
*wxHtmlImageMapCell::Find( int cond
, const void *param
) const
268 if (cond
== wxHTML_COND_ISIMAGEMAP
)
270 if (m_Name
== *((wxString
*)(param
)))
273 return wxHtmlCell::Find(cond
, param
);
280 //--------------------------------------------------------------------------------
283 //--------------------------------------------------------------------------------
285 class wxHtmlImageCell
: public wxHtmlCell
288 wxHtmlImageCell(wxHtmlWindowInterface
*windowIface
,
289 wxFSFile
*input
, int w
= wxDefaultCoord
, int h
= wxDefaultCoord
,
290 double scale
= 1.0, int align
= wxHTML_ALIGN_BOTTOM
,
291 const wxString
& mapname
= wxEmptyString
);
293 void Draw(wxDC
& dc
, int x
, int y
, int view_y1
, int view_y2
,
294 wxHtmlRenderingInfo
& info
);
295 virtual wxHtmlLinkInfo
*GetLink(int x
= 0, int y
= 0) const;
297 void SetImage(const wxImage
& img
);
298 #if wxUSE_GIF && wxUSE_TIMER
299 void AdvanceAnimation(wxTimer
*timer
);
300 virtual void Layout(int w
);
307 wxHtmlWindowInterface
*m_windowIface
;
308 #if wxUSE_GIF && wxUSE_TIMER
309 wxGIFDecoder
*m_gifDecoder
;
311 int m_physX
, m_physY
;
314 wxHtmlImageMapCell
*m_imageMap
;
317 DECLARE_NO_COPY_CLASS(wxHtmlImageCell
)
320 #if wxUSE_GIF && wxUSE_TIMER
321 class wxGIFTimer
: public wxTimer
324 wxGIFTimer(wxHtmlImageCell
*cell
) : m_cell(cell
) {}
325 virtual void Notify()
327 m_cell
->AdvanceAnimation(this);
331 wxHtmlImageCell
*m_cell
;
333 DECLARE_NO_COPY_CLASS(wxGIFTimer
)
338 //----------------------------------------------------------------------------
340 //----------------------------------------------------------------------------
343 wxHtmlImageCell::wxHtmlImageCell(wxHtmlWindowInterface
*windowIface
,
345 int w
, int h
, double scale
, int align
,
346 const wxString
& mapname
) : wxHtmlCell()
348 m_windowIface
= windowIface
;
356 SetCanLiveOnPagebreak(false);
357 #if wxUSE_GIF && wxUSE_TIMER
360 m_physX
= m_physY
= wxDefaultCoord
;
363 if ( m_bmpW
&& m_bmpH
)
367 wxInputStream
*s
= input
->GetStream();
371 #if wxUSE_GIF && wxUSE_TIMER
373 if ( m_windowIface
&&
374 (input
->GetLocation().Matches(wxT("*.gif")) ||
375 input
->GetLocation().Matches(wxT("*.GIF"))) )
377 m_gifDecoder
= new wxGIFDecoder(s
, true);
378 if ( m_gifDecoder
->ReadGIF() == wxGIF_OK
)
381 if ( m_gifDecoder
->ConvertToImage(&img
) )
386 if ( m_gifDecoder
->IsAnimation() )
388 m_gifTimer
= new wxGIFTimer(this);
389 m_gifTimer
->Start(m_gifDecoder
->GetDelay(), true);
393 wxDELETE(m_gifDecoder
);
398 wxDELETE(m_gifDecoder
);
403 #endif // wxUSE_GIF && wxUSE_TIMER
405 wxImage
image(*s
, wxBITMAP_TYPE_ANY
);
411 else // input==NULL, use "broken image" bitmap
413 if ( m_bmpW
== wxDefaultCoord
&& m_bmpH
== wxDefaultCoord
)
421 if ( m_bmpW
== wxDefaultCoord
) m_bmpW
= 31;
422 if ( m_bmpH
== wxDefaultCoord
) m_bmpH
= 33;
425 new wxBitmap(wxArtProvider::GetBitmap(wxART_MISSING_IMAGE
));
428 //else: ignore the 0-sized images used sometimes on the Web pages
430 m_Width
= (int)(scale
* (double)m_bmpW
);
431 m_Height
= (int)(scale
* (double)m_bmpH
);
435 case wxHTML_ALIGN_TOP
:
436 m_Descent
= m_Height
;
438 case wxHTML_ALIGN_CENTER
:
439 m_Descent
= m_Height
/ 2;
441 case wxHTML_ALIGN_BOTTOM
:
448 void wxHtmlImageCell::SetImage(const wxImage
& img
)
450 #if !defined(__WXMSW__) || wxUSE_WXDIB
457 hh
= img
.GetHeight();
459 if ( m_bmpW
== wxDefaultCoord
)
461 if ( m_bmpH
== wxDefaultCoord
)
464 // Only scale the bitmap at the rendering stage,
465 // so we don't lose quality twice
467 if ((m_bmpW != ww) || (m_bmpH != hh))
469 wxImage img2 = img.Scale(m_bmpW, m_bmpH);
470 m_bitmap = new wxBitmap(img2);
474 m_bitmap
= new wxBitmap(img
);
479 #if wxUSE_GIF && wxUSE_TIMER
480 void wxHtmlImageCell::AdvanceAnimation(wxTimer
*timer
)
484 m_gifDecoder
->GoNextFrame(true);
486 if ( m_physX
== wxDefaultCoord
)
488 m_physX
= m_physY
= 0;
489 for (wxHtmlCell
*cell
= this; cell
; cell
= cell
->GetParent())
491 m_physX
+= cell
->GetPosX();
492 m_physY
+= cell
->GetPosY();
496 wxWindow
*win
= m_windowIface
->GetHTMLWindow();
498 m_windowIface
->HTMLCoordsToWindow(this, wxPoint(m_physX
, m_physY
));
499 wxRect
rect(pos
, wxSize(m_Width
, m_Height
));
501 if ( win
->GetClientRect().Intersects(rect
) &&
502 m_gifDecoder
->ConvertToImage(&img
) )
504 #if !defined(__WXMSW__) || wxUSE_WXDIB
505 if ( (int)m_gifDecoder
->GetWidth() != m_Width
||
506 (int)m_gifDecoder
->GetHeight() != m_Height
||
507 m_gifDecoder
->GetLeft() != 0 || m_gifDecoder
->GetTop() != 0 )
511 dc
.SelectObject(*m_bitmap
);
512 dc
.DrawBitmap(bmp
, m_gifDecoder
->GetLeft(), m_gifDecoder
->GetTop(),
513 true /* use mask */);
518 win
->Refresh(img
.HasMask(), &rect
);
521 timer
->Start(m_gifDecoder
->GetDelay(), true);
524 void wxHtmlImageCell::Layout(int w
)
526 wxHtmlCell::Layout(w
);
527 m_physX
= m_physY
= wxDefaultCoord
;
532 wxHtmlImageCell::~wxHtmlImageCell()
535 #if wxUSE_GIF && wxUSE_TIMER
542 void wxHtmlImageCell::Draw(wxDC
& dc
, int x
, int y
,
543 int WXUNUSED(view_y1
), int WXUNUSED(view_y2
),
544 wxHtmlRenderingInfo
& WXUNUSED(info
))
548 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
549 dc
.SetPen(*wxBLACK_PEN
);
550 dc
.DrawRectangle(x
+ m_PosX
, y
+ m_PosY
, m_Width
, m_Height
);
555 // We add in the scaling from the desired bitmap width
556 // and height, so we only do the scaling once.
557 double imageScaleX
= 1.0;
558 double imageScaleY
= 1.0;
559 if (m_bmpW
!= m_bitmap
->GetWidth())
560 imageScaleX
= (double) m_bmpW
/ (double) m_bitmap
->GetWidth();
561 if (m_bmpH
!= m_bitmap
->GetHeight())
562 imageScaleY
= (double) m_bmpH
/ (double) m_bitmap
->GetHeight();
565 dc
.GetUserScale(&us_x
, &us_y
);
566 dc
.SetUserScale(us_x
* m_scale
* imageScaleX
, us_y
* m_scale
* imageScaleY
);
568 dc
.DrawBitmap(*m_bitmap
, (int) ((x
+ m_PosX
) / (m_scale
*imageScaleX
)),
569 (int) ((y
+ m_PosY
) / (m_scale
*imageScaleY
)), true);
570 dc
.SetUserScale(us_x
, us_y
);
574 wxHtmlLinkInfo
*wxHtmlImageCell::GetLink( int x
, int y
) const
576 if (m_mapName
.empty())
577 return wxHtmlCell::GetLink( x
, y
);
580 wxHtmlContainerCell
*p
, *op
;
581 op
= p
= GetParent();
588 wxHtmlCell
*cell
= (wxHtmlCell
*)p
->Find(wxHTML_COND_ISIMAGEMAP
,
589 (const void*)(&m_mapName
));
592 ((wxString
&)m_mapName
).Clear();
593 return wxHtmlCell::GetLink( x
, y
);
595 { // dirty hack, ask Joel why he fills m_ImageMap in this place
596 // THE problem is that we're in const method and we can't modify m_ImageMap
597 wxHtmlImageMapCell
**cx
= (wxHtmlImageMapCell
**)(&m_imageMap
);
598 *cx
= (wxHtmlImageMapCell
*)cell
;
601 return m_imageMap
->GetLink(x
, y
);
606 //--------------------------------------------------------------------------------
608 //--------------------------------------------------------------------------------
610 TAG_HANDLER_BEGIN(IMG
, "IMG,MAP,AREA")
611 TAG_HANDLER_CONSTR(IMG
) { }
613 TAG_HANDLER_PROC(tag
)
615 if (tag
.GetName() == wxT("IMG"))
617 if (tag
.HasParam(wxT("SRC")))
619 int w
= wxDefaultCoord
, h
= wxDefaultCoord
;
622 wxString tmp
= tag
.GetParam(wxT("SRC"));
623 wxString mn
= wxEmptyString
;
625 str
= m_WParser
->OpenURL(wxHTML_URL_IMAGE
, tmp
);
627 if (tag
.HasParam(wxT("WIDTH")))
628 tag
.GetParamAsInt(wxT("WIDTH"), &w
);
629 if (tag
.HasParam(wxT("HEIGHT")))
630 tag
.GetParamAsInt(wxT("HEIGHT"), &h
);
631 al
= wxHTML_ALIGN_BOTTOM
;
632 if (tag
.HasParam(wxT("ALIGN")))
634 wxString alstr
= tag
.GetParam(wxT("ALIGN"));
635 alstr
.MakeUpper(); // for the case alignment was in ".."
636 if (alstr
== wxT("TEXTTOP"))
637 al
= wxHTML_ALIGN_TOP
;
638 else if ((alstr
== wxT("CENTER")) || (alstr
== wxT("ABSCENTER")))
639 al
= wxHTML_ALIGN_CENTER
;
641 if (tag
.HasParam(wxT("USEMAP")))
643 mn
= tag
.GetParam( wxT("USEMAP") );
644 if (mn
.GetChar(0) == wxT('#'))
649 wxHtmlImageCell
*cel
= new wxHtmlImageCell(
650 m_WParser
->GetWindowInterface(),
652 m_WParser
->GetPixelScale(),
654 m_WParser
->ApplyStateToCell(cel
);
655 cel
->SetId(tag
.GetParam(wxT("id"))); // may be empty
656 m_WParser
->GetContainer()->InsertCell(cel
);
661 if (tag
.GetName() == wxT("MAP"))
663 m_WParser
->CloseContainer();
664 m_WParser
->OpenContainer();
665 if (tag
.HasParam(wxT("NAME")))
667 wxString tmp
= tag
.GetParam(wxT("NAME"));
668 wxHtmlImageMapCell
*cel
= new wxHtmlImageMapCell( tmp
);
669 m_WParser
->GetContainer()->InsertCell( cel
);
672 m_WParser
->CloseContainer();
673 m_WParser
->OpenContainer();
675 if (tag
.GetName() == wxT("AREA"))
677 if (tag
.HasParam(wxT("SHAPE")))
679 wxString tmp
= tag
.GetParam(wxT("SHAPE"));
680 wxString coords
= wxEmptyString
;
682 wxHtmlImageMapAreaCell
*cel
= NULL
;
683 if (tag
.HasParam(wxT("COORDS")))
685 coords
= tag
.GetParam(wxT("COORDS"));
687 if (tmp
== wxT("POLY"))
689 cel
= new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::POLY
, coords
, m_WParser
->GetPixelScale() );
691 else if (tmp
== wxT("CIRCLE"))
693 cel
= new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::CIRCLE
, coords
, m_WParser
->GetPixelScale() );
695 else if (tmp
== wxT("RECT"))
697 cel
= new wxHtmlImageMapAreaCell( wxHtmlImageMapAreaCell::RECT
, coords
, m_WParser
->GetPixelScale() );
699 if (cel
!= NULL
&& tag
.HasParam(wxT("HREF")))
702 if (tag
.HasParam(wxT("TARGET")))
703 target
= tag
.GetParam(wxT("TARGET"));
704 cel
->SetLink(wxHtmlLinkInfo(tag
.GetParam(wxT("HREF")), target
));
707 m_WParser
->GetContainer()->InsertCell( cel
);
718 TAGS_MODULE_BEGIN(Image
)
722 TAGS_MODULE_END(Image
)