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
);
378 bool adjust
= specified
!= GetRenderSize ();
380 if (GetStretch () != StretchUniformToFill
)
381 specified
= specified
.Min (stretched
);
383 Rect paint
= Rect (0, 0, specified
.width
, specified
.height
);
386 Rect image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
388 if (GetStretch () == StretchNone
)
389 paint
= paint
.Union (image
);
391 if (image
.width
== 0.0 && image
.height
== 0.0)
394 pattern
= cairo_pattern_create_for_surface (source
->GetSurface (cr
));
395 image_brush_compute_pattern_matrix (&matrix
, paint
.width
, paint
.height
,
396 image
.width
, image
.height
,
398 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
400 cairo_pattern_set_matrix (pattern
, &matrix
);
401 cairo_pattern_set_extend (pattern
, CAIRO_EXTEND_PAD
);
402 if (cairo_pattern_status (pattern
) == CAIRO_STATUS_SUCCESS
) {
403 cairo_set_source (cr
, pattern
);
405 cairo_pattern_destroy (pattern
);
409 specified
= MeasureOverride (specified
);
410 paint
= Rect ((stretched
.width
- specified
.width
) * 0.5, (stretched
.height
- specified
.height
) * 0.5, specified
.width
, specified
.height
);
414 RenderLayoutClip (cr
);
416 paint
= paint
.Intersection (Rect (0, 0, stretched
.width
, stretched
.height
));
428 Image::ComputeActualSize ()
430 Size result
= MediaBase::ComputeActualSize ();
431 UIElement
*parent
= GetVisualParent ();
432 ImageSource
*source
= GetSource ();
434 if (parent
&& !parent
->Is (Type::CANVAS
))
435 if (LayoutInformation::GetLayoutSlot (this))
438 if (source
&& source
->GetSurface (NULL
)) {
439 Size available
= Size (INFINITY
, INFINITY
);
440 available
= ApplySizeConstraints (available
);
441 result
= MeasureOverride (available
);
442 result
= ApplySizeConstraints (result
);
449 Image::MeasureOverride (Size availableSize
)
451 Size desired
= availableSize
;
452 Rect shape_bounds
= Rect ();
453 ImageSource
*source
= GetSource ();
458 shape_bounds
= Rect (0,0,source
->GetPixelWidth (),source
->GetPixelHeight ());
460 /* don't stretch to infinite size */
461 if (isinf (desired
.width
))
462 desired
.width
= shape_bounds
.width
;
463 if (isinf (desired
.height
))
464 desired
.height
= shape_bounds
.height
;
466 /* compute the scaling */
467 if (shape_bounds
.width
> 0)
468 sx
= desired
.width
/ shape_bounds
.width
;
469 if (shape_bounds
.height
> 0)
470 sy
= desired
.height
/ shape_bounds
.height
;
472 /* don't use infinite dimensions as constraints */
473 if (isinf (availableSize
.width
))
475 if (isinf (availableSize
.height
))
478 switch (GetStretch ()) {
480 sx
= sy
= MIN (sx
, sy
);
482 case StretchUniformToFill
:
483 sx
= sy
= MAX (sx
, sy
);
486 if (isinf (availableSize
.width
))
488 if (isinf (availableSize
.height
))
496 desired
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
502 Image::ArrangeOverride (Size finalSize
)
504 Size arranged
= finalSize
;
505 Rect shape_bounds
= Rect ();
506 ImageSource
*source
= GetSource ();
512 shape_bounds
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
514 /* compute the scaling */
515 if (shape_bounds
.width
== 0)
516 shape_bounds
.width
= arranged
.width
;
517 if (shape_bounds
.height
== 0)
518 shape_bounds
.height
= arranged
.height
;
520 if (shape_bounds
.width
!= arranged
.width
)
521 sx
= arranged
.width
/ shape_bounds
.width
;
522 if (shape_bounds
.height
!= arranged
.height
)
523 sy
= arranged
.height
/ shape_bounds
.height
;
525 switch (GetStretch ()) {
527 sx
= sy
= MIN (sx
, sy
);
529 case StretchUniformToFill
:
530 sx
= sy
= MAX (sx
, sy
);
538 arranged
= Size (shape_bounds
.width
* sx
, shape_bounds
.height
* sy
);
544 Image::GetCoverageBounds ()
546 Stretch stretch
= GetStretch ();
547 ImageSource
*source
= GetSource ();
549 if (!source
|| source
->GetPixelFormat () == PixelFormatPbgra32
)
552 if (stretch
== StretchFill
|| stretch
== StretchUniformToFill
)
555 cairo_matrix_t matrix
;
556 Rect image
= Rect (0, 0, source
->GetPixelWidth (), source
->GetPixelHeight ());
557 Rect paint
= Rect (0, 0, GetActualWidth (), GetActualHeight ());
559 image_brush_compute_pattern_matrix (&matrix
,
560 paint
.width
, paint
.height
,
561 image
.width
, image
.height
, stretch
,
562 AlignmentXCenter
, AlignmentYCenter
, NULL
, NULL
);
564 cairo_matrix_invert (&matrix
);
565 cairo_matrix_multiply (&matrix
, &matrix
, &absolute_xform
);
567 image
= image
.Transform (&matrix
);
568 image
= image
.Intersection (bounds
);
574 Image::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
576 if (prop
&& (prop
->GetId () == Image::SourceProperty
577 || prop
->GetId () == MediaBase::SourceProperty
)) {
578 InvalidateMeasure ();
583 MediaBase::OnSubPropertyChanged (prop
, obj
, subobj_args
);
586 Image::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
588 if (args
->GetId () == Image::SourceProperty
) {
589 ImageSource
*source
= args
->GetNewValue () ? args
->GetNewValue ()->AsImageSource () : NULL
;
590 ImageSource
*old
= args
->GetOldValue () ? args
->GetOldValue ()->AsImageSource () : NULL
;
592 if (old
&& old
->Is(Type::BITMAPSOURCE
)) {
593 old
->RemoveHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
595 if (source
&& source
->Is(Type::BITMAPSOURCE
)) {
596 source
->AddHandler (BitmapSource::PixelDataChangedEvent
, source_pixel_data_changed
, this);
599 if (old
&& old
->Is(Type::BITMAPIMAGE
)) {
600 old
->RemoveHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
601 old
->RemoveHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
602 old
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
604 if (source
&& source
->Is(Type::BITMAPIMAGE
)) {
605 BitmapImage
*bitmap
= (BitmapImage
*) source
;
606 Uri
*uri
= bitmap
->GetUriSource ();
608 source
->AddHandler (BitmapImage::DownloadProgressEvent
, download_progress
, this);
609 source
->AddHandler (BitmapImage::ImageOpenedEvent
, image_opened
, this);
610 source
->AddHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
612 if (bitmap
->GetPixelWidth () > 0 && bitmap
->GetPixelHeight () > 0) {
613 RoutedEventArgs
*args
= new RoutedEventArgs ();
618 // can uri ever be null?
619 if (IsBeingParsed () && uri
&& IsAttached ()) {
620 ImageErrorEventArgs
*args
= NULL
;
622 if (uri
->IsInvalidPath ()) {
623 args
= new ImageErrorEventArgs (MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "invalid path found in uri"));
624 } else if (!bitmap
->ValidateDownloadPolicy ()) {
625 args
= new ImageErrorEventArgs (MoonError (MoonError::ARGUMENT_OUT_OF_RANGE
, 0, "Security Policy Violation"));
629 source
->RemoveHandler (BitmapImage::ImageFailedEvent
, image_failed
, this);
630 GetDeployment ()->GetSurface ()->EmitError (args
);
634 InvalidateMeasure ();
637 if (args
->GetProperty ()->GetOwnerType() != Type::IMAGE
) {
638 MediaBase::OnPropertyChanged (args
, error
);
642 // we need to notify attachees if our DownloadProgress changed.
643 NotifyListenersOfPropertyChange (args
, error
);
647 Image::InsideObject (cairo_t
*cr
, double x
, double y
)
649 if (!FrameworkElement::InsideObject (cr
, x
, y
))
654 cairo_set_matrix (cr
, &absolute_xform
);
659 TransformPoint (&nx
, &ny
);
661 Render (cr
, NULL
, true);
662 bool inside
= cairo_in_fill (cr
, nx
, ny
);
666 inside
= InsideLayoutClip (x
, y
);
669 inside
= InsideClip (cr
, x
, y
);
675 Image::CreateDefaultImageSource (DependencyObject
*instance
, DependencyProperty
*property
)
677 return Value::CreateUnrefPtr (new BitmapImage ());
681 // MediaAttributeCollection
685 MediaAttributeCollection::GetItemByName (const char *name
)
687 MediaAttribute
*attr
;
690 for (guint i
= 0; i
< array
->len
; i
++) {
691 attr
= ((Value
*) array
->pdata
[i
])->AsMediaAttribute ();
692 if (!(value
= attr
->GetName ()))
695 if (!g_ascii_strcasecmp (value
, name
))
704 // TimelineMarkerCollection
708 TimelineMarkerCollection::AddWithError (Value
*value
, MoonError
*error
)
710 TimelineMarker
*marker
, *cur
;
712 marker
= value
->AsTimelineMarker ();
714 for (guint i
= 0; i
< array
->len
; i
++) {
715 cur
= ((Value
*) array
->pdata
[i
])->AsTimelineMarker ();
716 if (cur
->GetTime () >= marker
->GetTime ()) {
717 DependencyObjectCollection::InsertWithError (i
, value
, error
);
722 return DependencyObjectCollection::InsertWithError (array
->len
, value
, error
) ? array
->len
- 1 : -1;
726 TimelineMarkerCollection::InsertWithError (int index
, Value
*value
, MoonError
*error
)
728 return AddWithError (value
, error
) != -1;