All pastes #894949 Raw Edit

Unnamed

public text v1 · immutable
·published 2008-02-07 13:24 UTC
rendered paste body
Index: shape.cpp
===================================================================
--- shape.cpp	(revision 95129)
+++ shape.cpp	(working copy)
@@ -319,47 +319,47 @@
 void
 Shape::ComputeBounds ()
 {
-	bounds = Rect (0,0,0,0);
+	Rect shape_bounds = ComputeShapeBounds ();
+	bounds = bounding_rect_for_transformed_rect (&absolute_xform,
+		       IntersectBoundsWithClipPath (shape_bounds, false));
+	//printf ("%f,%f,%f,%f\n", bounds.x, bounds.y, bounds.w, bounds.h);
+}
 
+Rect
+Shape::ComputeShapeBounds ()
+{
 	if (IsEmpty ())
-		return;
+		return Rect ();
 
 	double w = framework_element_get_width (this);
 	double h = framework_element_get_height (this);
 
-#if FALSE
-	Stretch stretch = shape_get_stretch (this);
-	switch (stretch) {
-	case StretchUniform:
-		w = h = (w < h) ? w : h;
-		break;
-	case StretchUniformToFill:
-		w = h = (w > h) ? w : h;
-		break;
-	case StretchFill:
-		/* nothing needed here.  the assignment of w/h above
-		   is correct for this case. */
-		break;
-	case StretchNone:
-		break;
-	}
-#endif
+	if ((w == 0.0) && (h == 0.0))
+		return Rect ();
 
-	if (w != 0.0 && h != 0.0) {
-		double t = shape_get_stroke_thickness (this) * .5;
+	double t = shape_get_stroke_thickness (this) * .5;
 
-		bounds = bounding_rect_for_transformed_rect (&absolute_xform,
-		       IntersectBoundsWithClipPath (Rect (-t, -t, w + 2 * t, h + 2 * t), false));
+	return Rect (-t, -t, w + 2 * t, h + 2 * t);
+}
 
-		//printf ("%f,%f,%f,%f\n", bounds.x, bounds.y, bounds.w, bounds.h);
-	}
+Rect
+Shape::ComputeLargestRectangleBounds ()
+{
+	Rect largest = ComputeLargestRectangle ();
+	if (largest.IsEmpty ())
+		return largest;
 
-	/* standard "grow the rectangle by enough to cover our
-	   asses because of cairo's floating point rendering"
-	   thing */
-// no-op	bounds.GrowBy(1);
+	return bounding_rect_for_transformed_rect (&absolute_xform,
+						    IntersectBoundsWithClipPath (largest, false));
 }
 
+Rect
+Shape::ComputeLargestRectangle ()
+{
+	// by default the largest rectangle that fits into a shape is empty
+	return Rect ();
+}
+
 void
 Shape::GetSizeForBrush (cairo_t *cr, double *width, double *height)
 {
@@ -765,6 +765,15 @@
 	// note: both moon_rounded_rectangle and moon_ellipse close the path
 }
 
+Rect
+Ellipse::ComputeLargestRectangle ()
+{
+	double t = GetValue (Shape::StrokeThicknessProperty)->AsDouble ();
+	double x = (GetValue (FrameworkElement::WidthProperty)->AsDouble () - t) * cos (M_PI_2);
+	double y = (GetValue (FrameworkElement::HeightProperty)->AsDouble () - t) * sin (M_PI_2);
+	Rect largest = ComputeShapeBounds ().GrowBy (-x, -y).RoundIn ();
+}
+
 void
 Ellipse::OnPropertyChanged (DependencyProperty *prop)
 {
@@ -1007,10 +1016,22 @@
 	return ((*rx != 0.0) && (*ry != 0.0));
 }
 
+Rect
+Rectangle::ComputeLargestRectangle ()
+{
+	double x = GetValue (Shape::StrokeThicknessProperty)->AsDouble ();
+	double y = x;
+	if (HasRadii ()) {
+		x += GetValue (Rectangle::RadiusXProperty)->AsDouble ();
+		y += GetValue (Rectangle::RadiusYProperty)->AsDouble ();
+	}
+	return ComputeShapeBounds ().GrowBy (-x, -y).RoundIn ();
+}
+
 double
 rectangle_get_radius_x (Rectangle *rectangle)
 {
-	return rectangle->GetValue (Rectangle::RadiusXProperty)->AsDouble();
+	return rectangle->GetValue (Rectangle::RadiusXProperty)->AsDouble ();
 }
 
 void
