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