Author: toshok
Date: 2008-01-30 18:00:04 -0500 (Wed, 30 Jan 2008)
New Revision: 94429

Modified:
   trunk/moon/src/ChangeLog
   trunk/moon/src/control.cpp
   trunk/moon/src/control.h
   trunk/moon/src/media.cpp
   trunk/moon/src/media.h
   trunk/moon/src/mplayer.cpp
   trunk/moon/src/mplayer.h
   trunk/moon/src/panel.cpp
   trunk/moon/src/panel.h
   trunk/moon/src/rect.cpp
   trunk/moon/src/rect.h
   trunk/moon/src/runtime.cpp
   trunk/moon/src/runtime.h
   trunk/moon/src/uielement.cpp
   trunk/moon/src/uielement.h
Log:
2008-01-30  Chris Toshok  <[EMAIL PROTECTED]>

        * mplayer.h (class MediaPlayer): add rendered_frame.

        * mplayer.cpp (MediaPlayer::MediaPlayer): init rendered_frame to
        false.
        (MediaPlayer::Close): reset rendered_frame.
        (render_frame): set rendered_frame to true if we've successfully
        copied data into the video surface.

        * media.cpp (Image::CreateSurface): set CachedSurface::has_alpha
        to the pixbuf's has_alpha if USE_OPT_RGB24.

        * media.h (class Image): make the CachedSurface type and the
        instance field "surface" public, so the front to back stuff can
        get at it.  Also, add "has_alpha" to it, since once the xlib
        surface has been created, we lose that information.

        * control.cpp (Control::FrontToBack): nothing to do but call
        FrontToBack on real_object.

        * control.h (class Control): add override for FrontToBack.

        * panel.cpp (Panel::FindStartingElement): get rid of this crap.
        it was broken and the wrong way to implement it.
        (Panel::Render): remove the RenderChildren call here, we do it in
        PostRender (and only if we're not rendering front to back)
        (Panel::PostRender): if we aren't rendering front to back, call
        RenderChildren.
        (Panel::RenderChildren): remove references to FindStartingElement.
        (Panel::FrontToBack): this method is a little more complicated
        than UIElement::FrontToBack owing to the fact that we're
        flattening things to a list.  We need to prepend a "cleanup node"
        first, before calling FrontToBack on our children, to do the
        Panel::PostRender stuff after our children have been rendered.  We
        remove this cleanup node if none of the children have added
        themselves to the list, and our bounds (without the children)
        don't intersect the expose region.  We apply the same logic to
        removing our rectangular bounds as the UIElement code does, but
        also have to take into account our background brush.  We punt if
        any part of it is transparent, and only handle SolidColorBrush and
        GradientBrush subclasses.

        * panel.h (class Panel): override UIElement:: FrontToBack,
        PreRender, and PostRender.

        * uielement.cpp (UIElement::DoRender): factor out most of the
        * guts
        of this method so it can be used in either front-to-back or
        back-to-front.  Make sure to pass "false" as the front-to-back arg
        for PreRender and PostRender.
        (UIElement::FrontToBack): calculate the intersection of the expose
        region and our bounds.  Add this region to the front of the render
        list, and then do some calculating to decide if we should remove
        it from consideration by elements lower than us in the display.
        Things like "are we opaque", "have we been rotated or skewed, such
        that our rectangular shape no longer fills the bounds entirely",
        stuff like that.  We further limit subtracting in element type
        specific ways - right now just for MediaElement and Image with
        certain constraints (images can't have alpha, media elements must
        have a frame rendered, both types must fill their rectangle, etc).
        If everything passes, we remove our bounds from the expose region.
        (UIElement::PreRender): new method, do the things that DoRender
        used to do before calling Render.
        (UIElement::PostRender): new method, do the things that DoRender
        used to do after calling Render.

        * uielement.h: move the IS_TRANSLUCENT/IS_INVISIBLE #defines
        * here
        so they can be used in panel.cpp.  Also, add 3 new virtual
        methods (FrontToBack, PreRender, PostRender) as well as two
        callback methods to invoke the 2 latter ones.

        * runtime.cpp (overrides): add "render=ftb" and "render=btf"
        overrides (with btf the default) corresponding to
        RUNTIME_INIT_RENDER_FRONT_TO_BACK.
        (Surface::Paint): add support for front-to-back rendering.  If
        it's enabled, make a FrontToBack pass on the fullscreen message
        and the toplevel element.  This populates the render list with a
        back to front ordered list of elements to paint, along with the
        regions they need repainted.  If the render list is empty for some
        reason (or if the user didn't select ftb rendering), we fall back
        to back to back-to-front rendering at the toplevel.
        (RenderNode::RenderNode): add ctor/dtor for RenderNode.

        * runtime.h: add the RenderNode class, used by the front to back
        rendering.

        * rect.h, rect.cpp: add IsEmpty() and two overloads of
        * Subtract()
        to Region.



Modified: trunk/moon/src/ChangeLog
===================================================================
--- trunk/moon/src/ChangeLog    2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/ChangeLog    2008-01-30 23:00:04 UTC (rev 94429)
@@ -1,3 +1,92 @@
+2008-01-30  Chris Toshok  <[EMAIL PROTECTED]>
+
+       * mplayer.h (class MediaPlayer): add rendered_frame.
+
+       * mplayer.cpp (MediaPlayer::MediaPlayer): init rendered_frame to
+       false.
+       (MediaPlayer::Close): reset rendered_frame.
+       (render_frame): set rendered_frame to true if we've successfully
+       copied data into the video surface.
+
+       * media.cpp (Image::CreateSurface): set CachedSurface::has_alpha
+       to the pixbuf's has_alpha if USE_OPT_RGB24.
+
+       * media.h (class Image): make the CachedSurface type and the
+       instance field "surface" public, so the front to back stuff can
+       get at it.  Also, add "has_alpha" to it, since once the xlib
+       surface has been created, we lose that information.
+
+       * control.cpp (Control::FrontToBack): nothing to do but call
+       FrontToBack on real_object.
+
+       * control.h (class Control): add override for FrontToBack.
+
+       * panel.cpp (Panel::FindStartingElement): get rid of this crap.
+       it was broken and the wrong way to implement it.
+       (Panel::Render): remove the RenderChildren call here, we do it in
+       PostRender (and only if we're not rendering front to back)
+       (Panel::PostRender): if we aren't rendering front to back, call
+       RenderChildren.
+       (Panel::RenderChildren): remove references to FindStartingElement.
+       (Panel::FrontToBack): this method is a little more complicated
+       than UIElement::FrontToBack owing to the fact that we're
+       flattening things to a list.  We need to prepend a "cleanup node"
+       first, before calling FrontToBack on our children, to do the
+       Panel::PostRender stuff after our children have been rendered.  We
+       remove this cleanup node if none of the children have added
+       themselves to the list, and our bounds (without the children)
+       don't intersect the expose region.  We apply the same logic to
+       removing our rectangular bounds as the UIElement code does, but
+       also have to take into account our background brush.  We punt if
+       any part of it is transparent, and only handle SolidColorBrush and
+       GradientBrush subclasses.
+
+       * panel.h (class Panel): override UIElement:: FrontToBack,
+       PreRender, and PostRender.
+
+       * uielement.cpp (UIElement::DoRender): factor out most of the guts
+       of this method so it can be used in either front-to-back or
+       back-to-front.  Make sure to pass "false" as the front-to-back arg
+       for PreRender and PostRender.
+       (UIElement::FrontToBack): calculate the intersection of the expose
+       region and our bounds.  Add this region to the front of the render
+       list, and then do some calculating to decide if we should remove
+       it from consideration by elements lower than us in the display.
+       Things like "are we opaque", "have we been rotated or skewed, such
+       that our rectangular shape no longer fills the bounds entirely",
+       stuff like that.  We further limit subtracting in element type
+       specific ways - right now just for MediaElement and Image with
+       certain constraints (images can't have alpha, media elements must
+       have a frame rendered, both types must fill their rectangle, etc).
+       If everything passes, we remove our bounds from the expose region.
+       (UIElement::PreRender): new method, do the things that DoRender
+       used to do before calling Render.
+       (UIElement::PostRender): new method, do the things that DoRender
+       used to do after calling Render.
+
+       * uielement.h: move the IS_TRANSLUCENT/IS_INVISIBLE #defines here
+       so they can be used in panel.cpp.  Also, add 3 new virtual
+       methods (FrontToBack, PreRender, PostRender) as well as two
+       callback methods to invoke the 2 latter ones.
+
+       * runtime.cpp (overrides): add "render=ftb" and "render=btf"
+       overrides (with btf the default) corresponding to
+       RUNTIME_INIT_RENDER_FRONT_TO_BACK.
+       (Surface::Paint): add support for front-to-back rendering.  If
+       it's enabled, make a FrontToBack pass on the fullscreen message
+       and the toplevel element.  This populates the render list with a
+       back to front ordered list of elements to paint, along with the
+       regions they need repainted.  If the render list is empty for some
+       reason (or if the user didn't select ftb rendering), we fall back
+       to back to back-to-front rendering at the toplevel.
+       (RenderNode::RenderNode): add ctor/dtor for RenderNode.
+
+       * runtime.h: add the RenderNode class, used by the front to back
+       rendering.
+
+       * rect.h, rect.cpp: add IsEmpty() and two overloads of Subtract()
+       to Region.
+
 2008-01-30  Jackson Harper  <[EMAIL PROTECTED]>
 
        * xaml.cpp: Strip leading whitespace from xaml files.

Modified: trunk/moon/src/control.cpp
===================================================================
--- trunk/moon/src/control.cpp  2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/control.cpp  2008-01-30 23:00:04 UTC (rev 94429)
@@ -30,6 +30,13 @@
                real_object->DoRender (cr, region);
 }
 
+void
+Control::FrontToBack (Region *surface_region, List *render_list)
+{
+       if (real_object)
+               return real_object->FrontToBack (surface_region, render_list);
+}
+
 void 
 Control::ComputeBounds ()
 {

Modified: trunk/moon/src/control.h
===================================================================
--- trunk/moon/src/control.h    2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/control.h    2008-01-30 23:00:04 UTC (rev 94429)
@@ -26,6 +26,7 @@
        virtual Type::Kind GetObjectType () { return Type::CONTROL; }
 
        virtual void Render (cairo_t *cr, Region *region);
+       virtual void FrontToBack (Region *surface_region, List *render_list);
        virtual void ComputeBounds ();
        virtual Rect GetSubtreeBounds () { return bounds_with_children; }
        virtual void GetTransformFor (UIElement *item, cairo_matrix_t *result);

Modified: trunk/moon/src/media.cpp
===================================================================
--- trunk/moon/src/media.cpp    2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/media.cpp    2008-01-30 23:00:04 UTC (rev 94429)
@@ -638,7 +638,7 @@
                h = (double) mplayer->height;
                w = (double) mplayer->width;
        }
-       
+
        cairo_save (cr);
        if (!EnableAntiAlias ())
                cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
@@ -1778,6 +1778,9 @@
                                                                      
surface->height,
                                                                      
gdk_pixbuf_get_rowstride (pixbuf));
 
+#if USE_OPT_RGB24
+               surface->has_alpha = has_alpha;
+#endif
                g_hash_table_insert (surface_cache, surface->fname, surface);
        }
 

Modified: trunk/moon/src/media.h
===================================================================
--- trunk/moon/src/media.h      2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/media.h      2008-01-30 23:00:04 UTC (rev 94429)
@@ -82,19 +82,6 @@
        
        Downloader *downloader;
        
-       struct CachedSurface {
-               int ref_cnt;
-               
-               char *fname;
-               cairo_surface_t *cairo;
-               bool xlib_surface_created;
-               GdkPixbuf *backing_pixbuf;
-               
-               int width;
-               int height;
-       };
-       
-       CachedSurface *surface;
        char *part_name;
        
        // pattern caching
@@ -122,7 +109,23 @@
        virtual bool InsideObject (cairo_t *cr, double x, double y);
        
        ImageBrush *brush;
+
+       struct CachedSurface {
+               int ref_cnt;
+               
+               char *fname;
+               cairo_surface_t *cairo;
+               bool xlib_surface_created;
+               GdkPixbuf *backing_pixbuf;
+               
+               bool has_alpha;
+               int width;
+               int height;
+       };
        
+
+       CachedSurface *surface;
+       
        static GHashTable *surface_cache;
        
        static int ImageFailedEvent;

Modified: trunk/moon/src/mplayer.cpp
===================================================================
--- trunk/moon/src/mplayer.cpp  2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/mplayer.cpp  2008-01-30 23:00:04 UTC (rev 94429)
@@ -180,6 +180,7 @@
        stop = false;
        eof = false;
        seeking = false;
+       rendered_frame = false;
        
        audio_thread = NULL;
        
@@ -414,6 +415,8 @@
        
        height = 0;
        width = 0;
+
+       rendered_frame = false;
 }
 
 //
