1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2007 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
15 #include <sys/types.h>
22 #include "writeablebitmap.h"
23 #include "bitmapimage.h"
28 #include "downloader.h"
37 MediaBase::MediaBase ()
39 SetObjectType (Type::MEDIABASE
);
41 source
.downloader
= NULL
;
42 source
.part_name
= NULL
;
43 source
.queued
= false;
46 allow_downloads
= false;
47 source_changed
= false;
50 MediaBase::~MediaBase ()
56 MediaBase::downloader_complete (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
58 MediaBase
*media
= (MediaBase
*) closure
;
60 media
->DownloaderComplete ();
64 MediaBase::downloader_failed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
66 MediaBase
*media
= (MediaBase
*) closure
;
68 media
->DownloaderFailed (calldata
);
72 MediaBase::DownloaderComplete ()
74 // Nothing for MediaBase to do...
78 MediaBase::DownloaderFailed (EventArgs
*args
)
80 // Nothing for MediaBase to do...
84 MediaBase::DownloaderAbort ()
87 downloader
->RemoveHandler (Downloader::DownloadFailedEvent
, downloader_failed
, this);
88 downloader
->RemoveHandler (Downloader::CompletedEvent
, downloader_complete
, this);
89 downloader
->SetStreamFunctions (NULL
, NULL
, NULL
);
99 MediaBase::SetAllowDownloads (bool allow
)
101 Surface
*surface
= GetSurface ();
105 if ((allow_downloads
&& allow
) || (!allow_downloads
&& !allow
))
108 if (allow
&& surface
&& source_changed
) {
109 source_changed
= false;
111 if ((uri
= GetSource ()) && *uri
) {
112 if (!(dl
= surface
->CreateDownloader ())) {
113 // we're shutting down
117 dl
->Open ("GET", uri
, GetDownloaderPolicy (uri
));
123 allow_downloads
= allow
;
127 MediaBase::OnLoaded ()
129 FrameworkElement::OnLoaded ();
130 SetAllowDownloads (true);
134 MediaBase::SetSourceAsyncCallback ()
136 Downloader
*downloader
;
141 downloader
= source
.downloader
;
142 part_name
= source
.part_name
;
144 source
.queued
= false;
145 source
.downloader
= NULL
;
146 source
.part_name
= NULL
;
148 if (GetSurface () == NULL
)
151 SetSourceInternal (downloader
, part_name
);
154 downloader
->unref ();
158 MediaBase::SetSourceInternal (Downloader
*downloader
, char *PartName
)
160 this->downloader
= downloader
;
161 part_name
= PartName
;
168 MediaBase::set_source_async (EventObject
*user_data
)
170 MediaBase
*media
= (MediaBase
*) user_data
;
172 media
->SetSourceAsyncCallback ();
176 MediaBase::SetSource (Downloader
*downloader
, const char *PartName
)
178 source_changed
= false;
181 if (source
.downloader
)
182 source
.downloader
->unref ();
184 g_free (source
.part_name
);
185 source
.downloader
= NULL
;
186 source
.part_name
= NULL
;
189 source
.part_name
= g_strdup (PartName
);
190 source
.downloader
= downloader
;
195 if (source
.downloader
&& source
.downloader
->Completed ()) {
196 SetSourceInternal (source
.downloader
, source
.part_name
);
197 source
.downloader
->unref ();
198 } else if (!source
.queued
) {
199 AddTickCall (MediaBase::set_source_async
);
200 source
.queued
= true;
205 MediaBase::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
207 if (args
->GetId () == MediaBase::SourceProperty
) {
208 const char *uri
= args
->GetNewValue() ? args
->GetNewValue()->AsString () : NULL
;
209 Surface
*surface
= GetSurface ();
211 if (surface
&& AllowDownloads ()) {
214 if ((dl
= surface
->CreateDownloader ())) {
215 dl
->Open ("GET", uri
, GetDownloaderPolicy (uri
));
219 // we're shutting down
222 SetSource (NULL
, NULL
);
225 source_changed
= true;
229 if (args
->GetProperty ()->GetOwnerType() != Type::MEDIABASE
) {
230 FrameworkElement::OnPropertyChanged (args
, error
);
234 NotifyListenersOfPropertyChange (args
, error
);
242 SetObjectType (Type::IMAGE
);
247 BitmapSource
*source
= (BitmapSource
*)GetSource ();
250 source
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
254 Image::download_progress (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
256 Image
*media
= (Image
*) closure
;
258 media
->DownloadProgress ();
262 Image::image_opened (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
264 Image
*media
= (Image
*) closure
;
266 media
->ImageOpened ();
270 Image::image_failed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
272 Image
*media
= (Image
*) closure
;
274 media
->ImageFailed ((ImageErrorEventArgs
*)calldata
);
278 Image::source_pixel_data_changed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
280 Image
*media
= (Image
*) closure
;
282 media
->SourcePixelDataChanged ();
286 Image::DownloadProgress ()
288 BitmapImage
*source
= (BitmapImage
*) GetSource ();
290 SetDownloadProgress (source
->GetProgress ());
291 Emit (DownloadProgressChangedEvent
);
295 Image::ImageOpened ()
297 BitmapSource
*source
= (BitmapSource
*)GetSource ();
299 if (source
->Is (Type::BITMAPIMAGE
)) {
300 source
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
301 source
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
302 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
305 InvalidateArrange ();
306 InvalidateMeasure ();
312 Image::ImageFailed (ImageErrorEventArgs
*args
)
314 BitmapSource
*source
= (BitmapSource
*) GetSource ();
316 if (source
->Is (Type::BITMAPIMAGE
)) {
317 source
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
318 source
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
319 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
321 source
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
323 InvalidateArrange ();
324 InvalidateMeasure ();
328 args
->ref (); // to counter the unref in Emit
329 Emit (ImageFailedEvent
, args
);
333 Image::SourcePixelDataChanged ()
339 Image::SetSourceInternal (Downloader
*downloader
, char *PartName
)
341 BitmapImage
*source
= (BitmapImage
*) GetSource ();
343 MediaBase::SetSourceInternal (downloader
, PartName
);
345 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
346 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
347 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
349 source
->SetDownloader (downloader
, NULL
, PartName
);
353 Image::SetSource (Downloader
*downloader
, const char *PartName
)
355 MediaBase::SetSource (downloader
, PartName
);
359 Image::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
361 ImageSource
*source
= GetSource ();
362 cairo_surface_t
*cairo_surface
;
363 cairo_pattern_t
*pattern
;
364 cairo_matrix_t matrix
;
373 cairo_surface
= source
->GetSurface (cr
);
375 if (GetActualWidth () == 0.0 && GetActualHeight () == 0.0)
377 if (source
->GetPixelWidth () == 0.0 && source
->GetPixelWidth () == 0.0)
382 image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
383 Size
specified (GetActualWidth (), GetActualHeight ());
385 if (GetStretch () != StretchNone
)
386 specified
= ApplySizeConstraints (specified
);
388 paint
= Rect (0, 0, specified
.width
, specified
.height
);
389 pattern
= cairo_pattern_create_for_surface (cairo_surface
);
391 image_brush_compute_pattern_matrix (&matrix
, paint
.width
, paint
.height
, image
.width
, image
.height
, GetStretch (),
392 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
394 cairo_pattern_set_matrix (pattern
, &matrix
);
395 cairo_set_source (cr
, pattern
);
397 cairo_set_matrix (cr
, &absolute_xform
);
400 RenderLayoutClip (cr
);
406 cairo_pattern_destroy (pattern
);
412 Image::ComputeActualSize ()
414 Size result
= MediaBase::ComputeActualSize ();
415 Size specified
= Size (GetWidth (), GetHeight ());
417 if (GetSource () && GetSource ()->GetSurface (NULL
)) {
418 Size available
= Size (INFINITY
, INFINITY
);
419 available
= available
.Min (specified
);
420 result
= MeasureOverride (available
);
428 Image::MeasureOverride (Size availableSize
)
430 Size desired
= availableSize
;
431 Rect shape_bounds
= Rect ();
432 ImageSource
*source
= GetSource ();
437 shape_bounds
= Rect (0,0,source
->GetPixelWidth (),source
->GetPixelHeight ());
439 if (GetStretch () == StretchNone
)
440 return desired
.Min (shape_bounds
.width
, shape_bounds
.height
);
442 /* don't stretch to infinite size */
443 if (isinf (desired
.width
))
444 desired
.width
= shape_bounds
.width
;
445 if (isinf (desired
.height
))
446 desired
.height
= shape_bounds
.height
;
448 /* compute the scaling */
449 if (shape_bounds
.width
> 0)
450 sx
= desired
.width
/ shape_bounds
.width
;
451 if (shape_bounds
.height
> 0)
452 sy
= desired
.height
/ shape_bounds
.height
;
454 switch (GetStretch ()) {
456 sx
= sy
= MIN (sx
, sy
);
458 case StretchUniformToFill
:
459 sx
= sy
= MAX (sx
, sy
);
465 desired
= desired
.Min (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
471 Image::ArrangeOverride (Size finalSize
)
473 Size arranged
= finalSize
;
474 Rect shape_bounds
= Rect ();
475 ImageSource
*source
= GetSource ();
481 shape_bounds
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
483 if (GetStretch () == StretchNone
) {
484 arranged
= Size (shape_bounds
.x
+ shape_bounds
.width
,
485 shape_bounds
.y
+ shape_bounds
.height
);
487 arranged
= arranged
.Max (finalSize
);
492 /* compute the scaling */
493 if (shape_bounds
.width
== 0)
494 shape_bounds
.width
= arranged
.width
;
495 if (shape_bounds
.height
== 0)
496 shape_bounds
.height
= arranged
.height
;
498 if (shape_bounds
.width
!= arranged
.width
)
499 sx
= arranged
.width
/ shape_bounds
.width
;
500 if (shape_bounds
.height
!= arranged
.height
)
501 sy
= arranged
.height
/ shape_bounds
.height
;
503 switch (GetStretch ()) {
505 sx
= sy
= MIN (sx
, sy
);
507 case StretchUniformToFill
:
508 sx
= sy
= MAX (sx
, sy
);
514 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
520 Image::GetCoverageBounds ()
522 Stretch stretch
= GetStretch ();
523 ImageSource
*source
= GetSource ();
525 if (!source
|| source
->GetPixelFormat () == PixelFormatPbgra32
)
528 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
531 cairo_matrix_t matrix
;
532 Rect image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
533 Rect paint
= Rect (0, 0, GetActualWidth (), GetActualHeight ());
535 image_brush_compute_pattern_matrix (&matrix
,
536 paint
.width
, paint
.height
,
537 image
.width
, image
.height
, stretch
,
538 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
540 cairo_matrix_invert (&matrix
);
541 cairo_matrix_multiply (&matrix
, &matrix
, &absolute_xform
);
543 image
= image
.Transform (&matrix
);
544 image
= image
.Intersection (bounds
);
550 Image::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
552 if (args
->GetId () == Image::SourceProperty
) {
553 ImageSource
*source
= args
->GetNewValue () ? args
->GetNewValue ()->AsImageSource () : NULL
;
554 ImageSource
*old
= args
->GetOldValue () ? args
->GetOldValue ()->AsImageSource () : NULL
;
556 if (old
&& old
->Is(Type::BITMAPSOURCE
)) {
557 old
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
559 if (source
&& source
->Is(Type::BITMAPSOURCE
)) {
560 source
->AddHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
563 if (old
&& old
->Is(Type::BITMAPIMAGE
)) {
564 old
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
565 old
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
566 old
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
568 if (source
&& source
->Is(Type::BITMAPIMAGE
)) {
569 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
570 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
571 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
573 if (((BitmapImage
*)source
)->GetPixelWidth () > 0 && ((BitmapImage
*)source
)->GetPixelHeight () > 0) {
579 if (args
->GetProperty ()->GetOwnerType() != Type::IMAGE
) {
580 MediaBase::OnPropertyChanged (args
, error
);
584 // we need to notify attachees if our DownloadProgress changed.
585 NotifyListenersOfPropertyChange (args
, error
);
589 Image::InsideObject (cairo_t
*cr
, double x
, double y
)
594 return FrameworkElement::InsideObject (cr
, x
, y
);
598 Image::CreateDefaultImageSource (DependencyObject
*instance
, DependencyProperty
*property
)
600 return Value::CreateUnrefPtr (new BitmapImage ());
604 // MediaAttributeCollection
608 MediaAttributeCollection::GetItemByName (const char *name
)
610 MediaAttribute
*attr
;
613 for (guint i
= 0; i
< array
->len
; i
++) {
614 attr
= ((Value
*) array
->pdata
[i
])->AsMediaAttribute ();
615 if (!(value
= attr
->GetName ()))
618 if (!g_ascii_strcasecmp (value
, name
))
627 // TimelineMarkerCollection
631 TimelineMarkerCollection::AddWithError (Value
*value
, MoonError
*error
)
633 TimelineMarker
*marker
, *cur
;
635 marker
= value
->AsTimelineMarker ();
637 for (guint i
= 0; i
< array
->len
; i
++) {
638 cur
= ((Value
*) array
->pdata
[i
])->AsTimelineMarker ();
639 if (cur
->GetTime () >= marker
->GetTime ()) {
640 DependencyObjectCollection::InsertWithError (i
, value
, error
);
645 return DependencyObjectCollection::InsertWithError (array
->len
, value
, error
) ? array
->len
- 1 : -1;
649 TimelineMarkerCollection::InsertWithError (int index
, Value
*value
, MoonError
*error
)
651 return AddWithError (value
, error
) != -1;
656 // MarkerReachedEventArgs
659 MarkerReachedEventArgs::MarkerReachedEventArgs (TimelineMarker
*marker
)
661 SetObjectType (Type::MARKERREACHEDEVENTARGS
);
662 this->marker
= marker
;
666 MarkerReachedEventArgs::~MarkerReachedEventArgs ()