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);
324 InvalidateArrange ();
325 InvalidateMeasure ();
329 args
->ref (); // to counter the unref in Emit
330 Emit (ImageFailedEvent
, args
);
334 Image::SourcePixelDataChanged ()
340 Image::SetSourceInternal (Downloader
*downloader
, char *PartName
)
342 BitmapImage
*source
= (BitmapImage
*) GetSource ();
344 MediaBase::SetSourceInternal (downloader
, PartName
);
346 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
347 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
348 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
350 source
->SetDownloader (downloader
, NULL
, PartName
);
354 Image::SetSource (Downloader
*downloader
, const char *PartName
)
356 MediaBase::SetSource (downloader
, PartName
);
360 Image::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
362 ImageSource
*source
= GetSource ();
363 cairo_pattern_t
*pattern
= NULL
;
364 cairo_matrix_t matrix
;
375 Size
specified (GetActualWidth (), GetActualHeight ());
376 Size stretched
= ApplySizeConstraints (specified
);
378 if (GetStretch () != StretchUniformToFill
)
379 specified
= specified
.Min(stretched
);
381 paint
= Rect (0, 0, specified
.width
, specified
.height
);
384 image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
386 if (GetStretch () == StretchNone
)
387 paint
= paint
.Union (image
);
389 if (image
.width
== 0.0 && image
.height
== 0.0)
392 pattern
= cairo_pattern_create_for_surface (source
->GetSurface (cr
));
393 image_brush_compute_pattern_matrix (&matrix
, paint
.width
, paint
.height
,
394 image
.width
, image
.height
,
396 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
398 cairo_pattern_set_matrix (pattern
, &matrix
);
399 cairo_set_source (cr
, pattern
);
402 cairo_set_matrix (cr
, &absolute_xform
);
405 RenderLayoutClip (cr
);
407 paint
= paint
.Intersection (Rect (0,0,stretched
.width
,stretched
.height
));
416 cairo_pattern_destroy (pattern
);
422 Image::ComputeActualSize ()
424 Size result
= MediaBase::ComputeActualSize ();
425 UIElement
*parent
= GetVisualParent ();
426 ImageSource
*source
= GetSource ();
428 if (parent
&& !parent
->Is (Type::CANVAS
))
429 if (LayoutInformation::GetLayoutSlot (this))
432 if (source
&& source
->GetSurface (NULL
)) {
433 Size available
= Size (INFINITY
, INFINITY
);
434 available
= ApplySizeConstraints (available
);
435 result
= MeasureOverride (available
);
436 result
= ApplySizeConstraints (result
);
443 Image::MeasureOverride (Size availableSize
)
445 Size desired
= availableSize
;
446 Rect shape_bounds
= Rect ();
447 ImageSource
*source
= GetSource ();
452 shape_bounds
= Rect (0,0,source
->GetPixelWidth (),source
->GetPixelHeight ());
454 /* don't stretch to infinite size */
455 if (isinf (desired
.width
))
456 desired
.width
= shape_bounds
.width
;
457 if (isinf (desired
.height
))
458 desired
.height
= shape_bounds
.height
;
460 /* compute the scaling */
461 if (shape_bounds
.width
> 0)
462 sx
= desired
.width
/ shape_bounds
.width
;
463 if (shape_bounds
.height
> 0)
464 sy
= desired
.height
/ shape_bounds
.height
;
466 /* don't use infinite dimensions as constraints */
467 if (isinf (availableSize
.width
))
469 if (isinf (availableSize
.height
))
472 switch (GetStretch ()) {
474 sx
= sy
= MIN (sx
, sy
);
476 case StretchUniformToFill
:
477 sx
= sy
= MAX (sx
, sy
);
480 if (isinf (availableSize
.width
))
482 if (isinf (availableSize
.height
))
490 desired
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
496 Image::ArrangeOverride (Size finalSize
)
498 Size arranged
= finalSize
;
499 Rect shape_bounds
= Rect ();
500 ImageSource
*source
= GetSource ();
506 shape_bounds
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
508 /* compute the scaling */
509 if (shape_bounds
.width
== 0)
510 shape_bounds
.width
= arranged
.width
;
511 if (shape_bounds
.height
== 0)
512 shape_bounds
.height
= arranged
.height
;
514 if (shape_bounds
.width
!= arranged
.width
)
515 sx
= arranged
.width
/ shape_bounds
.width
;
516 if (shape_bounds
.height
!= arranged
.height
)
517 sy
= arranged
.height
/ shape_bounds
.height
;
519 switch (GetStretch ()) {
521 sx
= sy
= MIN (sx
, sy
);
523 case StretchUniformToFill
:
524 sx
= sy
= MAX (sx
, sy
);
532 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
538 Image::GetCoverageBounds ()
540 Stretch stretch
= GetStretch ();
541 ImageSource
*source
= GetSource ();
543 if (!source
|| source
->GetPixelFormat () == PixelFormatPbgra32
)
546 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
549 cairo_matrix_t matrix
;
550 Rect image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
551 Rect paint
= Rect (0, 0, GetActualWidth (), GetActualHeight ());
553 image_brush_compute_pattern_matrix (&matrix
,
554 paint
.width
, paint
.height
,
555 image
.width
, image
.height
, stretch
,
556 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
558 cairo_matrix_invert (&matrix
);
559 cairo_matrix_multiply (&matrix
, &matrix
, &absolute_xform
);
561 image
= image
.Transform (&matrix
);
562 image
= image
.Intersection (bounds
);
568 Image::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
570 if (prop
&& (prop
->GetId () == Image::SourceProperty
571 || prop
->GetId () == MediaBase::SourceProperty
)) {
572 InvalidateMeasure ();
577 MediaBase::OnSubPropertyChanged (prop
, obj
, subobj_args
);
580 Image::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
582 if (args
->GetId () == Image::SourceProperty
) {
583 ImageSource
*source
= args
->GetNewValue () ? args
->GetNewValue ()->AsImageSource () : NULL
;
584 ImageSource
*old
= args
->GetOldValue () ? args
->GetOldValue ()->AsImageSource () : NULL
;
586 if (old
&& old
->Is(Type::BITMAPSOURCE
)) {
587 old
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
589 if (source
&& source
->Is(Type::BITMAPSOURCE
)) {
590 source
->AddHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
593 if (old
&& old
->Is(Type::BITMAPIMAGE
)) {
594 old
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
595 old
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
596 old
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
598 if (source
&& source
->Is(Type::BITMAPIMAGE
)) {
599 BitmapImage
*bitmap
= (BitmapImage
*) source
;
600 Uri
*uri
= bitmap
->GetUriSource ();
602 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
603 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
604 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
606 if (bitmap
->GetPixelWidth () > 0 && bitmap
->GetPixelHeight () > 0) {
610 // can uri ever be null?
611 if (IsBeingParsed () && uri
&& GetSurface ()) {
612 ImageErrorEventArgs
*args
= NULL
;
614 if (uri
->IsInvalidPath ()) {
615 args
= new ImageErrorEventArgs (MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "invalid path found in uri"));
616 } else if (!bitmap
->ValidateDownloadPolicy ()) {
617 args
= new ImageErrorEventArgs (MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "Security Policy Violation"));
621 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
622 GetSurface ()->EmitError (args
);
626 InvalidateMeasure ();
629 if (args
->GetProperty ()->GetOwnerType() != Type::IMAGE
) {
630 MediaBase::OnPropertyChanged (args
, error
);
634 // we need to notify attachees if our DownloadProgress changed.
635 NotifyListenersOfPropertyChange (args
, error
);
639 Image::InsideObject (cairo_t
*cr
, double x
, double y
)
641 if (!FrameworkElement::InsideObject (cr
, x
, y
))
646 cairo_set_matrix (cr
, &absolute_xform
);
651 TransformPoint (&nx
, &ny
);
653 Render (cr
, NULL
, true);
654 bool inside
= cairo_in_fill (cr
, nx
, ny
);
658 inside
= InsideLayoutClip (x
, y
);
661 inside
= InsideClip (cr
, x
, y
);
667 Image::CreateDefaultImageSource (DependencyObject
*instance
, DependencyProperty
*property
)
669 return Value::CreateUnrefPtr (new BitmapImage ());
673 // MediaAttributeCollection
677 MediaAttributeCollection::GetItemByName (const char *name
)
679 MediaAttribute
*attr
;
682 for (guint i
= 0; i
< array
->len
; i
++) {
683 attr
= ((Value
*) array
->pdata
[i
])->AsMediaAttribute ();
684 if (!(value
= attr
->GetName ()))
687 if (!g_ascii_strcasecmp (value
, name
))
696 // TimelineMarkerCollection
700 TimelineMarkerCollection::AddWithError (Value
*value
, MoonError
*error
)
702 TimelineMarker
*marker
, *cur
;
704 marker
= value
->AsTimelineMarker ();
706 for (guint i
= 0; i
< array
->len
; i
++) {
707 cur
= ((Value
*) array
->pdata
[i
])->AsTimelineMarker ();
708 if (cur
->GetTime () >= marker
->GetTime ()) {
709 DependencyObjectCollection::InsertWithError (i
, value
, error
);
714 return DependencyObjectCollection::InsertWithError (array
->len
, value
, error
) ? array
->len
- 1 : -1;
718 TimelineMarkerCollection::InsertWithError (int index
, Value
*value
, MoonError
*error
)
720 return AddWithError (value
, error
) != -1;
725 // MarkerReachedEventArgs
728 MarkerReachedEventArgs::MarkerReachedEventArgs (TimelineMarker
*marker
)
730 SetObjectType (Type::MARKERREACHEDEVENTARGS
);
731 this->marker
= marker
;
735 MarkerReachedEventArgs::~MarkerReachedEventArgs ()