示例#1
0
void
StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget,
                        const ColorPattern& aColor,
                        const StrokeOptions& aStrokeOptions)
{
  if (aRect.IsEmpty()) {
    return;
  }

  Point p1 = aRect.TopLeft();
  Point p2 = aRect.BottomLeft();
  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);

  p1 = aRect.BottomLeft();
  p2 = aRect.BottomRight();
  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);

  p1 = aRect.TopLeft();
  p2 = aRect.TopRight();
  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);

  p1 = aRect.TopRight();
  p2 = aRect.BottomRight();
  SnapLineToDevicePixelsForStroking(p1, p2, aDrawTarget);
  aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
}
示例#2
0
Rect
Matrix::TransformBounds(const Rect &aRect) const
{
  int i;
  Point quad[4];
  Float min_x, max_x;
  Float min_y, max_y;

  quad[0] = *this * aRect.TopLeft();
  quad[1] = *this * aRect.TopRight();
  quad[2] = *this * aRect.BottomLeft();
  quad[3] = *this * aRect.BottomRight();

  min_x = max_x = quad[0].x;
  min_y = max_y = quad[0].y;

  for (i = 1; i < 4; i++) {
    if (quad[i].x < min_x)
      min_x = quad[i].x;
    if (quad[i].x > max_x)
      max_x = quad[i].x;

    if (quad[i].y < min_y)
      min_y = quad[i].y;
    if (quad[i].y > max_y)
      max_y = quad[i].y;
  }

  return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
}
// XXX snapToPixels is only valid when snapping for filled
// rectangles and for even-width stroked rectangles.
// For odd-width stroked rectangles, we need to offset x/y by
// 0.5...
void
gfxContext::Rectangle(const gfxRect& rect, bool snapToPixels)
{
  Rect rec = ToRect(rect);

  if (snapToPixels) {
    gfxRect newRect(rect);
    if (UserToDevicePixelSnapped(newRect, true)) {
      gfxMatrix mat = ThebesMatrix(mTransform);
      if (mat.Invert()) {
        // We need the user space rect.
        rec = ToRect(mat.TransformBounds(newRect));
      } else {
        rec = Rect();
      }
    }
  }

  if (!mPathBuilder && !mPathIsRect) {
    mPathIsRect = true;
    mRect = rec;
    return;
  }

  EnsurePathBuilder();

  mPathBuilder->MoveTo(rec.TopLeft());
  mPathBuilder->LineTo(rec.TopRight());
  mPathBuilder->LineTo(rec.BottomRight());
  mPathBuilder->LineTo(rec.BottomLeft());
  mPathBuilder->Close();
}
示例#4
0
void
DrawTargetD2D1::PushClipRect(const Rect &aRect)
{
  if (!mTransform.IsRectilinear()) {
    // Whoops, this isn't a rectangle in device space, Direct2D will not deal
    // with this transform the way we want it to.
    // See remarks: http://msdn.microsoft.com/en-us/library/dd316860%28VS.85%29.aspx

    RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
    pathBuilder->MoveTo(aRect.TopLeft());
    pathBuilder->LineTo(aRect.TopRight());
    pathBuilder->LineTo(aRect.BottomRight());
    pathBuilder->LineTo(aRect.BottomLeft());
    pathBuilder->Close();
    RefPtr<Path> path = pathBuilder->Finish();
    return PushClip(path);
  }

  PushedClip clip;
  Rect rect = mTransform.TransformBounds(aRect);
  IntRect intRect;
  clip.mIsPixelAligned = rect.ToIntRect(&intRect);

  // Do not store the transform, just store the device space rectangle directly.
  clip.mBounds = D2DRect(rect);

  mPushedClips.push_back(clip);

  mDC->SetTransform(D2D1::IdentityMatrix());
  mTransformDirty = true;

  if (mClipsArePushed) {
    mDC->PushAxisAlignedClip(clip.mBounds, clip.mIsPixelAligned ? D2D1_ANTIALIAS_MODE_ALIASED : D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
  }
}
示例#5
0
void
AppendRectToPath(PathBuilder* aPathBuilder,
                 const Rect& aRect,
                 bool aDrawClockwise)
{
  if (aDrawClockwise) {
    aPathBuilder->MoveTo(aRect.TopLeft());
    aPathBuilder->LineTo(aRect.TopRight());
    aPathBuilder->LineTo(aRect.BottomRight());
    aPathBuilder->LineTo(aRect.BottomLeft());
  } else {
    aPathBuilder->MoveTo(aRect.TopRight());
    aPathBuilder->LineTo(aRect.TopLeft());
    aPathBuilder->LineTo(aRect.BottomLeft());
    aPathBuilder->LineTo(aRect.BottomRight());
  }
  aPathBuilder->Close();
}
示例#6
0
void TopSubMenuItem::Pull()
{
	Rect r = GetScreenRect();
	if(parentmenu && parentmenu->IsChild() && !parentmenu->submenu)
		parentmenu->SetupRestoreFocus();
	Point p = r.BottomLeft();
	if(GUI_GlobalStyle() >= GUISTYLE_XP)
		p += style->pullshift;
	SubMenuBase::Pull(this, p, Size(r.Width(), -r.Height()));
	if(parentmenu)
		parentmenu->SyncState();
}
ConvexPolygon::ConvexPolygon(const Rect& aRect)
{
  if (!aRect.width || !aRect.height) {
    return;
  }

  mPoints.reserve(4);
  mPoints.push_back(aRect.BottomRight());
  mPoints.push_back(aRect.TopRight());
  mPoints.push_back(aRect.TopLeft());
  mPoints.push_back(aRect.BottomLeft());

  EnsureAntiClockwise();
}
示例#8
0
Rect Matrix4x4::ProjectRectBounds(const Rect& aRect) const
{
  Point4D points[4];

  points[0] = ProjectPoint(aRect.TopLeft());
  points[1] = ProjectPoint(aRect.TopRight());
  points[2] = ProjectPoint(aRect.BottomRight());
  points[3] = ProjectPoint(aRect.BottomLeft());

  Float min_x = std::numeric_limits<Float>::max();
  Float min_y = std::numeric_limits<Float>::max();
  Float max_x = -std::numeric_limits<Float>::max();
  Float max_y = -std::numeric_limits<Float>::max();

  bool foundPoint = false;
  for (int i=0; i<4; i++) {
    // Only use points that exist above the w=0 plane
    if (points[i].HasPositiveWCoord()) {
      foundPoint = true;
      Point point2d = points[i].As2DPoint();
      min_x = min<Float>(point2d.x, min_x);
      max_x = max<Float>(point2d.x, max_x);
      min_y = min<Float>(point2d.y, min_y);
      max_y = max<Float>(point2d.y, max_y);
    }

    int next = (i == 3) ? 0 : i + 1;
    if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) {
      // If the line between two points crosses the w=0 plane, then interpolate a point
      // as close to the w=0 plane as possible and use that instead.
      Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]);

      Point point2d = intercept.As2DPoint();
      min_x = min<Float>(point2d.x, min_x);
      max_x = max<Float>(point2d.x, max_x);
      min_y = min<Float>(point2d.y, min_y);
      max_y = max<Float>(point2d.y, max_y);
    }
  }

  if (!foundPoint) {
    return Rect(0, 0, 0, 0);
  }

  return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
}
示例#9
0
Rect Matrix4x4::ProjectRectBounds(const Rect& aRect, const Rect &aClip) const
{
  // This function must never return std::numeric_limits<Float>::max() or any
  // other arbitrary large value in place of inifinity.  This often occurs when
  // aRect is an inversed projection matrix or when aRect is transformed to be
  // partly behind and in front of the camera (w=0 plane in homogenous
  // coordinates) - See Bug 1035611

  // Some call-sites will call RoundGfxRectToAppRect which clips both the
  // extents and dimensions of the rect to be bounded by nscoord_MAX.
  // If we return a Rect that, when converted to nscoords, has a width or height
  // greater than nscoord_MAX, RoundGfxRectToAppRect will clip the overflow
  // off both the min and max end of the rect after clipping the extents of the
  // rect, resulting in a translation of the rect towards the infinite end.

  // The bounds returned by ProjectRectBounds are expected to be clipped only on
  // the edges beyond the bounds of the coordinate system; otherwise, the
  // clipped bounding box would be smaller than the correct one and result
  // bugs such as incorrect culling (eg. Bug 1073056)

  // To address this without requiring all code to work in homogenous
  // coordinates or interpret infinite values correctly, a specialized
  // clipping function is integrated into ProjectRectBounds.

  // Callers should pass an aClip value that represents the extents to clip
  // the result to, in the same coordinate system as aRect.
  Point4D points[4];

  points[0] = ProjectPoint(aRect.TopLeft());
  points[1] = ProjectPoint(aRect.TopRight());
  points[2] = ProjectPoint(aRect.BottomRight());
  points[3] = ProjectPoint(aRect.BottomLeft());

  Float min_x = std::numeric_limits<Float>::max();
  Float min_y = std::numeric_limits<Float>::max();
  Float max_x = -std::numeric_limits<Float>::max();
  Float max_y = -std::numeric_limits<Float>::max();

  for (int i=0; i<4; i++) {
    // Only use points that exist above the w=0 plane
    if (points[i].HasPositiveWCoord()) {
      Point point2d = aClip.ClampPoint(points[i].As2DPoint());
      min_x = std::min<Float>(point2d.x, min_x);
      max_x = std::max<Float>(point2d.x, max_x);
      min_y = std::min<Float>(point2d.y, min_y);
      max_y = std::max<Float>(point2d.y, max_y);
    }

    int next = (i == 3) ? 0 : i + 1;
    if (points[i].HasPositiveWCoord() != points[next].HasPositiveWCoord()) {
      // If the line between two points crosses the w=0 plane, then interpolate
      // to find the point of intersection with the w=0 plane and use that
      // instead.
      Point4D intercept = ComputePerspectivePlaneIntercept(points[i], points[next]);
      // Since intercept.w will always be 0 here, we interpret x,y,z as a
      // direction towards an infinite vanishing point.
      if (intercept.x < 0.0f) {
        min_x = aClip.x;
      } else if (intercept.x > 0.0f) {
        max_x = aClip.XMost();
      }
      if (intercept.y < 0.0f) {
        min_y = aClip.y;
      } else if (intercept.y > 0.0f) {
        max_y = aClip.YMost();
      }
    }
  }

  if (max_x < min_x || max_y < min_y) {
    return Rect(0, 0, 0, 0);
  }

  return Rect(min_x, min_y, max_x - min_x, max_y - min_y);
}
示例#10
0
void FormView::DrawGroupTools(Draw& w, const Rect& r)
{
	if (!IsLayout())
		return;

	_groupRect = r;
	Point p;
	Rect t;
	int v;

	p = r.TopLeft();
	v = (r.BottomLeft().y >= GetRect().Height())
		? GetRect().Height() - (GetRect().Height() - r.TopLeft().y) / 2 - 10
		: ((r.TopLeft().y < 0)
			? r.BottomLeft().y / 2 - 10
			: r.CenterLeft().y - 10);
	if (p.x >= 20)  // left tool
	{
		t = Rect(Point(r.CenterLeft().x - 10, v), Size(11, 11) );
		w.DrawImage(t, _toolLeft[_leftCur]);
	}
	else
	{
		t = Rect(Point(2, v), Size(11, 11) );
		w.DrawImage(t, _toolLeft[_leftCur]);
	}

	v = (r.TopLeft().x < 0)
		?  r.TopRight().x / 2 - 5
		: (r.TopRight().x > GetRect().Width()
			? GetRect().Width() - (GetRect().Width() - r.TopLeft().x) / 2 - 5
			: r.TopCenter().x - 5);
	if (p.y >= 20)
	{
		t = Rect( Point(v, r.TopCenter().y - 10), Size(11, 11) ); // top tool
		w.DrawImage(t, _toolTop[_topCur]);
	}
	else
	{
		t = Rect( Point(v, 2), Size(11, 11) ); // top tool
		w.DrawImage(t, _toolTop[_topCur]);
	}

	p = r.BottomRight();
	v = (p.y >= GetRect().Height())
		? GetRect().Height() - (GetRect().Height() - r.TopLeft().y) / 2 - 10
		: ((r.TopLeft().y < 0)
			? r.BottomLeft().y / 2 - 110
			: r.CenterLeft().y - 10);
	if (p.x <= GetRect().Width() - 20)
	{
		t = Rect( Point(r.CenterRight().x, v), Size(11, 11) ); // right tool
		w.DrawImage(t, _toolRight[_rightCur]);
	}
	else
	{
		t = Rect( Point(GetRect().Width() - 11, v), Size(11, 11) ); // right tool
		w.DrawImage(t, _toolRight[_rightCur]);
	}

	v = (r.TopLeft().x < 0)
		?  r.TopRight().x / 2 - 5
		: (r.TopRight().x > GetRect().Width()
			? GetRect().Width() - (GetRect().Width() - r.TopLeft().x) / 2 - 5
			: r.TopCenter().x - 5);
	if (p.y <= GetRect().Height() - 20)
	{
		t = Rect( Point(v, r.BottomCenter().y), Size(11, 11) ); // bottom tool
		w.DrawImage(t, _toolBottom[_bottomCur]);
	}
	else
	{
		t = Rect( Point(v, GetRect().Height() - 11), Size(11, 11) ); // bottom tool
		w.DrawImage(t, _toolBottom[_bottomCur]);
	}
}
示例#11
0
void
AppendRoundedRectToPath(PathBuilder* aPathBuilder,
                        const Rect& aRect,
                        const RectCornerRadii& aRadii,
                        bool aDrawClockwise)
{
  // For CW drawing, this looks like:
  //
  //  ...******0**      1    C
  //              ****
  //                  ***    2
  //                     **
  //                       *
  //                        *
  //                         3
  //                         *
  //                         *
  //
  // Where 0, 1, 2, 3 are the control points of the Bezier curve for
  // the corner, and C is the actual corner point.
  //
  // At the start of the loop, the current point is assumed to be
  // the point adjacent to the top left corner on the top
  // horizontal.  Note that corner indices start at the top left and
  // continue clockwise, whereas in our loop i = 0 refers to the top
  // right corner.
  //
  // When going CCW, the control points are swapped, and the first
  // corner that's drawn is the top left (along with the top segment).
  //
  // There is considerable latitude in how one chooses the four
  // control points for a Bezier curve approximation to an ellipse.
  // For the overall path to be continuous and show no corner at the
  // endpoints of the arc, points 0 and 3 must be at the ends of the
  // straight segments of the rectangle; points 0, 1, and C must be
  // collinear; and points 3, 2, and C must also be collinear.  This
  // leaves only two free parameters: the ratio of the line segments
  // 01 and 0C, and the ratio of the line segments 32 and 3C.  See
  // the following papers for extensive discussion of how to choose
  // these ratios:
  //
  //   Dokken, Tor, et al. "Good approximation of circles by
  //      curvature-continuous Bezier curves."  Computer-Aided
  //      Geometric Design 7(1990) 33--41.
  //   Goldapp, Michael. "Approximation of circular arcs by cubic
  //      polynomials." Computer-Aided Geometric Design 8(1991) 227--238.
  //   Maisonobe, Luc. "Drawing an elliptical arc using polylines,
  //      quadratic, or cubic Bezier curves."
  //      http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
  //
  // We follow the approach in section 2 of Goldapp (least-error,
  // Hermite-type approximation) and make both ratios equal to
  //
  //          2   2 + n - sqrt(2n + 28)
  //  alpha = - * ---------------------
  //          3           n - 4
  //
  // where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ).
  //
  // This is the result of Goldapp's equation (10b) when the angle
  // swept out by the arc is pi/2, and the parameter "a-bar" is the
  // expression given immediately below equation (21).
  //
  // Using this value, the maximum radial error for a circle, as a
  // fraction of the radius, is on the order of 0.2 x 10^-3.
  // Neither Dokken nor Goldapp discusses error for a general
  // ellipse; Maisonobe does, but his choice of control points
  // follows different constraints, and Goldapp's expression for
  // 'alpha' gives much smaller radial error, even for very flat
  // ellipses, than Maisonobe's equivalent.
  //
  // For the various corners and for each axis, the sign of this
  // constant changes, or it might be 0 -- it's multiplied by the
  // appropriate multiplier from the list before using.

  const Float alpha = Float(0.55191497064665766025);

  typedef struct { Float a, b; } twoFloats;

  twoFloats cwCornerMults[4] = { { -1,  0 },    // cc == clockwise
                                 {  0, -1 },
                                 { +1,  0 },
                                 {  0, +1 } };
  twoFloats ccwCornerMults[4] = { { +1,  0 },   // ccw == counter-clockwise
                                  {  0, -1 },
                                  { -1,  0 },
                                  {  0, +1 } };

  twoFloats *cornerMults = aDrawClockwise ? cwCornerMults : ccwCornerMults;

  Point cornerCoords[] = { aRect.TopLeft(), aRect.TopRight(),
                           aRect.BottomRight(), aRect.BottomLeft() };

  Point pc, p0, p1, p2, p3;

  if (aDrawClockwise) {
    aPathBuilder->MoveTo(Point(aRect.X() + aRadii[RectCorner::TopLeft].width,
                               aRect.Y()));
  } else {
    aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aRadii[RectCorner::TopRight].width,
                               aRect.Y()));
  }

  for (int i = 0; i < 4; ++i) {
    // the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
    int c = aDrawClockwise ? ((i+1) % 4) : ((4-i) % 4);

    // i+2 and i+3 respectively.  These are used to index into the corner
    // multiplier table, and were deduced by calculating out the long form
    // of each corner and finding a pattern in the signs and values.
    int i2 = (i+2) % 4;
    int i3 = (i+3) % 4;

    pc = cornerCoords[c];

    if (aRadii[c].width > 0.0 && aRadii[c].height > 0.0) {
      p0.x = pc.x + cornerMults[i].a * aRadii[c].width;
      p0.y = pc.y + cornerMults[i].b * aRadii[c].height;

      p3.x = pc.x + cornerMults[i3].a * aRadii[c].width;
      p3.y = pc.y + cornerMults[i3].b * aRadii[c].height;

      p1.x = p0.x + alpha * cornerMults[i2].a * aRadii[c].width;
      p1.y = p0.y + alpha * cornerMults[i2].b * aRadii[c].height;

      p2.x = p3.x - alpha * cornerMults[i3].a * aRadii[c].width;
      p2.y = p3.y - alpha * cornerMults[i3].b * aRadii[c].height;

      aPathBuilder->LineTo(p0);
      aPathBuilder->BezierTo(p1, p2, p3);
    } else {
      aPathBuilder->LineTo(pc);
    }
  }

  aPathBuilder->Close();
}