@@ -1182,39 +1203,36 @@
 	moon_line_to (path, line_get_x2 (this), line_get_y2 (this));
 }
 
-void
-Line::ComputeBounds ()
+Rect
+Line::ComputeShapeBounds ()
 {
+	Rect shape_bounds = Rect ();
+
 	Value *vh, *vw;
-	if (Shape::MixedHeightWidth (&vh, &vw)) {
-		bounds = Rect (0.0, 0.0, 0.0, 0.0);
-		return;
-	}
+	if (Shape::MixedHeightWidth (&vh, &vw))
+		return shape_bounds;
 
 	double thickness = shape_get_stroke_thickness (this);
-	if (thickness <= 0.0) {
-		bounds = Rect (0.0, 0.0, 0.0, 0.0);
-		return;
-	}
+	if (thickness <= 0.0)
+		return shape_bounds;
 
 	double x1 = line_get_x1 (this);
 	double y1 = line_get_y1 (this);
 	double x2 = line_get_x2 (this);
 	double y2 = line_get_y2 (this);
 
-	calc_line_bounds (x1, x2, y1, y2, thickness, &bounds);
+	calc_line_bounds (x1, x2, y1, y2, thickness, &shape_bounds);
 	origin.x = MIN (x1, x2);
 	origin.y = MIN (y1, y2);
 
 	// if Height and Width are specified (they could be both missing)
 	// then we must clip the line those values
 	if (vh && vw) {
-		bounds.w = MIN (bounds.w, vw->AsDouble ());
-		bounds.h = MIN (bounds.h, vh->AsDouble ());
+		shape_bounds.w = MIN (shape_bounds.w, vw->AsDouble ());
+		shape_bounds.h = MIN (shape_bounds.h, vh->AsDouble ());
 	}
 
-	bounds = bounding_rect_for_transformed_rect (&absolute_xform, 
-						     IntersectBoundsWithClipPath (bounds, false));
+	return shape_bounds;
 }
 
 void
@@ -1450,23 +1468,21 @@
 	}
 }
 
-void
-Polygon::ComputeBounds ()
+Rect
+Polygon::ComputeShapeBounds ()
 {
+	Rect shape_bounds = Rect ();
+
 	Value *vh, *vw;
-	if (Shape::MixedHeightWidth (&vh, &vw)) {
-		bounds = Rect (0.0, 0.0, 0.0, 0.0);
-		return;
-	}
+	if (Shape::MixedHeightWidth (&vh, &vw))
+		return shape_bounds;
 
 	int i, count = 0;
 	Point *points = polygon_get_points (this, &count);
 
 	// the first point is a move to, resulting in an empty shape
-	if (!points || (count < 2)) {
-		bounds = Rect (0.0, 0.0, 0.0, 0.0);
-		return;
-	}
+	if (!points || (count < 2))
+		return shape_bounds;
 
 	double thickness = shape_get_stroke_thickness (this);
 	if (thickness == 0.0)
@@ -1483,10 +1499,10 @@
 		origin.y = MIN (origin.y, points[1].y);
 
 		polygon_extend_line (&x0, &x1, &y0, &y1, thickness);
-		calc_line_bounds (x0, x1, y0, y1, thickness, &bounds);
+		calc_line_bounds (x0, x1, y0, y1, thickness, &shape_bounds);
 	} else {
-		bounds.x = x1 = x0;
-		bounds.y = y1 = y0;
+		shape_bounds.x = x1 = x0;
+		shape_bounds.y = y1 = y0;
 		// FIXME: we're too big for large thickness and/or steep angle
 		Rect line_bounds;
 		double x2 = points [1].x;
@@ -1496,7 +1512,7 @@
 		origin.x = MIN (origin.x, MIN (x2, x3));
 		origin.y = MIN (origin.y, MIN (y2, y3));
 
-		calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &bounds);
+		calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &shape_bounds);
 		for (i = 3; i < count; i++) {
 			x1 = x2;
 			y1 = y2;
@@ -1506,7 +1522,7 @@
 			y3 = points [i].y;
 			origin.x = MIN (origin.x, x3);
 			origin.y = MIN (origin.y, y3);
-			calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &bounds);
+			calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &shape_bounds);
 		}
 		// a polygon is a closed shape (unless it's a line)
 		x1 = x2;