@@ -430,6 +433,7 @@
        if (!frame->IsPlanar ()) {
                // Just copy the data
                memcpy (video->rgb_buffer, frame->buffer, MIN (frame->buflen, 
(uint32_t) (mplayer->width * mplayer->height * 4)));
+               mplayer->rendered_frame = true;
                return;
        }
        
@@ -444,6 +448,7 @@
        
        stream->converter->Convert (frame->data_stride, frame->srcStride, 
frame->srcSlideY,
                                    frame->srcSlideH, rgb_dest, rgb_stride);
+       mplayer->rendered_frame = true;
 }
 
 bool

Modified: trunk/moon/src/mplayer.h
===================================================================
--- trunk/moon/src/mplayer.h    2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/mplayer.h    2008-01-30 23:00:04 UTC (rev 94429)
@@ -39,6 +39,8 @@
        Audio *audio;
        Video *video;
        
+       bool rendered_frame;
+
        // sync
        uint64_t start_time;  
        

Modified: trunk/moon/src/panel.cpp
===================================================================
--- trunk/moon/src/panel.cpp    2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/panel.cpp    2008-01-30 23:00:04 UTC (rev 94429)
@@ -142,85 +142,7 @@
 static int level = 0;
 
 //#define DEBUG_INVALIDATE 1
