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"
32 #include "deployment.h"
38 MediaBase::MediaBase ()
40 SetObjectType (Type::MEDIABASE
);
42 source
.downloader
= NULL
;
43 source
.part_name
= NULL
;
44 source
.queued
= false;
47 allow_downloads
= false;
48 source_changed
= false;
51 MediaBase::~MediaBase ()
57 MediaBase::downloader_complete (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
59 MediaBase
*media
= (MediaBase
*) closure
;
61 media
->DownloaderComplete ();
65 MediaBase::downloader_failed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
67 MediaBase
*media
= (MediaBase
*) closure
;
69 media
->DownloaderFailed (calldata
);
73 MediaBase::DownloaderComplete ()
75 // Nothing for MediaBase to do...
79 MediaBase::DownloaderFailed (EventArgs
*args
)
81 // Nothing for MediaBase to do...
85 MediaBase::DownloaderAbort ()
88 downloader
->RemoveHandler (Downloader::DownloadFailedEvent
, downloader_failed
, this);
89 downloader
->RemoveHandler (Downloader::CompletedEvent
, downloader_complete
, this);
90 downloader
->SetStreamFunctions (NULL
, NULL
, NULL
);
100 MediaBase::SetAllowDownloads (bool allow
)
105 if ((allow_downloads
&& allow
) || (!allow_downloads
&& !allow
))
108 if (allow
&& IsAttached () && source_changed
) {
109 source_changed
= false;
111 if ((uri
= GetSource ()) && *uri
) {
112 if (!(dl
= GetDeployment ()->GetSurface ()->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
;
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
;
210 if (IsAttached () && AllowDownloads ()) {
213 if ((dl
= GetDeployment ()->GetSurface ()->CreateDownloader ())) {
214 dl
->Open ("GET", uri
, GetDownloaderPolicy (uri
));
218 // we're shutting down
221 SetSource (NULL
, NULL
);
224 source_changed
= true;
228 if (args
->GetProperty ()->GetOwnerType() != Type::MEDIABASE
) {
229 FrameworkElement::OnPropertyChanged (args
, error
);
233 NotifyListenersOfPropertyChange (args
, error
);
241 SetObjectType (Type::IMAGE
);
246 BitmapSource
*source
= (BitmapSource
*)GetSource ();
249 source
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
253 Image::download_progress (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
255 Image
*media
= (Image
*) closure
;
257 media
->DownloadProgress ();
261 Image::image_opened (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
263 Image
*media
= (Image
*) closure
;
265 media
->ImageOpened ((RoutedEventArgs
*)calldata
);
269 Image::image_failed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
271 Image
*media
= (Image
*) closure
;
273 media
->ImageFailed ((ImageErrorEventArgs
*)calldata
);
277 Image::source_pixel_data_changed (EventObject
*sender
, EventArgs
*calldata
, gpointer closure
)
279 Image
*media
= (Image
*) closure
;
281 media
->SourcePixelDataChanged ();
285 Image::DownloadProgress ()
287 BitmapImage
*source
= (BitmapImage
*) GetSource ();
289 SetDownloadProgress (source
->GetProgress ());
290 Emit (DownloadProgressChangedEvent
);
294 Image::ImageOpened (RoutedEventArgs
*args
)
296 BitmapSource
*source
= (BitmapSource
*)GetSource ();
298 if (source
->Is (Type::BITMAPIMAGE
)) {
299 source
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
300 source
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
301 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
304 InvalidateArrange ();
305 InvalidateMeasure ();
309 args
->ref (); // to counter the unref in Emit
310 Emit (ImageOpenedEvent
, args
);
314 Image::ImageFailed (ImageErrorEventArgs
*args
)
316 BitmapSource
*source
= (BitmapSource
*) GetSource ();
318 if (source
->Is (Type::BITMAPIMAGE
)) {
319 source
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
320 source
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
321 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
323 source
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
326 InvalidateArrange ();
327 InvalidateMeasure ();
331 args
->ref (); // to counter the unref in Emit
332 Emit (ImageFailedEvent
, args
);
336 Image::SourcePixelDataChanged ()
342 Image::SetSourceInternal (Downloader
*downloader
, char *PartName
)
344 BitmapImage
*source
= (BitmapImage
*) GetSource ();
346 MediaBase::SetSourceInternal (downloader
, PartName
);
348 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
349 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
350 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
352 source
->SetDownloader (downloader
, NULL
, PartName
);
356 Image::SetSource (Downloader
*downloader
, const char *PartName
)
358 MediaBase::SetSource (downloader
, PartName
);
362 Image::Render (cairo_t
*cr
, Region
*region
, bool path_only
)
364 ImageSource
*source
= GetSource ();
365 cairo_pattern_t
*pattern
= NULL
;
366 cairo_matrix_t matrix
;
374 cairo_set_matrix (cr
, &absolute_xform
);
376 Size
specified (GetActualWidth (), GetActualHeight ());
377 Size stretched
= ApplySizeConstraints (specified
);
379 if (GetStretch () != StretchUniformToFill
)
380 specified
= specified
.Min (stretched
);
382 Rect paint
= Rect (0, 0, specified
.width
, specified
.height
);
385 Rect image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
387 if (GetStretch () == StretchNone
)
388 paint
= paint
.Union (image
);
390 if (image
.width
== 0.0 && image
.height
== 0.0)
393 pattern
= cairo_pattern_create_for_surface (source
->GetSurface (cr
));
394 image_brush_compute_pattern_matrix (&matrix
, paint
.width
, paint
.height
,
395 image
.width
, image
.height
,
397 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
399 cairo_pattern_set_matrix (pattern
, &matrix
);
400 if (cairo_pattern_status (pattern
) == CAIRO_STATUS_SUCCESS
) {
401 cairo_set_source (cr
, pattern
);
403 cairo_pattern_destroy (pattern
);
407 RenderLayoutClip (cr
);
409 paint
= paint
.Intersection (Rect (0, 0, stretched
.width
, stretched
.height
));
421 Image::ComputeActualSize ()
423 Size result
= MediaBase::ComputeActualSize ();
424 UIElement
*parent
= GetVisualParent ();
425 ImageSource
*source
= GetSource ();
427 if (parent
&& !parent
->Is (Type::CANVAS
))
428 if (LayoutInformation::GetLayoutSlot (this))
431 if (source
&& source
->GetSurface (NULL
)) {
432 Size available
= Size (INFINITY
, INFINITY
);
433 available
= ApplySizeConstraints (available
);
434 result
= MeasureOverride (available
);
435 result
= ApplySizeConstraints (result
);
442 Image::MeasureOverride (Size availableSize
)
444 Size desired
= availableSize
;
445 Rect shape_bounds
= Rect ();
446 ImageSource
*source
= GetSource ();
451 shape_bounds
= Rect (0,0,source
->GetPixelWidth (),source
->GetPixelHeight ());
453 /* don't stretch to infinite size */
454 if (isinf (desired
.width
))
455 desired
.width
= shape_bounds
.width
;
456 if (isinf (desired
.height
))
457 desired
.height
= shape_bounds
.height
;
459 /* compute the scaling */
460 if (shape_bounds
.width
> 0)
461 sx
= desired
.width
/ shape_bounds
.width
;
462 if (shape_bounds
.height
> 0)
463 sy
= desired
.height
/ shape_bounds
.height
;
465 /* don't use infinite dimensions as constraints */
466 if (isinf (availableSize
.width
))
468 if (isinf (availableSize
.height
))
471 switch (GetStretch ()) {
473 sx
= sy
= MIN (sx
, sy
);
475 case StretchUniformToFill
:
476 sx
= sy
= MAX (sx
, sy
);
479 if (isinf (availableSize
.width
))
481 if (isinf (availableSize
.height
))
489 desired
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
495 Image::ArrangeOverride (Size finalSize
)
497 Size arranged
= finalSize
;
498 Rect shape_bounds
= Rect ();
499 ImageSource
*source
= GetSource ();
505 shape_bounds
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
507 /* compute the scaling */
508 if (shape_bounds
.width
== 0)
509 shape_bounds
.width
= arranged
.width
;
510 if (shape_bounds
.height
== 0)
511 shape_bounds
.height
= arranged
.height
;
513 if (shape_bounds
.width
!= arranged
.width
)
514 sx
= arranged
.width
/ shape_bounds
.width
;
515 if (shape_bounds
.height
!= arranged
.height
)
516 sy
= arranged
.height
/ shape_bounds
.height
;
518 switch (GetStretch ()) {
520 sx
= sy
= MIN (sx
, sy
);
522 case StretchUniformToFill
:
523 sx
= sy
= MAX (sx
, sy
);
531 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
537 Image::GetCoverageBounds ()
539 Stretch stretch
= GetStretch ();
540 ImageSource
*source
= GetSource ();
542 if (!source
|| source
->GetPixelFormat () == PixelFormatPbgra32
)
545 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
548 cairo_matrix_t matrix
;
549 Rect image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
550 Rect paint
= Rect (0, 0, GetActualWidth (), GetActualHeight ());
552 image_brush_compute_pattern_matrix (&matrix
,
553 paint
.width
, paint
.height
,
554 image
.width
, image
.height
, stretch
,
555 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
557 cairo_matrix_invert (&matrix
);
558 cairo_matrix_multiply (&matrix
, &matrix
, &absolute_xform
);
560 image
= image
.Transform (&matrix
);
561 image
= image
.Intersection (bounds
);
567 Image::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
569 if (prop
&& (prop
->GetId () == Image::SourceProperty
570 || prop
->GetId () == MediaBase::SourceProperty
)) {
571 InvalidateMeasure ();
576 MediaBase::OnSubPropertyChanged (prop
, obj
, subobj_args
);
579 Image::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
581 if (args
->GetId () == Image::SourceProperty
) {
582 ImageSource
*source
= args
->GetNewValue () ? args
->GetNewValue ()->AsImageSource () : NULL
;
583 ImageSource
*old
= args
->GetOldValue () ? args
->GetOldValue ()->AsImageSource () : NULL
;
585 if (old
&& old
->Is(Type::BITMAPSOURCE
)) {
586 old
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
588 if (source
&& source
->Is(Type::BITMAPSOURCE
)) {
589 source
->AddHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
592 if (old
&& old
->Is(Type::BITMAPIMAGE
)) {
593 old
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
594 old
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
595 old
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
597 if (source
&& source
->Is(Type::BITMAPIMAGE
)) {
598 BitmapImage
*bitmap
= (BitmapImage
*) source
;
599 Uri
*uri
= bitmap
->GetUriSource ();
601 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
602 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
603 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
605 if (bitmap
->GetPixelWidth () > 0 && bitmap
->GetPixelHeight () > 0) {
606 RoutedEventArgs
*args
= new RoutedEventArgs ();
611 // can uri ever be null?
612 if (IsBeingParsed () && uri
&& IsAttached ()) {
613 ImageErrorEventArgs
*args
= NULL
;
615 if (uri
->IsInvalidPath ()) {
616 args
= new ImageErrorEventArgs (MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "invalid path found in uri"));
617 } else if (!bitmap
->ValidateDownloadPolicy ()) {
618 args
= new ImageErrorEventArgs (MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "Security Policy Violation"));
622 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
623 GetDeployment ()->GetSurface ()->EmitError (args
);
627 InvalidateMeasure ();
630 if (args
->GetProperty ()->GetOwnerType() != Type::IMAGE
) {
631 MediaBase::OnPropertyChanged (args
, error
);
635 // we need to notify attachees if our DownloadProgress changed.
636 NotifyListenersOfPropertyChange (args
, error
);
640 Image::InsideObject (cairo_t
*cr
, double x
, double y
)
642 if (!FrameworkElement::InsideObject (cr
, x
, y
))
647 cairo_set_matrix (cr
, &absolute_xform
);
652 TransformPoint (&nx
, &ny
);
654 Render (cr
, NULL
, true);
655 bool inside
= cairo_in_fill (cr
, nx
, ny
);
659 inside
= InsideLayoutClip (x
, y
);
662 inside
= InsideClip (cr
, x
, y
);
668 Image::CreateDefaultImageSource (DependencyObject
*instance
, DependencyProperty
*property
)
670 return Value::CreateUnrefPtr (new BitmapImage ());
674 // MediaAttributeCollection
678 MediaAttributeCollection::GetItemByName (const char *name
)
680 MediaAttribute
*attr
;
683 for (guint i
= 0; i
< array
->len
; i
++) {
684 attr
= ((Value
*) array
->pdata
[i
])->AsMediaAttribute ();
685 if (!(value
= attr
->GetName ()))
688 if (!g_ascii_strcasecmp (value
, name
))
697 // TimelineMarkerCollection
701 TimelineMarkerCollection::AddWithError (Value
*value
, MoonError
*error
)
703 TimelineMarker
*marker
, *cur
;
705 marker
= value
->AsTimelineMarker ();
707 for (guint i
= 0; i
< array
->len
; i
++) {
708 cur
= ((Value
*) array
->pdata
[i
])->AsTimelineMarker ();
709 if (cur
->GetTime () >= marker
->GetTime ()) {
710 DependencyObjectCollection::InsertWithError (i
, value
, error
);
715 return DependencyObjectCollection::InsertWithError (array
->len
, value
, error
) ? array
->len
- 1 : -1;
719 TimelineMarkerCollection::InsertWithError (int index
, Value
*value
, MoonError
*error
)
721 return AddWithError (value
, error
) != -1;