@@ -1515,7 +1531,7 @@
 		y2 = y3;
 		x3 = x0;
 		y3 = y0;
-		calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &bounds);
+		calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &shape_bounds);
 
 		x1 = points [count-1].x;
 		y1 = points [count-1].y;
@@ -1523,24 +1539,23 @@
 		y2 = y0;
 		x3 = points [1].x;
 		y3 = points [1].y;
-		calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &bounds);
+		calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &shape_bounds);
 	}
 
 	if (shape_get_stretch (this) != StretchNone) {
-		bounds.x -= x0;
-		bounds.y -= y0;
+		shape_bounds.x -= x0;
+		shape_bounds.y -= y0;
 	}
 
 	// if Height and Width are specified (they could be both missing)
 	// then we must clip the path those values, and this also defines
 	// *exactly* our bounds (whether we like them or not is another story)
 	if (vh && vw) {
-		bounds.w = vw->AsDouble ();
-		bounds.h = vh->AsDouble ();
+		shape_bounds.w = vw->AsDouble ();
+		shape_bounds.h = vh->AsDouble ();
 	}
 
-	bounds = bounding_rect_for_transformed_rect (&absolute_xform, 
-						     IntersectBoundsWithClipPath (bounds, false));
+	return shape_bounds;
 }
 
 void
@@ -1758,23 +1773,21 @@
 	return polyline_get_fill_rule (this);
 }
 
-void
-Polyline::ComputeBounds ()
+Rect
+Polyline::ComputeShapeBounds ()
 {
+	Rect shape_bounds = Rect ();
+
 	Value *vh, *vw;
-	if (Shape::MixedHeightWidth (&vh, &vw)) {
-		bounds = Rect (0.0, 0.0, 0.0, 0.0);
-		return;
-	}
+	if (Shape::MixedHeightWidth (&vh, &vw))
+		return shape_bounds;
 
 	int i, count = 0;
 	Point *points = polyline_get_points (this, &count);
 
 	// the first point is a move to, resulting in an empty shape
-	if (!points || (count < 2)) {
-		bounds = Rect (0.0, 0.0, 0.0, 0.0);
-		return;
-	}
+	if (!points || (count < 2))
+		return shape_bounds;
 
 	double thickness = shape_get_stroke_thickness (this);
 	if (thickness == 0.0)
@@ -1789,7 +1802,7 @@
 		double y2 = points [1].y;
 		origin.x = MIN (origin.x, x2);
 		origin.y = MIN (origin.y, y2);
-		calc_line_bounds (x1, x2, y1, y2, thickness, &bounds);
+		calc_line_bounds (x1, x2, y1, y2, thickness, &shape_bounds);
 	} else {
 		// FIXME: we're too big for large thickness and/or steep angle
 		Rect line_bounds;
@@ -1797,37 +1810,36 @@
 		double y2 = points [1].y;
 		origin.x = MIN (origin.x, x2);
 		origin.y = MIN (origin.y, y2);
-		calc_line_bounds (x1, x2, y1, y2, thickness, &bounds);
+		calc_line_bounds (x1, x2, y1, y2, thickness, &shape_bounds);
 		for (i = 2; i < count; i++) {
 			double x3 = points [i].x;
 			double y3 = points [i].y;
 			origin.x = MIN (origin.x, x3);
 			origin.y = MIN (origin.y, y3);
-			calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &bounds);
+			calc_line_bounds_with_joins (x1, y1, x2, y2, x3, y3, thickness, &shape_bounds);
 			x1 = x2;
 			y1 = y2;
 			x2 = x3;
 			y2 = y3;
 		}
 		calc_line_bounds (x1, x2, y1, y2, thickness, &line_bounds);
-		bounds = bounds.Union (line_bounds);
+		shape_bounds = shape_bounds.Union (line_bounds);
 	}
 
 	if (shape_get_stretch (this) != StretchNone) {
-		bounds.x -= points [0].x;
-		bounds.y -= points [0].y;
+		shape_bounds.x -= points [0].x;
+		shape_bounds.y -= points [0].y;
 	}
 
 	// if Height and Width are specified (they could be both missing)
 	// then we must clip the path those values, and this also defines
 	// *exactly* our bounds (whether we like them or not is another story)
 	if (vh && vw) {
-		bounds.w = vw->AsDouble ();
-		bounds.h = vh->AsDouble ();
+		shape_bounds.w = vw->AsDouble ();
+		shape_bounds.h = vh->AsDouble ();
 	}
 