-//#define USE_STARTING_ELEMENT 1
 
-
-
-int
-Panel::FindStartingElement (Region *region)
-{
-#if USE_STARTING_ELEMENT
-       VisualCollection *children = GetChildren ();
-       Rect clip = region->ClipBox ().RoundOut ();
-       
-       gint i = children->z_sorted->len;
-       if (i < 2)
-               return -1;
-
-       if (!clip.IntersectsWith (GetBounds().RoundOut())
-           || !GetRenderVisible () 
-           || GetValue (UIElement::ClipProperty) != NULL
-           || uielement_get_opacity_mask (this) != NULL
-           )
-               return -1;
-
-       for (i --; i >= 0; i --) {
-               UIElement *item = (UIElement *) children->z_sorted->pdata[i];
-               // if the exposed rectangle is completely within the bounds
-               // of a child that has opacity == 1.0 and lacks an opacity
-               // mask, we start rendering from there.
-               if (item->GetRenderVisible ()
-                   && item->GetValue (UIElement::ClipProperty) == NULL
-                   && (item->absolute_xform.yx == 0 && item->absolute_xform.xy 
== 0) /* no skew */
-                   && uielement_get_opacity_mask (item) == NULL
-                   && clip.IntersectsWith (item->GetBounds ().RoundOut ())
-                   && region->RectIn (item->GetBounds().RoundOut()) == 
GDK_OVERLAP_RECTANGLE_IN
-                   ) {
-                       // there are actually some more type
-                       // specific checks required.  we need
-                       // to fulsrther limit it to elements
-                       // which are truly rectangular to
-                       // begin with (images, panels,
-                       // mediaelements), and which aren't
-                       // rotated/skewed.  also, make sure
-                       // panel backgrounds are
-                       // non-translucent.
-                       Type::Kind type = item->GetObjectType();
-
-                       if (type == Type::PANEL || type == Type::CANVAS || type 
== Type::INKPRESENTER) {
-                               bool panel_works = false;
-#if 1
-                               Brush *bg = panel_get_background ((Panel*)item);
-                               if (bg && bg->GetObjectType() == 
Type::SOLIDCOLORBRUSH) {
-                                       Color *c = solid_color_brush_get_color 
((SolidColorBrush*)bg);
-                                       if (c && c->a == 1.0) {
-                                               /* we're good */
-                                               panel_works = true;
-                                       }
-                               }
-#endif
-
-                               if (!panel_works) {
-                                       /* look one level down and see if
-                                       ** there's a child of this the child
-                                       ** panel that completely encompasses
-                                       ** the rectangle.
-                                       */
-                                       if (-1 == 
((Panel*)item)->FindStartingElement (region))
-                                               continue;
-                               }
-                       }
-                       else if (type != Type::MEDIAELEMENT) {
-                               continue;
-                       }
-                       return i;
-               }
-       }
-#endif
-
-       return -1;
-}
-
 void
 Panel::UpdateTotalRenderVisibility ()
 {
@@ -242,10 +164,15 @@
        FrameworkElement::UpdateTotalHitTestVisibility ();
 }
 
+static bool
+use_front_to_back (Panel *panel)
+{
+       return panel->GetChildren ()->list->Length() < 25;
+}
+
 void
 Panel::Render (cairo_t *cr, Region *region)
 {
-       cairo_save (cr);
        cairo_set_matrix (cr, &absolute_xform);
 
        Value *value = GetValue (Panel::BackgroundProperty);
@@ -263,11 +190,20 @@
                        cairo_fill (cr);
                }
        }
+}
 
-       RenderChildren (cr, region);
-       cairo_restore (cr);
+void
+Panel::PostRender (cairo_t *cr, Region *region, bool front_to_back)
+{
+       // if we didn't render front to back, then render the children here
+       if (!front_to_back || !use_front_to_back (this)) {
+               RenderChildren (cr, region);
+       }
+
+       UIElement::PostRender (cr, region, front_to_back);
 }
 
+
 void
 Panel::RenderChildren (cairo_t *cr, Region *parent_region)
 {
@@ -275,15 +211,9 @@
 
        Region *clipped_region = new Region (bounds_with_children);
        clipped_region->Intersect (parent_region);
-       gint start_element = FindStartingElement (clipped_region);
-       
-       if (start_element <= 0)
-               start_element = 0;
-       else
-               printf ("start_element = %d\n", start_element);
 
        cairo_identity_matrix (cr);
-       for (guint i = start_element; i < children->z_sorted->len; i++) {
+       for (guint i = 0; i < children->z_sorted->len; i++) {
                UIElement *item = (UIElement *) children->z_sorted->pdata[i];
                
                Region *region = new Region (item->GetSubtreeBounds());
@@ -338,6 +268,108 @@
        delete clipped_region;
 }
 
+void
+Panel::FrontToBack (Region *surface_region, List *render_list)
+{
+       double local_opacity = GetValue (OpacityProperty)->AsDouble();
+
+       if (surface_region->RectIn (bounds_with_children.RoundOut()) == 
GDK_OVERLAP_RECTANGLE_OUT)
+               return;
+
+       if (!GetRenderVisible ()
+           || IS_INVISIBLE (local_opacity))
+               return;
+
+       if (!use_front_to_back (this)) {
+               Region *self_region = new Region (surface_region->gdkregion);
+               self_region->Intersect (bounds_with_children.RoundOut());
+               // we need to include our children in this one, since
+               // we'll be rendering them in the PostRender method.
+               if (!self_region->IsEmpty())
+                       render_list->Prepend (new RenderNode (this, 
self_region, !self_region->IsEmpty(),
+                                                             
UIElement::CallPreRender, UIElement::CallPostRender));
+               // don't remove the region from surface_region because
+               // there are likely holes in it
+               return;
+       }
+
+       RenderNode *panel_cleanup_node = new RenderNode (this, NULL, false, 
NULL, UIElement::CallPostRender);
+       
+       render_list->Prepend (panel_cleanup_node);
+
+       VisualCollection *children = GetChildren ();
+       for (guint i = children->z_sorted->len; i > 0; i--) {
+               UIElement *item = (UIElement *) children->z_sorted->pdata[i - 
1];
+
+               item->FrontToBack (surface_region, render_list);
+       }
+
+       Region *self_region = new Region (surface_region->gdkregion);
+       self_region->Intersect (bounds.RoundOut ()); // note the RoundOut
+
+       if (self_region->IsEmpty() && render_list->First() == 
panel_cleanup_node) {
+               /* we don't intersect the surface region, and none of
+                  our children did either, remove the cleanup node */
+               render_list->Remove (render_list->First());
+               delete self_region;
+               return;
+       }
+
+       render_list->Prepend (new RenderNode (this, self_region, 
!self_region->IsEmpty(), UIElement::CallPreRender, NULL));
+
+       if (!self_region->IsEmpty()) {
+
+               bool subtract = (GetValue (UIElement::ClipProperty) == NULL
+                                && (absolute_xform.yx == 0 && 
absolute_xform.xy == 0) /* no skew */
+                                && uielement_get_opacity_mask (this) == NULL
+                                && !IS_TRANSLUCENT (local_opacity));
+
+               if (subtract) {
+                       Value *brush_value = GetValue 
(Panel::BackgroundProperty);
+                       if (brush_value
+                           && brush_value->AsBrush()) {
+
+                               double background_alpha = 0.0;
+                               Brush *brush = brush_value->AsBrush();
+
+                               if (brush->Is(Type::SOLIDCOLORBRUSH)) {
+
+                                       SolidColorBrush *scb = 
(SolidColorBrush*)brush;
+                                       Color *c = scb->GetColor();
+                                       background_alpha = c->a;
+                               }
+                               else if (brush->Is(Type::GRADIENTBRUSH)) {
+                                       GradientStopCollection *stops = 
gradient_brush_get_gradient_stops ((GradientBrush*)brush);
+
+                                       if (stops->list->Length() > 0) {
+                                               background_alpha = 1.0;
+
+                                               Collection::Node *cn;
+                                               for (cn = (Collection::Node *) 
children->list->First ();
+                                                    cn != NULL;
+                                                    cn = (Collection::Node *) 
cn->next) {
+
+                                                       GradientStop *stop = 
(GradientStop*)cn->obj;
+                                                       Color* c = 
gradient_stop_get_color (stop);
+                                                       if (c->a < 
background_alpha)
+                                                               
background_alpha = c->a;
+                                               }
+                                       }
+                               }
+
+                               subtract = !IS_TRANSLUCENT (background_alpha);
+                       }
+                       else {
+                               // no background defined
+                               subtract = false;
+                       }
+               }
+
+               if (subtract)
+                       surface_region->Subtract (bounds); // note the lack of 
RoundOut here.
+       }
+}
+
 bool
 Panel::InsideObject (cairo_t *cr, double x, double y)
 {

Modified: trunk/moon/src/panel.h
===================================================================
--- trunk/moon/src/panel.h      2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/panel.h      2008-01-30 23:00:04 UTC (rev 94429)
@@ -21,8 +21,6 @@
        //
        UIElement *mouse_over;
 
-       int FindStartingElement (Region *region);
-
  public:
        Panel ();
        virtual ~Panel ();
@@ -35,6 +33,9 @@
        virtual void Render (cairo_t *cr, Region *region);
        virtual void RenderChildren (cairo_t *cr, Region *region);
 
+       virtual void FrontToBack (Region *surface_region, List *render_list);
+       virtual void PostRender (cairo_t *cr, Region *region, bool 
front_to_back);
+
        bool CheckOver (cairo_t *cr, UIElement *item, double x, double y);
 
        virtual UIElement* FindMouseOver (cairo_t *cr, double x, double y);

Modified: trunk/moon/src/rect.cpp
===================================================================
--- trunk/moon/src/rect.cpp     2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/rect.cpp     2008-01-30 23:00:04 UTC (rev 94429)
@@ -58,7 +58,7 @@
        return Rect (l, t, r-l, b-t);
 }
 
-Region::Region () : gdkregion (NULL)
+Region::Region ()
 { 
        gdkregion = gdk_region_new (); 
 }
@@ -86,6 +86,12 @@
        gdkregion = NULL;
 }
 
+bool
+Region::IsEmpty ()
+{
+       return gdk_region_empty (gdkregion);
+}
+
 void 
 Region::Union (Rect rect)
 {
@@ -125,7 +131,21 @@
        Intersect (&tmp);
 }
 
+
 void
+Region::Subtract (Region *region)
+{
+       gdk_region_subtract (gdkregion, region->gdkregion);
+}
+
+void
+Region::Subtract (Rect rect)
+{
+       Region tmp = Region (rect);
+       Subtract (&tmp);
+}
+
+void
 Region::GetRectangles (GdkRectangle **rects, int *count)
 {
        gdk_region_get_rectangles (gdkregion, rects, count);

Modified: trunk/moon/src/rect.h
===================================================================
--- trunk/moon/src/rect.h       2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/rect.h       2008-01-30 23:00:04 UTC (rev 94429)
@@ -171,6 +171,8 @@
        
        ~Region ();
 
+       bool IsEmpty ();
+
        void Union (Rect rect);
        void Union (GdkRegion *region);
        void Union (GdkRectangle *rect);
@@ -179,6 +181,9 @@
        void Intersect (Region *region);
        void Intersect (Rect rect);
 
+       void Subtract (Region *region);
+       void Subtract (Rect rect);
+
        void GetRectangles (GdkRectangle **rects, int *count);
 
        Rect ClipBox ();

Modified: trunk/moon/src/runtime.cpp
===================================================================
--- trunk/moon/src/runtime.cpp  2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/runtime.cpp  2008-01-30 23:00:04 UTC (rev 94429)
@@ -85,6 +85,8 @@
        { "bbox=hide",         RUNTIME_INIT_SHOW_BOUNDING_BOXES,   false },
        { "fps=show",          RUNTIME_INIT_SHOW_FPS,              true  },
        { "fps=hide",          RUNTIME_INIT_SHOW_FPS,              false },
+       { "render=ftb",        RUNTIME_INIT_RENDER_FRONT_TO_BACK,  true  },
+       { "render=btf",        RUNTIME_INIT_RENDER_FRONT_TO_BACK,  false  }
 };
 
 #define RENDER_EXPOSE (moonlight_flags & RUNTIME_INIT_SHOW_EXPOSE)
@@ -454,14 +456,72 @@
 void
 Surface::Paint (cairo_t *ctx, Region *region)
 {
+#if FRONT_TO_BACK_STATS
+       uielements_rendered_front_to_back = 0;
+       uielements_rendered_back_to_front = 0;
+#endif
+
        if (is_anything_dirty())
                process_dirty_elements();
+
+       bool did_front_to_back = false;
+
+       List *render_list = new List ();
+       Region *copy = new Region (region->gdkregion);
+
+       if (moonlight_flags & RUNTIME_INIT_RENDER_FRONT_TO_BACK) {
+               if (full_screen_message)
+                       full_screen_message->FrontToBack (copy, render_list);
+
+               toplevel->FrontToBack (copy, render_list);
+
+               if (render_list->IsEmpty()) {
+                       g_warning ("error building up render list - region 
corresponds to no UIElement intersections");
+               }
+               else {
+                       Region *empty_region = new Region ();
+
+                       RenderNode *node;
+                       while ((node = (RenderNode*)render_list->First())) {
+                               Region *r = node->region ? node->region : 
empty_region;
+                               UIElement *ui = node->uielement;
+                        
+#if FRONT_TO_BACK_STATS
+                               uielements_rendered_front_to_back ++;
+#endif
+ 
+                               if (node->pre_render)
+                                       node->pre_render (ctx, ui, r, true);
+
+                               if (node->render_element)
+                                       ui->Render (ctx, r);
+
+                               if (node->post_render)
+                                       node->post_render (ctx, ui, r, true);
+
+                               render_list->Remove (node);
+                       }
+
+                       did_front_to_back = true;
+                       delete empty_region;
+               }
+
+               delete render_list;
+               delete copy;
+       }
        
-       toplevel->DoRender (ctx, region);
-       
-       if (full_screen_message) {
-               full_screen_message->DoRender (ctx, region);
+       if (!did_front_to_back) {
+               toplevel->DoRender (ctx, region);
+
+               if (full_screen_message) {
+                       full_screen_message->DoRender (ctx, region);
+               }
        }
+
+#if FRONT_TO_BACK_STATS
+       printf ("UIElements rendered front-to-back: %d\n", 
uielements_rendered_front_to_back);
+       printf ("UIElements rendered back-to-front: %d\n", 
uielements_rendered_back_to_front);
+#endif
 }
 
 //
@@ -934,6 +994,32 @@
        return TRUE;
 }
 
+RenderNode::RenderNode (UIElement *el,
+                       Region *region,
+                       bool render_element,
+                       RenderFunc pre,
+                       RenderFunc post)
+
+{
+       uielement = el;
+       uielement->ref();
+       this->region = region;
+       this->render_element = render_element;
+       this->pre_render = pre;
+       this->post_render = post;
+}
+
+RenderNode::~RenderNode ()
+{
+       if (uielement) {
+               uielement->unref ();
+               uielement = NULL;
+       }
+
+       if (region)
+               delete region;
+}
+
 UIElementNode::UIElementNode (UIElement *el)
 {
        uielement = el;

Modified: trunk/moon/src/runtime.h
===================================================================
--- trunk/moon/src/runtime.h    2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/runtime.h    2008-01-30 23:00:04 UTC (rev 94429)
@@ -28,6 +28,8 @@
 #include "list.h"
 #include "downloader.h"
 
+#define FRONT_TO_BACK_STATS 0
+
 #define TIMERS 0
 #if TIMERS
 #define STARTTIMER(id,str) TimeSpan id##_t_start = get_now(); printf ("timing 
of '%s' started at %lld\n", str, id##_t_start)
@@ -46,6 +48,7 @@
        RUNTIME_INIT_SHOW_CLIPPING         = 1 << 5,
        RUNTIME_INIT_SHOW_BOUNDING_BOXES   = 1 << 6,
        RUNTIME_INIT_SHOW_FPS              = 1 << 7,
+       RUNTIME_INIT_RENDER_FRONT_TO_BACK  = 1 << 8
 };
 
 #define RUNTIME_INIT_DESKTOP (RUNTIME_INIT_PANGO_TEXT_LAYOUT)
@@ -136,6 +139,11 @@
                fps_report = report;
                fps_data = user_data;
        }
+
+#if FRONT_TO_BACK_STATS
+       int uielements_rendered_front_to_back;
+       int uielements_rendered_back_to_front;
+#endif
        
 private:
        gpointer downloader_context;
@@ -272,7 +280,22 @@
        virtual ~UIElementNode ();
 };
 