-	bounds = bounding_rect_for_transformed_rect (&absolute_xform, 
-						     IntersectBoundsWithClipPath (bounds, false));
+	return shape_bounds;
 }
 
 void
@@ -1997,20 +2009,20 @@
 	return geometry ? geometry_get_fill_rule (geometry) : Shape::GetFillRule ();
 }
 
-void
-Path::ComputeBounds ()
+Rect
+Path::ComputeShapeBounds ()
 {
-	bounds = Rect (0.0, 0.0, 0.0, 0.0);
+	Rect shape_bounds = Rect ();
 	cairo_matrix_init_identity (&stretch_transform);
 
 	Value *vh, *vw;
 	if (Shape::MixedHeightWidth (&vh, &vw))
-		return;
+		return shape_bounds;
 
 	Geometry* geometry = path_get_data (this);
 	if (!geometry) {
 		SetShapeFlags (UIElement::SHAPE_EMPTY);
-		return;
+		return shape_bounds;
 	}
 
 	double w = vw ? vw->AsDouble () : 0.0;
@@ -2018,30 +2030,30 @@
 	
 	if ((h < 0.0) || (w < 0.0)) {
 		SetShapeFlags (UIElement::SHAPE_EMPTY);
-		return;
+		return shape_bounds;
 	}
 
 	if (vh && (h <= 0.0) || vw && (w <= 0.0)) { 
 		SetShapeFlags (UIElement::SHAPE_EMPTY);
-		return;
+		return shape_bounds;
 	}
 	
-	bounds = geometry->ComputeBounds (this);
+	shape_bounds = geometry->ComputeBounds (this);
 
-	h = (h == 0.0) ? bounds.h : h;
-	w = (w == 0.0) ? bounds.w : w;
+	h = (h == 0.0) ? shape_bounds.h : h;
+	w = (w == 0.0) ? shape_bounds.w : w;
 
 	if (h <= 0.0 || w <= 0.0) {
 		SetShapeFlags (UIElement::SHAPE_EMPTY);
-		return;
+		return shape_bounds;
 	}
 
 	// Compute the transformation we use for stretching
 
 	Stretch stretch = shape_get_stretch (this);
 	if (stretch != StretchNone) {
-		double sh = h / bounds.h;
-		double sw = w / bounds.w;
+		double sh = h / shape_bounds.h;
+		double sw = w / shape_bounds.w;
 		switch (stretch) {
 		case StretchFill:
 			break;
@@ -2057,28 +2069,26 @@
 		}
 		
 		cairo_matrix_scale (&stretch_transform, sw, sh);
-		cairo_matrix_translate (&stretch_transform, -bounds.x, -bounds.y);
+		cairo_matrix_translate (&stretch_transform, -shape_bounds.x, -shape_bounds.y);
 		
 		// Double check our math
 		cairo_matrix_t test = stretch_transform;
 		if (cairo_matrix_invert (&test)) {
 			cairo_matrix_init_identity (&stretch_transform);
-			g_warning ("Unable to compute stretch transform %f %f %f %f \n", sw, sh, bounds.x, bounds.y);
+			g_warning ("Unable to compute stretch transform %f %f %f %f \n", sw, sh, shape_bounds.x, shape_bounds.y);
 		}		
 	}
 
-	bounds = bounding_rect_for_transformed_rect (&stretch_transform, bounds);
+	shape_bounds = bounding_rect_for_transformed_rect (&stretch_transform, shape_bounds);
 		
 	if (vh && vw) {
-		bounds.w = MIN (bounds.w, vw->AsDouble ());
-		bounds.h = MIN (bounds.h, vh->AsDouble ());
+		shape_bounds.w = MIN (shape_bounds.w, vw->AsDouble ());
+		shape_bounds.h = MIN (shape_bounds.h, vh->AsDouble ());
 	}
 
-	bounds = bounding_rect_for_transformed_rect (&absolute_xform,
-						     IntersectBoundsWithClipPath (bounds, false));
 	//FIXME
-	origin = Point (bounds.x, bounds.y);
-		
+	origin = Point (shape_bounds.x, shape_bounds.y);
+	return shape_bounds;
 }
 
 void