+/* for rendering */
+typedef void (*RenderFunc) (cairo_t *ctx, UIElement *uielement, Region 
*region, bool front_to_back);
+class RenderNode : public List::Node {
+public:
+       UIElement *uielement;
+       Region *region;
+       bool render_element;
+       RenderFunc pre_render;
+       RenderFunc post_render;
 
+       RenderNode (UIElement *el, Region *region, bool render_element, 
RenderFunc pre, RenderFunc post);
+
+       virtual ~RenderNode ();
+};
+
+
 Surface *surface_new       (int width, int height);
 void     surface_resize    (Surface *s, int width, int height);
 void     surface_attach    (Surface *s, UIElement *element);

Modified: trunk/moon/src/uielement.cpp
===================================================================
--- trunk/moon/src/uielement.cpp        2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/uielement.cpp        2008-01-30 23:00:04 UTC (rev 94429)
@@ -23,16 +23,7 @@
 #include "eventargs.h"
 
 //#define DEBUG_INVALIDATE 0
-#define QUANTUM_ALPHA 1
 
-#if QUANTUM_ALPHA
-#define IS_TRANSLUCENT(x) (x * 255 < 254.5)
-#define IS_INVISIBLE(x) (x * 255 < .5)
-#else
-#define IS_TRANSLUCENT(x) (x < 1.0)
-#define IS_INVISIBLE(x) (x <= 0.0)
-#endif
-
 extern guint32 moonlight_flags;
 
 
@@ -491,12 +482,80 @@
 void
 UIElement::DoRender (cairo_t *cr, Region *region)
 {
-       cairo_pattern_t *mask = NULL;
+       if (!GetRenderVisible() || IS_INVISIBLE (total_opacity) || 
region->RectIn (GetSubtreeBounds().RoundOut()) == GDK_OVERLAP_RECTANGLE_OUT)
+               return;
+
+#if FRONT_TO_BACK_STATS
+       GetSurface()->uielements_rendered_back_to_front ++;
+#endif
+
+       PreRender (cr, region, false);
+
+       Render (cr, region);
+
+       PostRender (cr, region, false);
+}
+
+void
+UIElement::FrontToBack (Region *surface_region, List *render_list)
+{
        double local_opacity = GetValue (OpacityProperty)->AsDouble();
 
-       if (!GetRenderVisible() || IS_INVISIBLE (total_opacity) || 
region->RectIn (GetSubtreeBounds()) == GDK_OVERLAP_RECTANGLE_OUT)
+       if (!GetRenderVisible ()
+           || IS_INVISIBLE (total_opacity)) {
                return;
-       
+       }
+
+       Region* self_region = new Region (surface_region->gdkregion);
+       self_region->Intersect (bounds.RoundOut());  // note the RoundOut here.
+       if (!self_region->IsEmpty()) {
+               render_list->Prepend (new RenderNode (this, self_region, true, 
CallPreRender, CallPostRender));
+
+               bool subtract = (GetValue (UIElement::ClipProperty) == NULL
+                                && (absolute_xform.yx == 0 && 
absolute_xform.xy == 0) /* no skew */
+                                && opacityMask == NULL
+                                && !IS_TRANSLUCENT (local_opacity));
+
+               // element type specific checks
+               if (subtract) {
+                       if (Is (Type::MEDIAELEMENT)) {
+                               MediaElement *me = (MediaElement*)this;
+                               subtract = (strcmp 
(media_element_get_current_state (me), "Buffering")
+                                           && me->mplayer
+                                           && me->mplayer->rendered_frame
+                                           && ((me->mplayer->width == 
me->GetBounds().w
+                                                && me->mplayer->height == 
me->GetBounds().h)
+                                               ||
+                                               (media_base_get_stretch (me) == 
StretchFill
+                                                || media_base_get_stretch (me) 
== StretchUniformToFill)));
+                       }
+                       else if (Is (Type::IMAGE)) {
+                               Image *image = (Image*)this;
+                               subtract = (image->surface
+                                           && !image->surface->has_alpha
+                                           && ((image->GetWidth() == 
image->GetBounds().w
+                                                && image->GetHeight() == 
image->GetBounds().h)
+                                               ||
+                                               (media_base_get_stretch (image) 
== StretchFill
+                                                || media_base_get_stretch 
(image) == StretchUniformToFill)));
+                       }
+                       // XXX more stuff here for non-panel subclasses...
+                       else {
+                               subtract = false;
+                       }
+               }
+
+               if (subtract)
+                       surface_region->Subtract (bounds); // note the lack of 
RoundOut here.
+
+       }
+}
+
+void
+UIElement::PreRender (cairo_t *cr, Region *region, bool front_to_back)
+{
+       double local_opacity = GetValue (OpacityProperty)->AsDouble();
+
        STARTTIMER (UIElement_render, Type::Find (GetObjectType())->name);
        cairo_save (cr);
 
@@ -519,10 +578,15 @@
 
        if (opacityMask != NULL)
                cairo_push_group (cr);
+}
 