Index: shape.h
===================================================================
--- shape.h	(revision 95129)
+++ shape.h	(working copy)
@@ -49,6 +49,9 @@
 
 	moon_path *path;
 	virtual void InvalidatePathCache (bool free = false);
+
+	virtual Rect ComputeShapeBounds ();
+	virtual Rect ComputeLargestRectangle ();
  public: 
 	static DependencyProperty* FillProperty;
 	static DependencyProperty* StretchProperty;
@@ -74,9 +77,9 @@
 	virtual void ComputeBounds ();
 	virtual bool InsideObject (cairo_t *cr, double x, double y);
 	virtual Point GetTransformOrigin ();
-	virtual Point GetOriginPoint () {
-		return origin;
-	}
+	virtual Point GetOriginPoint () { return origin; }
+
+	Rect ComputeLargestRectangleBounds ();
 	
 	//
 	// new virtual methods for shapes
@@ -142,6 +145,7 @@
 class Ellipse : public Shape {
  protected:
 	virtual bool DrawShape (cairo_t *cr, bool do_op);
+	virtual Rect ComputeLargestRectangle ();
  public:
 	Ellipse ();
 	virtual Type::Kind GetObjectType () { return Type::ELLIPSE; };
@@ -169,11 +173,12 @@
 	virtual Type::Kind GetObjectType () { return Type::RECTANGLE; };
 
 	virtual void BuildPath ();
+	virtual bool CanFill () { return true; }
 
 	virtual void OnPropertyChanged (DependencyProperty *prop);
 
 	bool GetRadius (double *rx, double *ry);
-	virtual bool CanFill () { return true; }
+	virtual Rect ComputeLargestRectangle ();
 };
 
 Rectangle *rectangle_new          (void);
@@ -189,6 +194,7 @@
 class Line : public Shape {
  protected:
 	virtual bool DrawShape (cairo_t *cr, bool do_op);
+	virtual Rect ComputeShapeBounds ();
  public:
 	static DependencyProperty* X1Property;
 	static DependencyProperty* Y1Property;
@@ -198,7 +204,6 @@
 	virtual Type::Kind GetObjectType () { return Type::LINE; };
 	
 	virtual void BuildPath ();
-	virtual void ComputeBounds ();
 	virtual bool ClipOnHeightAndWidth () { return true; }
 
 	virtual void OnPropertyChanged (DependencyProperty *prop);
@@ -224,6 +229,7 @@
 class Polygon : public Shape {
  protected:
 	virtual bool DrawShape (cairo_t *cr, bool do_op);
+	virtual Rect ComputeShapeBounds ();
  public:
 	static DependencyProperty* FillRuleProperty;
 	static DependencyProperty* PointsProperty;
@@ -241,7 +247,6 @@
 	virtual bool CanFill () { return true; }
 
 	virtual void GetSizeForBrush (cairo_t *cr, double *width, double *height);
-	virtual void ComputeBounds ();
 	virtual bool ClipOnHeightAndWidth () { return true; }
 
 	virtual void OnPropertyChanged (DependencyProperty *prop);
@@ -261,6 +266,7 @@
 class Polyline : public Shape {
  protected:
 	virtual bool DrawShape (cairo_t *cr, bool do_op);
+	virtual Rect ComputeShapeBounds ();
  public:
 	static DependencyProperty* FillRuleProperty;
 	static DependencyProperty* PointsProperty;
@@ -275,7 +281,6 @@
 
 	virtual bool CanFill () { return true; }
 	virtual void GetSizeForBrush (cairo_t *cr, double *width, double *height);
-	virtual void ComputeBounds ();
 	virtual bool ClipOnHeightAndWidth () { return true; }
 
 	virtual FillRule GetFillRule ();
@@ -298,6 +303,8 @@
  protected:
 	virtual bool SetupLine (cairo_t* cr);
 	virtual bool DrawShape (cairo_t *cr, bool do_op);
+	virtual Rect ComputeShapeBounds ();
+
 	cairo_matrix_t stretch_transform;
  public:
 	static DependencyProperty* DataProperty;
@@ -312,7 +319,6 @@
 	virtual void Draw (cairo_t *cr);
 
 	virtual void GetSizeForBrush (cairo_t *cr, double *width, double *height);
-	virtual void ComputeBounds ();
 	virtual bool ClipOnHeightAndWidth () { return true; }
 
 	virtual bool CanFill () { return true; }