-       Render (cr, region);
+void
+UIElement::PostRender (cairo_t *cr, Region *region, bool front_to_back)
+{
+       double local_opacity = GetValue (OpacityProperty)->AsDouble();
 
        if (opacityMask != NULL) {
+               cairo_pattern_t *mask;
                cairo_pattern_t *data = cairo_pop_group (cr);
                opacityMask->SetupBrush (cr, this);
                mask = cairo_get_source (cr);
@@ -540,7 +604,7 @@
        cairo_restore (cr);
        
        ENDTIMER (UIElement_render, Type::Find (GetObjectType())->name);
-       
+
        if (moonlight_flags & RUNTIME_INIT_SHOW_CLIPPING) {
                cairo_save (cr);
                cairo_new_path (cr);
@@ -571,6 +635,18 @@
 }
 
 void
+UIElement::CallPreRender (cairo_t *cr, UIElement *element, Region *region, 
bool front_to_back)
+{
+       element->PreRender (cr, region, front_to_back);
+}
+
+void
+UIElement::CallPostRender (cairo_t *cr, UIElement *element, Region *region, 
bool front_to_back)
+{
+       element->PostRender (cr, region, front_to_back);
+}
+
+void
 UIElement::Render (cairo_t *cr, Region *region)
 {
         Rect rect = region->ClipBox ();

Modified: trunk/moon/src/uielement.h
===================================================================
--- trunk/moon/src/uielement.h  2008-01-30 22:48:00 UTC (rev 94428)
+++ trunk/moon/src/uielement.h  2008-01-30 23:00:04 UTC (rev 94429)
@@ -18,6 +18,16 @@
 #include "rect.h"
 #include "list.h"
 
+#define QUANTUM_ALPHA 1
+
+#if QUANTUM_ALPHA
+#define IS_TRANSLUCENT(x) (x * 255 < 254.5)
+#define IS_INVISIBLE(x) (x * 255 < .5)
+#else
+#define IS_TRANSLUCENT(x) (x < 1.0)
+#define IS_INVISIBLE(x) (x <= 0.0)
+#endif
+
 class Surface;
 
 class UIElement : public Visual {
@@ -122,6 +132,13 @@
        // with debugging and/or timing info
        void DoRender (cairo_t *cr, Region *region);
 
+       virtual void FrontToBack (Region *surface_region, List *render_list);
+       virtual void PreRender (cairo_t *cr, Region *region, bool 
front_to_back);
+       virtual void PostRender (cairo_t *cr, Region *region, bool 
front_to_back);
+
+       static void CallPreRender (cairo_t *cr, UIElement *element, Region 
*region, bool front_to_back);
+       static void CallPostRender (cairo_t *cr, UIElement *element, Region 
*region, bool front_to_back);
+
        //
        // GetSizeForBrush:
        //   Gets the size of the area to be painted by a Brush (needed for 
image/video scaling)

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to